我创建了一个非规范化表,需要每小时插入/更新一次。从数据的角度来看,这个过程非常复杂,所以我正在寻找一种推荐的方法来更新表而不会中断用户。
我正在考虑让我的流程插入/更新一个单独的表,一旦完成,需要一种方法将这些更改推送到我的实时生产表。
任何帮助都会很棒!
答案 0 :(得分:4)
另一种解决方案是使用多个模式并播放switch-a-roo。我只喜欢这种方法,因为我曾经在工作中做过这个技巧,而关于重命名对象(无法抑制)的警告信息填满了我的历史记录。基本上你需要两个额外的模式(一个临时保存表的副本,一个保存缓存的副本)。
CREATE SCHEMA cache AUTHORIZATION dbo;
CREATE SCHEMA hold AUTHORIZATION dbo;
现在,在缓存模式中创建表的模仿:
SELECT * INTO cache.table FROM dbo.table WHERE 1 = 0;
-- then create any indexes etc.
现在是时候刷新数据了:
-- step 1:
TRUNCATE TABLE cache.table;
-- (if you need to maintain FKs you may need to delete)
INSERT INTO cache.table SELECT ...
-- step 2:
-- this transaction will be almost instantaneous,
-- since it is a metadata operation only:
BEGIN TRANSACTION;
ALTER SCHEMA hold TRANSFER dbo.table;
ALTER SCHEMA dbo TRANSFER cache.table;
ALTER SCHEMA cache TRANSFER hold.table;
COMMIT TRANSACTION;
理论上,您可以将最后一次转移移出交易,因为用户可以在第二次转移后开始查询dbo.table的新副本,但就像我说的那样,这几乎是瞬间的如果你发现并发性有任何不同,我会感到惊讶。
您也可以选择在此处再次截断cache.table
,但我始终将其填充,以便我可以比较数据更改或在出现问题时进行故障排除。根据步骤1所用的时间长短,反向执行传输可能比从头重新填充更快。
与重命名一样,你可以从这个过程中得到不可思议的东西,比如统计数据随着实际表格移动而丢失,他们不会坚持使用名称。就像重命名一样,你会想要测试它,你可能想要玩隔离级别,例如RCSI用于访问报告表。
答案 1 :(得分:2)
一种解决方案是使用您提到的临时表来执行此操作,然后将其名称更改为生产表名称(但首先,将生产表重命名为其他名称)。之后,您可以放弃以前的生产表。当然,你应该在交易中完成所有这些工作。
所以,它将是:
-- Fill tmpTable
--
-- Do renaming
begin tran t1;
execute sp_rename 'productionTable', 'productionTableBackup';
execute sp_rename 'tmpTable', 'productionTable';
commit tran t1;