【问题标题】:Checking foreign key constraint "online"“在线”检查外键约束
【发布时间】:2013-10-23 18:37:44
【问题描述】:

如果我们有一个巨大的事实表并想添加一个新维度,我们可以这样做:

BEGIN TRANSACTION

ALTER TABLE [GiantFactTable]
ADD NewDimValueId INT NOT NULL
CONSTRAINT [temp_DF_NewDimValueId] DEFAULT (-1)
WITH VALUES -- table is not actually rebuilt!

ALTER TABLE [GiantFactTable]
WITH NOCHECK
ADD CONSTRAINT [FK_GiantFactTable_NewDimValue]
FOREIGN KEY ([NewDimValueId])
REFERENCES [NewDimValue] ([Id])

-- drop the default constraint, new INSERTs will specify a value for NewDimValueId column
ALTER TABLE [GiantFactTable]
DROP CONSTRAINT [temp_DF_NewDimValueId]

COMMIT TRANSACTION

注意:以上所有操作都只处理表元数据,无论表大小如何,都应该很快。 然后我们可以运行一个作业在小事务中回填GiantFactTable.NewDimValueId,这样就不会违反 FK。 (此时任何插入/更新 - 例如回填操作 - 都由 FK 验证,因为它已启用,但不是“受信任的”)

回填后我们知道数据是一致的,我的问题是SQL引擎怎么也能开悟呢? 无需让表脱机。

此命令将使 FK 受信任,但它需要架构修改 (Sch-M) 锁定,并且可能需要数小时(数天?)才能使表脱机:

ALTER TABLE [GiantFactTable]
WITH CHECK CHECK CONSTRAINT [FK_GiantFactTable_NewDimValue]

关于工作负载:表有几百个分区(固定数量),数据一次附加到一个分区(以循环方式),从不删除。还有一个恒定的读取工作负载,它使用集群键一次从一个分区获取(相对较小)范围内的行。 一次检查一个分区并使其脱机是可以接受的。但我找不到任何语法来做到这一点。还有其他想法吗?

【问题讨论】:

标签: sql sql-server foreign-keys sql-server-2012 check-constraints


【解决方案1】:

想到了一些想法,但它们并不漂亮:

重定向工作负载并离线运行检查约束

  1. 创建一个具有相同结构的新表。
  2. 更改“插入”工作负载以插入到新表中
  3. 将数据从“读取”工作负载使用的分区复制到新表(或具有相同结构的第三个表)
  4. 更改“读取”工作负载以使用新表
  5. 运行alter table 来检查约束并让它根据需要等待
  6. 将这两个工作负载改回主表。
  7. 将新行重新插入主表中
  8. 删除新表

上面的一个变体是在步骤 3 中将相关分区切换到新表。这应该比复制数据更快,但我认为您必须在约束之后复制(而不仅仅是切换)数据已检查。

将所有数据插入新表

  1. 创建具有相同结构和启用约束的新表
  2. 将“插入”工作负载更改为新表
  3. 将旧表中的所有数据分批复制到新表中,等待完成即可
  4. 将“读取”工作负载更改为新表。如果第 3 步耗时过长,并且“读取”工作负载需要仅插入到新表中的行,则您必须手动管理此转换。
  5. 放下旧表

使用索引加速约束检查?

我不知道这是否可行,但您可以尝试在外键列上创建非聚集索引。还要确保在外键引用的表上的相关唯一键上有一个索引。 alter table 命令可能能够使用它们来加快检查速度(至少与执行全表扫描相比,通过最小化 IO)。当然,可以在线创建索引以避免任何中断。

【讨论】:

  • 第二个想法当然可行,在这种情况下,所有读者都使用该表的视图当然也有帮助(它将事实表及其维度连接起来,并有助于消除分区)。如果视图更新为SELECT * FROM GiantFactTable_old UNION ALL SELECT * FROM GiantFactTable 之类的内容,那么读者就不会更聪明了。
  • 同样重要的是,第二个建议不需要额外的临时存储来实现。 (毕竟这是giant 表!)
猜你喜欢
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 2015-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多