mysqlrelease-managementmysql-error-1050

How do you version and sync your MySQL data model?


What's the best way to save my MySQL data model and automatically apply changes to my development database server as they are made (or at least nightly)?

For example, today I'm working on my project and create this table in my database, and save the statement to SQL file to deploy to production later:

create table dog (
  uid int,
  name varchar(50)
);

And tomorrow, I decide I want to record the breed of each dog too. So I change the SQL file to read:

create table dog (
  uid int,
  name varchar(50),
  breed varchar(30)
);

That script will work in production for the first release, but it won't help me update my development database because ERROR 1050 (42S01): Table 'dog' already exists. Furthermore, it won't work in production if this change was made after the first release. So I really need to ALTER the table now.

So now I have two concerns:

  1. Is this how I should be saving my data model (a bunch of create statements in a SQL file), and
  2. How should I be applying changes like this to my database?

My goal is to release changes accurately and enable continuous integration. I use a tool called DDLSYNC do find and apply difference in an Oracle database, but I'm not sure what similar tools exist for MySQL.


Solution

  • At work, we developed a small script to manage our database versioning. Every change to any table or set of data gets it's own SQL file.

    The files are numbered sequentially. We keep track of which update files have been run by storing that information in the database. The script inserts a row with the filename when the file is about to be executed, and updates the row with a completion timestamp when the execution finishes. This is wrapped inside a transaction. (It's worth remembering that DDL commands in MySQL can not occur within a transaction. Any attempt to perform DDL in a transaction causes an implicit commit.)

    Because the SQL files are part of our source code repository, we can make running the update script part of the normal rollout process. This makes keeping the database and the code in sync easy as pie. Honestly, the hardest part is making sure another dev hasn't grabbed the next number in a pending commit.

    We combine this update system with an (optional) nightly wipe of our dev database, replacing the contents with last night's live system backup. After the backup is restored, the update gets run, with any pending update files getting run in the process.

    The restoration occurs in such a way that only tables that were in the live database get overwritten. Any update that adds a table therefore also has to be responsible for only adding it if it doesn't exist. DROP TABLE IF EXISTS is handy. Unfortunately not all databases support that, so the update system also allows for execution of scripts written in our language of choice, not just SQL.

    All of this in about 150 lines of code. It's as easy as reading a directory, comparing the contents to a table, and executing anything that hasn't already been executed, in a determined order.