Correctly managing your MySQL database objects such as schemas, tables, indexes, base data etc, is critical to the success of a 24×7 online website. I rarely encounter a robust working solution as part of my consulting so I would like to share my experience in identifying the best practices you should be adopting whether your an existing organization or just an individual with a simple website.
Much of the following concept actually pre dates my involvement in MySQL (since 1999), so this is not just applicable for a MySQL RDBMS. For the purposes of this discussion I’d like to focus on the theory successfully used with clients.
Under version control I have the following directory structure:
NOTE If your first observation was “Arrh, Version Control?”, you are in more trouble then you want to be right from day one. You need Version Control such as svn, cvs, bzr, git etc for any website no matter how small.
/database /scripts /sql /schema /patch /revert /admin /data ....
The /database is a top level directory, and for software packaging for all database related operations, you simply include all contents from /database.
At it’s core, every database object change for configuration management will be addressed in three (3) files.
- A schema file
- A patch file
- A revert file
In fact, you can add version control rules for example to ensure if you add a patch file, a corresponding revert and schema file is also specified.
For a “current” working environment, there are two paths for database object management.
- An upgrade path
- A new version creation.
An upgrade path which is the normal production operation, takes an existing database schema and ‘patches’ this to a new revision. As the name suggests, for each ‘patch’ file a corresponding ‘revert’ file can be used to revert the upgrade. For testing and development environments, a current version of the full schema can always be created without using the upgrade path simply by creating the schema with the current schema file.
For the purposes of understanding how this would work in a real environment, I’ll use the Sakila test database and I’ll step through a few examples.
Seeding your configuration management
Because we already have an existing schema, the first step is to seed our new configuration management with the existing schema information.
This would actually involve some duplication, however this will become more apparent in future examples.
We will be creating the following three (3) files:
- /database/sql/schema/schema.sakila.sql
- /database/sql/patch/patch.20090303.01.sql
- /database/sql/revert/revert.20090303.01.sql
/database/sql/schema/schema.sakila.sql
This will be a copy of the sakila-db/sakila-schema.sql. You will need to edit this file to remove the following lines.
DROP SCHEMA IF EXISTS sakila; CREATE SCHEMA sakila; USE sakila;
All configuration files must not contain any schema definitions. This will be discussed in more detail at a later time.
/database/sql/schema/patch.20090303.01.sql
This will be a copy of the above file.
/database/sql/schema/revert.20090303.01.sql
DROP PROCEDURE IF EXISTS rewards_report ; DROP FUNCTION IF EXISTS get_customer_balance; DROP PROCEDURE IF EXISTS film_in_stock; DROP PROCEDURE IF EXISTS film_not_in_stock; DROP FUNCTION IF EXISTS inventory_held_by_customer; DROP FUNCTION IF EXISTS inventory_in_stock; DROP VIEW IF EXISTS customer_list; DROP VIEW IF EXISTS film_list; DROP VIEW IF EXISTS nicer_but_slower_film_list; DROP VIEW IF EXISTS staff_list; DROP VIEW IF EXISTS sales_by_store; DROP VIEW IF EXISTS sales_by_film_category; DROP VIEW IF EXISTS actor_info; DROP TABLE IF EXISTS actor; DROP TABLE IF EXISTS address; DROP TABLE IF EXISTS category; DROP TABLE IF EXISTS city; DROP TABLE IF EXISTS country; DROP TABLE IF EXISTS customer; DROP TABLE IF EXISTS film; DROP TABLE IF EXISTS film_actor; DROP TABLE IF EXISTS film_category; DROP TABLE IF EXISTS film_text; DROP TABLE IF EXISTS inventory; DROP TABLE IF EXISTS language; DROP TABLE IF EXISTS payment; DROP TABLE IF EXISTS rental; DROP TABLE IF EXISTS staff; DROP TABLE IF EXISTS store;
For the purposes of this theory, I will discuss schema creation and management at a later time. For this example, we assume the ‘sakila’ schema has been created and is empty.
The ‘two’ paths
The default path is to apply the patch file to the appropriate schema. In this case, by using the patch file, this would create the current ‘sakila’ schema.
If this fails for example, you should automatically apply the revert script which should restore your environment to it’s original state, in this case an empty schema.
If you wanted to create a new test environment for example, (following creation of the schema), you could simply apply the schema file.
Let’s perform another iteration, to see the full working process.
Adding new objects
Let’s say we wanted to keep additional information such as famous quotes an actor has made. We want to create a new table ‘actor_quote’.
For this we would first create a patch and revert script to manage this new object.
/database/sql/patch/patch.20090303.02.sql
CREATE TABLE actor_quote ( quote_id INT UNSIGNED NOT NULL AUTO_INCREMENT, actor_id SMALLINT UNSIGNED NOT NULL, quote VARCHAR(200) NOT NULL, PRIMARY KEY (quote_id), KEY idx_fk_actor_id (actor_id), CONSTRAINT fk_actor_quote_actor FOREIGN KEY (actor_id) REFERENCES actor (actor_id) ON DELETE RESTRICT ON UPDATE CASCADE )ENGINE=InnoDB DEFAULT CHARSET=utf8;
/database/sql/revert/revert.20090303.02.sql
DROP TABLE IF EXISTS actor_quote;
/database/sql/schema/schema.sakila.sql
The contents of the patch file should be appended to this file.
The ‘two’ paths
If we look at the two paths again.
The normal production operation, by using the patch file, would create the new database object.
If this fails for example, you should automatically apply the revert script which should restore your environment to it’s original state, in this case drop the table if it exists. In this simplest example,
If you wanted to create a new test environment for example, (following creation of the schema), you could simply apply the schema file.
Review
We have only touched on the entire process of configuration management for database objects. The implementation of this practice includes meta data and controlling scripts that manage the order of execution, recording operations performed successfully or unsuccessfully for example.
About Standards
Within this overview a number of standards are in place. These include:
- SQL scripts do not contain any CREATE/DROP DATABASE|SCHEMA commands
- SQL scripts do not contain any schema/database specific references. This is important for being able to easily test and verify operations. In our above examples, the default Sakila DB contains such information and would be edited appropriately.
- For Patch and Revert files a chronological date format for naming is used, e.g. YYYYMMDD.XX, where XX is a sequential number for multiple patch/revert scripts for any given day.
- All SQL statements must be terminated with ‘;’. This is important for the management processes and automated scripts that take these fundamental schema/patch/revert scripts as source information.
- Where possible, try to make revert scripts, support either a successful or failed patch process. For example, adding IF EXISTS to a DROP TABLE statements supports both cases.
- It is reasonably obvious to have schema, patch and revert directories as a naming standard, but file name also include this as a prefix. This is performed as a double check, if a file is seen in isolation it’s type can be determined regardless of directory location. Also for logging, only filenames are used.
More Information
Configuration Management in MySQL is one of the topics discussed in the “MySQL Essentials” training course. You can find more information regarding this and other training offerings including an upcoming schedule at 42SQL Education.
Frank Mashraqi says
Good post, Ronald. It is surprising to see how many projects completely ignore configuration management for databases.
Frank
Gregory Haase says
I agree – it’s not that complicated to do a proper setup, and having proper change management can really save you a lot of heartache in the long run. That is why I’m really looking forward to covering a lot of these topics in my “Build and Release Management for Database Engineers” tutorial at the MySQL Conference next month. I’d ask all your readers to come by, but it’s unfortunately being held at the same time as your “Practical MySQL Plugin Development” talk.