Skip to content

Identify database issues before they hit production.

License

Notifications You must be signed in to change notification settings

postingres/active_record_doctor

 
 

Repository files navigation

Active Record Doctor

Active Record Doctor helps to keep the database in a good shape. Currently, it can:

  • index unindexed foreign keys
  • detect extraneous indexes
  • detect missing foreign key constraints
  • detect models referencing undefined tables

More features coming soon!

Want to suggest a feature? Just shoot me an email.

Build Status

Installation

The preferred installation method is adding active_record_doctor to your Gemfile:

gem 'active_record_doctor', group: :development

Then run:

bundle install

Usage

Indexing Unindexed Foreign Keys

Foreign keys should be indexed unless it's proven ineffective. However, Rails makes it easy to create an unindexed foreign key. Active Record Doctor can automatically generate database migrations that add the missing indexes. It's a three-step process:

  1. Generate a list of unindexed foreign keys by running
rake active_record_doctor:unindexed_foreign_keys > unindexed_foreign_keys.txt
  1. Remove columns that should not be indexed from unindexed_foreign_keys.txt as a column can look like a foreign key (i.e. end with _id) without being one.

  2. Generate the migrations

rails generate active_record_doctor:add_indexes unindexed_foreign_keys.txt
  1. Run the migrations
rake db:migrate

Removing Extraneous Indexes

Let me illustrate with an example. Consider a users table with columns first_name and last_name. If there are two indexes:

  • A two-column index on last_name, first_name.
  • A single-column index on last_name.

Then the latter index can be dropped as the former can play its role. In general, a multi-column index on column_1, column_2, ..., column_n can replace indexes on:

  • column_1
  • column_1, column_2
  • ...
  • column_1, column_2, ..., column_(n - 1)

To discover such indexes automatically just follow these steps:

  1. List extraneous indexes by running:
rake active_record_doctor:extraneous_indexes
  1. Confirm that each of the indexes can be indeed dropped.

  2. Create a migration to drop the indexes.

The indexes aren't dropped automatically because there's usually just a few of them and it's a good idea to double-check that you won't drop something necessary.

Also, extra indexes on primary keys are considered extraneous too and will be reported.

Note that a unique index can never be replaced by a non-unique one. For example, if there's a unique index on users.login and a non-unique index on users.login, users.domain then the tool will not suggest dropping users.login as it could violate the uniqueness assumption.

Detecting Missing Foreign Key Constraints

If users.profile_id references a row in profiles then this can be expressed at the database level with a foreign key constraint. It forces users.profile_id to point to an existing row in profiles. The problem is that in many legacy Rails apps the constraint isn't enforced at the database level.

active_record_doctor can automatically detect foreign keys that could benefit from a foreign key constraint (a future version will generate a migrations that add the constraint; for now, it's your job). You can obtain the list of foreign keys with the following command:

rake active_record_doctor:missing_foreign_keys

The output will look like:

users profile_id
comments user_id article_id

Tables are listed one per line. Each line starts with a table name followed by column names that should have a foreign key constraint. In the example above, users.profile_id, comments.user_id, and comments.article_id lack a foreign key constraint.

In order to add a foreign key constraint to users.profile_id use the following migration:

class AddForeignKeyConstraintToUsersProfileId < ActiveRecord::Migration
  def change
    add_foreign_key :users, :profiles
  end
end

Detecting Models Referencing Undefined Tables

Active Record guesses the table name based on the class name. There are a few cases where the name can be wrong (e.g. you forgot to commit a migration or changed the table name). Active Record Doctor can help you identify these cases before they hit production.

The only think you need to do is run:

rake active_record_doctor:undefined_table_references

If there a model references an undefined table then you'll see a message like this:

The following models reference undefined tables:
  Contract (the table contract_records is undefined)

On top of that rake will exit with status code of 1. This allows you to use this check as part of your Continuous Integration pipeline.

Author

This gem is developed and maintained by Greg Navis.

About

Identify database issues before they hit production.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Ruby 86.2%
  • HTML 10.6%
  • CSS 1.5%
  • JavaScript 1.3%
  • Logos 0.4%