【发布时间】:2015-05-07 21:23:55
【问题描述】:
我是 MERGE 的新手和索引新手,所以请耐心等待...
我有一个存储过程,它构建一个 #changes 临时表,根据 #changes 更新一个 prod_tbl 表,然后将之前和之后的值插入到 auto_update_log 表中,该表随着重复行快速增长。为了防止这种情况,我想使用 MERGE 语句。速度是最重要的,线程安全也是最重要的,因为这个表会被操作一整天。
auto_update_log 上没有任何现有索引,也没有任何类型的键。我的想法是使用键列(来自auto_update_log 表)和所有前后列创建一个多列索引,以帮助加快 MERGE 的速度。将有 6 个前后列加上与auto_update_log 的 PK 相关的一键列。
示例日志表:
CREATE TABLE dbo.sample_auto_update_log (
id INT NOT NULL, --Primary key from [prod_tbl]
item_a_before VARCHAR(25) NULL, --[prod_tbl].[item_a]
item_a_detail VARCHAR(25) NULL, --Value from elsewhere in the DB that applies
item_a_after VARCHAR(25) NULL, --The new value SET for [prod_tbl].[item_a]
update_count INT NOT NULL DEFAULT (0),
update_datetime DATETIME NOT NULL DEFAULT (GETDATE())
);
示例合并:
MERGE sample_auto_update_log WITH (HOLDLOCK) AS t
USING #changes AS s
ON (t.id = s.id AND t.item_a_before = s.item_a_before AND t.item_a_after = s.item_a_after)
WHEN MATCHED THEN
UPDATE
SET update_count = update_count + 1, update_datetime = GETDATE()
WHEN NOT MATCHED THEN
INSERT (id, item_a_before, item_a_detail, item_a_after)
VALUES (s.id, s.item_a_before, s.item_a_detail, s.item_a_after);
问题: 如何使用索引或其他方法最好地优化 MERGE?
【问题讨论】:
-
老实说,您最好不要使用 MERGE 进行 upserts。 MERGE 有许多错误,像这样的 upsert 就是其中之一。 mssqltips.com/sqlservertip/3074/…
-
@SeanLange ,你有什么好的选择吗?我已经阅读了几篇文章,包括您发布的文章,似乎很多这些问题不适用于我的情况。例如,我没有在我的目标或源表中使用主键,没有变量或表变量,没有在触发器中使用它,我已经在使用
(HOLDLOCK)提示来防止竞争条件等。我也可能有夸大了线程安全的重要性——性能是一个更大的问题,因为用户不太可能同时访问相同的记录,但这会运行很多次。 -
为什么不直接发出两条语句加入您的临时表?第一个是更新,然后是插入。
-
真的只是因为我阅读MERGE可以更快。我想使用这里建议的方法:stackoverflow.com/a/21209131/550595,但这似乎只适用于单行。不过,我可能只使用两条语句,如果这成为问题,那么我将编写一个删除重复项并增加计数器的作业。
标签: sql-server-2008 merge upsert