Referential Integrity – a fundamental that enables smarter and more cost effective database applications

More often than not, I find the database layer is typically a realm in applications that isn’t emphasized very much. There are certainly developers out there comfortable working with databases, but with the rise of database abstraction layers, query builders, and ORMs, it’s not uncommon to find that database fundamentals are abstracted away, deferred as a lower priority, or pushed aside permanently.  One such fundamental that I find commonly ignored all together is referential integrity.

Referential integrity can be considered a practice, implemented through foreign key constraints, that enforces valid data relations in a relational database.  Most databases include support for it in some way or another (MySQL’s MyISAM storage engine doesn’t support RI), so the practice and benefits are shared among most relational databases.

Before I show a simple example of how to enforce RI, I’ll provide a few reasons why it’s in your best interest to enforce RI in your applications:

  • Faster and more cost efficient development.  RI enables you to catch more database related bugs sooner, which not only translates into faster debugging, but also provides the benefit of not having any post bug-fix data refactoring due to accumulated fallout from bugs that may otherwise go unnoticed.
  • Higher quality apps – more bugs are caught and fixed sooner, which translates into fewer bugs that reach your users.
  • Smarter databases – I’ve always rejected the notion that databases are just a storage mechanic for your application.  Databases should be crafted smartly, in a way such that it can look after itself; RI enables that through it’s validation-like behavior.  You provide validation for input into your application, why not provide validation for data going into your database?
  • Better performance (in some cases).  Some databases, SQL Server specifically, have optimizers that use foreign keys to improve read performance when executing queries that touch foreign keyed tables.

So, with those being established, here’s a brief example showing how to enforce RI; a simple user and user type model will be used.  These code snippets were executed against a MySQL (5.x) database, if you’re interested in following along.

First, create a user_types tables:

CREATE TABLE user_types
(
  user_type_id tinyInt UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(20) NOT NULL,
  constraint PK_user_types PRIMARY KEY (user_type_id)
) engine = InnoDB;

… then populate it with data:

INSERT INTO user_types (name)
SELECT ‘Admin’ UNION ALL
SELECT ‘Agent’ UNION ALL
SELECT ‘Client’;

Next, create a users table:

CREATE TABLE users
(
  user_id int UNSIGNED NOT NULL AUTO_INCREMENT,
  user_type_id tinyInt UNSIGNED NOT NULL,
  firstname varchar(25) NOT NULL,
  lastname varchar(25) NOT NULL,
  constraint PK_users PRIMARY KEY (user_id),
  constraint FK_users_user_type_id FOREIGN KEY (user_type_id) REFERENCES user_types(user_type_id)
) engine = InnoDB;

Before I continue, here’s a quick note on a couple of things from above:

  1. engine = InnoDB – this is key when implementing referential integrity in MySQL, as the (default) MyISAM storage engine does not support RI.
  2. constraint FK_users_user_type_id foreign key (user_type_id) references user_types(user_type_id) – this is how we programmatically create our foreign key relationship between users.user_type_id and user_types.user_type_id.  The naming convention “FK_users_user_type_id” is optional, I use it to establish that it’s a foreign key constraint on the users.user_type_id column, and that it should reference the user_types.user_type_id column.

With those tables and dummy data established, we can now run a couple of test cases. Insert this row first:

insert into users (user_type_id, firstname, lastname) values (1, ‘John’, ‘Smith’);

Now try to insert this row:

insert into users (user_type_id, firstname, lastname) values (0, ‘Jenny’, ‘Craig’);

You should get an error that states something along the lines of “Cannot add or update a child row: a foreign key constraint fails…”.  What’s happened is that the database didn’t execute the insert because of invalid data. The problem is that the 2nd insert tried to insert a user_type_id value of 0 in our previous insert statement, but since 0 isn’t a value found in user_types.user_type_id, the database threw an error.  In this case the error was intentional, but such errors can easily happen in real world applications and not become obvious until weeks or months worth of data damage have already happened in your application.

Posted in Database | Leave a comment

Enabling compression for faster web pages

If you’re familiar with Steve Souders, or use tools like YSlow or PageSpeed to optimize your sites, you probably already know that enabling compression for your web sites is a proven way to speed up response times. Even though that’s well known by now, I remember having a hard time finding a resource that illustrated how to do this back when I first started doing this for my sites. It’s a very simple procedure, here’s what’s involved.

First, make sure you have the deflate_module installed.  To do that:

  1. find your Apache’s config file (for CentOS – /etc/httpd/conf/httpd.conf)
  2. open it and make sure you have the deflate_module installed.  Search for lines beginning with LoadModule – if you see a line starting with LoadModule deflate_module, it’s installed and ready to use.  Otherwise, you’ll need to add a line for the deflate_module.

Next, you’ll need to add AddOutputFilterByType directives to the Apache config file.   These basically inform Apache which content types you want the deflate_module to act on.  Here are the ones I’ve added:

AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript

Keep in mind there are 2 ways of adding these directives. You can add those anywhere in your Apache config file to enable compression globally (I appended mine to the end of my conf file). However, you may only have specific apps or sites that you want to target vs. enabling compression globally; in such cases you can add those directives inside their respective virtual host blocks.

You can see the impact this change made, even to simple pages like my blog.  The entire page is now 30% smaller and 131 ms have been shaved from the total download time.

Before

After

Posted in Performance | Leave a comment

WordPress: call to undefined function get_option()

So I finally got around to installing WordPress; all seemed fine until I deployed to my live server and tried to log into the Admin panel.  After doing so, I hit the following error:

Fatal error: Call to undefined function get_option() in …/wp-admin/admin.php on line xyz.

After doing some research, it seems like a lot of folks have hit this problem.  Googling the error surfaced 2 common fixes:

  • deleting trailing spaces from the wp-config.php and functions.php files
  • re-uploading the entire Word Press installation (seems as if Word Press files have a way of becoming corrupt during their upload, which sounds odd)

Neither of those worked for me, but after suspecting the issue had something to do with php 5.3 and calls to include_once, my Google-fu uncovered this post:

http://wordpress.org/support/topic/wp-301-apc-314-php-533-white-wp-adnmin-page

So, it turns out that my issue was due to having php 5.3 and a specific version of APC installed.  After setting this APC directive in my apc.ini:

apc.include_once_override = 0

… all is well again! Hopefully this saves someone the hours of research, debugging, and frustration that I went through!

Posted in General | 9 Comments