2

我创建了一个需要每小时插入/更新的非规范化表。从数据的角度来看,这个过程相当复杂,所以我正在寻找一种推荐的方法来更新表而不干扰用户。

我正在考虑有一个单独的表,我的流程插入/更新到并且一旦完成,需要一种方法将这些更改推送到我的实时生产表。

任何帮助都会很棒!

4

2 回答 2

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。

于 2012-02-08T02:29:58.313 回答
2

一种解决方案是使用您提到的临时表,然后将其名称更改为生产表名称(但首先,将生产表重命名为其他名称)。之后,您可以删除以前的生产表。当然,您应该在事务中完成所有这些操作。

所以,它会是:

-- Fill tmpTable
--

-- Do renaming
begin tran t1;
execute sp_rename 'productionTable', 'productionTableBackup';
execute sp_rename 'tmpTable', 'productionTable';
commit tran t1;
于 2012-02-08T01:41:38.050 回答