哪个跑得最快?
- 使用主键从表中选择(整数、聚集索引、1,000,000+ 行)
- 尝试在不存在该行的不同表上进行更新?(整数主键、聚集索引、200,000+ 行的 where 子句)
背景
我们目前有一些程序需要维护其表的过滤副本。
涉及的表:
[MasterTable]
包含过滤条件的[ChildTable]
被过滤[ChildFilterTable]
保存过滤后的记录
目前正在通过以下方式完成:
- 选择过滤条件
- 如果过滤条件匹配,则:
- 尝试更新
- 如果没有更新记录,则插入一条新记录
示例 SQL:
DECLARE @FilterValue INT
/* Get FilterValue to check */
SELECT @FilterValue = FilterValue FROM [MasterTable] WHERE ID = @IDFromChildTable
IF @FilterValue = 123
BEGIN
/* Attempt update */
UPDATE [ChildFilterTable] SET
...
WHERE ChildID = @IDFromChildTable
IF @@ROWCOUNT = 0
BEGIN
/* Row not there yet, insert it! */
INSERT INTO [ChildFilterTable] (ChildID, ....) VALUES (@IDFromChildTable, ....)
END
END
拟议变更
改成:
- 尝试更新
- 如果没有更新记录,则:
- 选择过滤条件
- 如果过滤条件匹配则:插入一条新记录
所以:
DECLARE @FilterValue INT
/* Attempt update */
UPDATE [ChildFilterTable] SET
...
WHERE ChildID = @IDFromChildTable
IF @@ROWCOUNT = 0
BEGIN
/* Get FilterValue to check */
SELECT @FilterValue = FilterValue FROM [MasterTable] WHERE ID = @IDFromChildTable
IF @FilterValue = 123
BEGIN
/* Row not there yet, insert it! */
INSERT INTO [ChildFilterTable] (ChildID, ....) VALUES (@IDFromChildTable, ....)
END
END
注意:业务规则确认过滤器值一旦设置就永远不会改变,[MasterTable]
因此我们无需担心更新与过滤器记录不匹配的值(即:如果它在 ChildFilterTable 中,我们要更新它。
不能在一个原子操作中使用 SQL Server 2008 添加的MERGE语句来“UPSERT”吗?
你检查过你的插入/更新有多贵吗?
如果您关心性能,我总是会先调用 INSERT 或 UPDATE,具体取决于您的场景中更可能需要什么。因此,如果您希望您的数据在 80% 的情况下已经存在,请先调用 UPDATE,然后在 INSERT 失败时调用。如果在大多数情况下通常必须插入记录,请先调用 INSERT。
您可以尝试在两个查询开始时设置统计时间,并查看结果。请记住,如果查询被缓存,您将看到不同的结果,因此您可能必须在测试时清除缓存以查看它们是如何工作的。