views:

907

answers:

10

I've arrived at the point where I realise that I must start versioning my database schemata and changes. I consequently read the existing posts on SO about that topic but I'm not sure how to proceed.

I'm basically a one man company and not long ago I didn't even use version control for my code. I'm on a windows environment, using Aptana (IDE) and SVN (with Tortoise). I work on PHP/mysql projects.

What's a efficient and sufficient (no overkill) way to version my database schemata?

I do have a freelancer or two in some projects but I don't expect a lot of branching and merging going on. So basically I would like to keep track of concurrent schemata to my code revisions.

[edit] Momentary solution: for the moment I decided I will just make a schema dump plus one with the necessary initial data whenever I'm going to commit a tag (stable version). That seems to be just enough for me at the current stage.[/edit]

[edit2]plus I'm now also using a third file called increments.sql where I put all the changes with dates, etc. to make it easy to trace the change history in one file. from time to time I integrate the changes into the two other files and empty the increments.sql[/edit]

+5  A: 

Simple way for a small company: dump your database to SQL and add it to your repository. Then every time you change something, add the changes in the dump file.

You can then use diff to see changes between versions, not to mention have comments explaining your changes. This will also make you virtually immune to MySQL upgrades.

The one downside I've seen to this is that you have to remember to manually add the SQL to your dumpfile. You can train yourself to always remember, but be careful if you work with others. Missing an update could be a pain later on.

This could be mitigated by creating some elaborate script to do it for you when submitting to subversion but it's a bit much for a one man show.

Edit: In the year that's gone by since this answer, I've had to implement a versioning scheme for MySQL for a small team. Manually adding each change was seen as a cumbersome solution, much like it was mentioned in the comments, so we went with dumping the database and adding that file to version control.

What we found was that test data was ending up in the dump and was making it quite difficult to figure out what had changed. This could be solved by dumping the schema only, but this was impossible for our projects since our applications depended on certain data in the database to function. Eventually we returned to manually adding changes to the database dump.

Not only was this the simplest solution, but it also solved certain issues that some versions of MySQL have with exporting/importing. Normally we would have to dump the development database, remove any test data, log entries, etc, remove/change certain names where applicable and only then be able to create the production database. By manually adding changes we could control exactly what would end up in production, a little at a time, so that in the end everything was ready and moving to the production environment was as painless as possible.

Manos Dilaverakis
This way you can easily get an old version up and running quickly.
antennen
why not just dump every time after a change? maybe a batch file that dumps the schema and auto-commits (just this file)? the manual step makes it just harder, imho
Schnalle
@Schnalle - good point. The way I see it, it's up to personal preference. Personally I'm willing to do the manual part just so I can simply right-click on the dump file and use options like "show differences" and "blame" with Tortoise.
Manos Dilaverakis
I've done exactly that with a small team of developers and it worked quite well. We used phpmyadmin for the export and a small custom script to import/replace everything once a new dump was available. Just remember to tell everyone that a new version is in the repo so other's changes won't conflict.
Mike B
aren't svn hooks supposed to solve such problems?
tharkun
+2  A: 

How about versioning file generated by doing this:

mysqldump --no-data database > database.sql
vartec
+2  A: 

Where I work we have an install script for each new version of the app which has the sql we need to run for the upgrade. This works well enough for 6 devs with some branching for maintenance releases. We're considering moving to Auto Patch http://autopatch.sourceforge.net/ which handles working out what patches to apply to any database you are upgrading. It looks like there may be some small complication handling branching with auto Patch, but it doesn't sound like that'll be an issue for you.

Robin
+2  A: 

i'd guess, a batch file like this should do the job (didn't try tough) ...

mysqldump --no-data -ufoo -pbar dbname > path/to/app/schema.sql
svn commit path/to/app/schema.sql

just run the batch file after changing the schema, or let a cron/scheduler do it (but i don't know ... i think, commits work if just the timestamps changed, even if the contents is the same. don't know if that would be a problem.)

Schnalle
sounds good to me, couldn't this batch file be a svn hook script, have never used hooks so far...
tharkun
me neither. i just googled for svn hooks, and there's a "start-commit" hook ("run before commit transaction begins"). it looks like hooks are per-repository, and just call an executable file with parameters (go bat!). here's the doc: http://svnbook.red-bean.com/en/1.0/svn-book.html#svn-ch-5-sect-2.
Schnalle
+2  A: 

The main ideea is to have a folder with this structure in your project base path

/__DB
—-/changesets
——–/1123
—-/data
—-/tables

Now who the whole thing works is that you have 3 folders: Tables Holds the table create query. I recommend using the naming “table_name.sql”.

Data Holds the table insert data query. I recommend using the same naming “table_name.sql”. Note: Not all tables need a data file, you would only add the ones that need this initial data on project install.

Changesets This is the main folder you will work with. This holds the change sets made to the initial structure. This holds actually folders with changesets. For example i added a folder 1123 wich will contain the modifications made in revision 1123 ( the number is from your code source control ) and may contain one or more sql files.

I like to add them grouped into tables with the naming xx_tablename.sql - the xx is a number that tells the order they need to be runned, since sometimes you need the modification runned in a certain order.

Note: When you modify a table, you also add those modifications to table and data files … since those are the file s that will be used to do a fresh install.

This is the main ideea.

for more details you could check this blog post

solomongaby
I appreciate your well explained solution but I think this would already qualify for overkill in my situation.
tharkun
but it still helps me because it gave me an idea of how to handle initial data!
tharkun
solomongaby
+1  A: 

At our company we did it this way:

We put all tables / db objects in their own file, like tbl_Foo.sql. The files contain several "parts" that are delimited with

-- part: create

where create is just a descriptive identification for a given part, the file looks like:

-- part: create
IF not exists ...
CREATE TABLE tbl_Foo ...
-- part: addtimestamp
IF not exists ...
BEGIN
   ALTER TABLE ...
END

Then we have an xml file that references every single part that we want executed when we update database to new schema. It looks pretty much like this:

<playlist>
   <classes>
     <class name="table" desc="Table creation" />
     <class name="schema" desc="Table optimization" />
   </classes>
   <dbschema>
      <steps db="a_database">
         <step file="tbl_Foo.sql" part="create" class="table" />
         <step file="tbl_Bar.sql" part="create" class="table" />
      </steps>
      <steps db="a_database">
         <step file="tbl_Foo.sql" part="addtimestamp" class="schema" />
      </steps>
   </dbschema>          
</playlist>

The <classes/> part if for GUI, and <dbschema/> with <steps/> is to partition changes. The <step/>:s are executed sequentially. We have some other entities, like sqlclr to do different things like deploy binary files, but that's pretty much it.

Of course we have a component that takes that playlist file and a resource / filesystem object that crossreferences the playlist and takes out wanted parts and then runs them as admin on database.

Since the "parts" in .sql's are written so they can be executed on any version of DB, we can run all parts on every previous/older version of DB and modify it to be current. Of course there are some cases where SQL server parses column names "early" and we have to later modify part's to become exec_sqls, but it doesn't happen often.

Pasi Savolainen
needless to say we do have lots of customers and goddamned consultants install different versions willynilly, no 2 versions per year for us :(
Pasi Savolainen
A: 

I do something similar to Manos except I have a 'master' file (master.sql) that I update with some regularity (once every 2 months). Then, for each change I build a version named .sql file with the changes. This way I can start off with the master.sql and add each version named .sql file until I get up to the current version and I can update clients using the version named .sql files to make things simpler.

Jason
A: 

Take a look at SchemaSync. It will generate the patch and revert scripts (.sql files) needed to migrate and version your database schema over time. It's a command line utility for MySQL that is language and framework independent.

Mitch
+1  A: 

Hi there! Some months ago I searched tool for versioning MySQL schema. I found many useful tools, like Doctrine migration, RoR migration, some tools writen in Java and Python.

But no one of them was satisfied my requirements.

My requirements:

  1. No requirements , exclude PHP and MySQL
  2. No schema configuration files, like schema.yml in Doctrine
  3. Able to read current schema from connection and create new migration script, than represent identical schema in other installations of application.

I started to write my migration tool, and today I have beta version.

Please, try it, if you have an interest in this topic. Please send me future requests and bugreports.

Source code: bitbucket.org/idler/mmp/src Overview in English: bitbucket.org/idler/mmp/wiki/Home Overview in Russian: antonoff.info/development/mysql-migration-with-php-project

Maxim Antonov
+1  A: 

Our solution is MySQL Workbench. We regularly reverse-engineer the existing Database into a Model with the appropriate version number. It is then possible to easily perform Diffs between versions as needed. Plus, we get nice EER Diagrams, etc.

Gary