向表中添加新的空列导致锁定

nwa*_*lke 7 postgresql postgresql-9.3

昨天我们在我们的生产数据库上运行了一个我们认为是安全的模式迁移,但遇到了一个问题。似乎添加新列会导致锁定,我们的应用程序无法再访问该表。以下是迁移前对表的说明:

                                                                    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)
Run Code Online (Sandbox Code Playgroud)

这是我们添加“地标”列后的表格:

                                                                     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)
Run Code Online (Sandbox Code Playgroud)

您在这里看到的是否会导致表锁定添加列“地标”?我们只是想避免将来出现停机时间。

更多信息:该表有 304 行,并且处于我们的应用程序 8 分钟无法使用它的状态。

该应用程序是一个 rails 应用程序,我们使用了一个 rake 任务来执行迁移。这是我们使用的代码:

class AddLandmarkToFacility < ActiveRecord::Migration
  def change
    add_column :facilities, :landmarks, :string
  end
end
Run Code Online (Sandbox Code Playgroud)

我相信这会导致以下ALTER声明:

ALTER TABLE "facilities" ADD "landmarks" character varying;
Run Code Online (Sandbox Code Playgroud)

Dan*_*ité 9

ALTER TABLE需要ACCESS EXCLUSIVE锁。从文档

ALTER TABLE 更改现有表的定义。下面描述了几个子表单。请注意,每个子表单所需的锁定级别可能不同。除非明确指出,否则将持有 ACCESS EXCLUSIVE 锁。当列出多个子命令时,持有的锁将是任何子命令所需的最严格的锁

如果没有默认值或表很小,通常不需要几分钟即可添加一列,而在您的情况下,您对两者都很好。

但是为了获得该锁,其他事务不应在同一个表上持有锁。有几件事情需要考虑:

  • 一个简单SELECT的表需要一个锁来阻止其他人执行ALTER TABLE.
  • 锁定仅在其事务结束时释放,而不是在需要它们的指令结束时释放。
  • 一旦ALTER TABLE ...ADD COLUMN等待锁定,其他想要访问SELECT该表的事务也将被阻塞。

后果是:

  • 如果有读取该表的长时间运行的事务,它们将阻塞ALTER TABLE迁移直到它们完成。

  • 如果迁移本身是更大事务的一部分,这将阻止其他想要访问该表的进程,直到它提交。