Yesterday we ran a schema migration on our production database that we thought would be safe, but ran into an issue. It seems as though adding the new column caused a lock and our application could no longer get access to the table. Here's an explain of the table before the migration:
Table "public.facilities"
Column | Type | Modifiers | Storage | Stats target | Description
-----------------------------------+-----------------------------+---------------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('facilities_id_seq'::regclass) | plain | |
name | character varying(255) | | extended | |
phone | character varying(255) | | extended | |
time_zone | character varying(255) | | extended | |
company_id | integer | | plain | |
created_at | timestamp without time zone | | plain | |
updated_at | timestamp without time zone | | plain | |
phnkey_id_token | character varying(255) | | extended | |
phnkey_api_key | character varying(255) | | extended | |
phnkey_auth_token | character varying(255) | | extended | |
payment_provider_name | character varying(255) | | extended | |
payment_provider_data | hstore | | extended | |
tenant_portal_key | character varying(255) | | extended | |
uuid | uuid | default uuid_generate_v4() | plain | |
deleted | boolean | default false | plain | |
deleted_on | timestamp without time zone | | plain | |
deleted_by_id | integer | | plain | |
accounting_method | character varying(255) | | extended | |
last_exported_on | timestamp without time zone | | plain | |
public_url | character varying(255) | | extended | |
access_hours_same_as_office_hours | boolean | default false | plain | |
logo | character varying(255) | | extended | |
next_lease_number | integer | default 1 | plain | |
email | character varying | | extended | |
fax | character varying | | extended | |
store_number | character varying | | extended | |
custom_portal_url | character varying | | extended | |
brand_name | character varying | | extended | |
Indexes:
"facilities_pkey" PRIMARY KEY, btree (id)
"index_facilities_on_tenant_portal_key" UNIQUE, btree (tenant_portal_key)
"index_facilities_on_uuid" UNIQUE, btree (uuid)
"index_facilities_on_company_id" btree (company_id)
And here's the table after we added the column "landmarks":
Table "public.facilities"
Column | Type | Modifiers | Storage | Stats target | Description
-----------------------------------+-----------------------------+---------------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('facilities_id_seq'::regclass) | plain | |
name | character varying(255) | | extended | |
phone | character varying(255) | | extended | |
time_zone | character varying(255) | | extended | |
company_id | integer | | plain | |
created_at | timestamp without time zone | | plain | |
updated_at | timestamp without time zone | | plain | |
phnkey_id_token | character varying(255) | | extended | |
phnkey_api_key | character varying(255) | | extended | |
phnkey_auth_token | character varying(255) | | extended | |
payment_provider_name | character varying(255) | | extended | |
payment_provider_data | hstore | | extended | |
tenant_portal_key | character varying(255) | | extended | |
uuid | uuid | default uuid_generate_v4() | plain | |
deleted | boolean | default false | plain | |
deleted_on | timestamp without time zone | | plain | |
deleted_by_id | integer | | plain | |
accounting_method | character varying(255) | | extended | |
last_exported_on | timestamp without time zone | | plain | |
public_url | character varying(255) | | extended | |
access_hours_same_as_office_hours | boolean | default false | plain | |
logo | character varying(255) | | extended | |
next_lease_number | integer | default 1 | plain | |
email | character varying | | extended | |
fax | character varying | | extended | |
store_number | character varying | | extended | |
custom_portal_url | character varying | | extended | |
brand_name | character varying | | extended | |
landmarks | character varying | | extended | |
Indexes:
"facilities_pkey" PRIMARY KEY, btree (id)
"index_facilities_on_tenant_portal_key" UNIQUE, btree (tenant_portal_key)
"index_facilities_on_uuid" UNIQUE, btree (uuid)
"index_facilities_on_company_id" btree (company_id)
Is there something you see here that would lead to a table lock on adding the column "landmarks"? We're just trying to avoid the down time in the future.
Further info: The table has 304 rows and was in a state that our application couldn't use it for 8 minutes.
The application is a rails app and we used a rake task to perform the migration. Here's the code we used:
class AddLandmarkToFacility < ActiveRecord::Migration
def change
add_column :facilities, :landmarks, :string
end
end
Which I believe results in this ALTER
statement:
ALTER TABLE "facilities" ADD "landmarks" character varying;