我有一张这样的表:
Name | TimeA | TimeB | ValueA | ValueB
而且,我正在执行一些MERGE
操作,如下所示:
CREATE TABLE #TEMP1...
INSERT INTO #TEMP1
SELECT Name, Value
FROM dbo.AnotherTable
WHERE ...
MERGE INTO dbo.MyTable AS Target
USING (SELECT Name, Value FROM #TEMP1) AS Source
ON Target.Name = Source.Name
AND Target.TimeA = @TimeA
WHEN MATCHED THEN
UPDATE SET ValueA = Value
WHEN NOT MATCHED THEN
INSERT (Name, TimeA, TimeB, ValueA)
VALUES (Source.Name, @TimeA, @TimeB, Value)
查询执行计划说明如下:
MERGE -> Table Merge 3% -> Compute Scalar 0% ->
Top 0% -> Compute Scalar 0% -> Compute Scalar 0% ->
Nested Loops (Left Outer Join) 0% <- Constant Scan 0%
^
|
|
--- Compute Scalar 0% <- Table Spool (Kager Spool) 12% <- Table Scan 86%
然而,该计划并没有告诉我索引会改善性能。我认为(Name,TimeA)
上的非聚集索引应该可以提高性能。有没有更好的方法来实现这样的MERGE查询的性能?
编辑1 :我应该注意表格的大小。平均来源平均包含30-70行,而目标包含&gt; 3000万行。
答案 0 :(得分:4)
我会考虑
WHEN MATCHED AND ValueA <> Value THEN
你可能正在更新不需要的记录。
答案 1 :(得分:3)
这是供参考。我用过一些相关的观点来改进我的查询:
为了提高MERGE语句的性能,我们建议使用 遵循指数准则:
- 在源表中的连接列上创建一个唯一且覆盖的索引。
- 在目标表的连接列上创建唯一的聚簇索引。
要过滤掉源表或目标表中的行,请使用其中一个 以下方法。指定行过滤的搜索条件 适当的WHEN条款。例如,当没有匹配时 S.EmployeeName喜欢'%'然后插入....
因此,我添加的索引是:
ALTER TABLE #TEMP1
ADD CONSTRAINT PK_TEMP1 PRIMARY KEY CLUSTERED
(ELEMENTINSTANCE, ifAlias)
CREATE CLUSTERED INDEX IX_MyTable
ON dbo.MyTable(Name)
我最后的疑问是:
MERGE INTO dbo.MyTable AS Target
USING (SELECT Name, Value FROM #TEMP1) AS Source
ON Target.Name = Source.Name
WHEN MATCHED AND ValueA <> Value AND Target.TimeA = @TimeA THEN
UPDATE SET ValueA = Value
WHEN NOT MATCHED THEN
INSERT (Name, TimeA, TimeB, ValueA)
VALUES (Source.Name, @TimeA, @TimeB, Value)
这给了我以下执行计划:
MERGE -> Table Merge 3% -> Compute Scalar 0% ->
Top 0% -> Compute Scalar 0% -> Compute Scalar 0% ->
Nested Loops (Left Outer Join) 0% <- Table Scan (#TEMP1) Source 12%
^
|
|
--- Compute Scalar 0% <- Clustered Index Seek (dbo.MyTable) 12%
谢谢大家的帮助!希望这应该保持一段时间的性能。
答案 2 :(得分:0)
我发现,通过花费大量时间创建没有提高性能的索引,当SSMS生成查询计划,并且不建议创建索引时,没有索引会有所帮助。情况并非总是如此,但往往是。
话虽如此,通过尝试一些索引,进入Profiler并检查一些指标,如总读数,可以很容易地解决问题。看看有什么帮助,有什么不帮助。如果没有看到完整的架构和各种表中的行数,我们就无法提供太多帮助。此外,我认为合并通常需要表扫描,没有索引可以帮助。