Bra*_*out 4 sql t-sql optimization sql-server-2008
我有一个SQL查询(对于SQL Server 2008 R2)需要很长时间才能完成.我想知道是否有更好的方法吗?
SELECT @count = COUNT(Name)
FROM Table1 t
WHERE t.Name = @name AND t.Code NOT IN (SELECT Code FROM ExcludedCodes)
Run Code Online (Sandbox Code Playgroud)
Table1中有大约90万行,并由Name和Code索引.ExcludedCodes只有大约30行.
这个查询在一个存储过程中被调用大约40k次,程序完成所需的总时间是27分钟.我相信这是我最大的瓶颈,因为它查询了大量的行和次数它做到了.
因此,如果您知道优化此方法的好方法,我们将不胜感激!如果它无法优化那么我想我坚持了27分钟......
编辑
我改变了NOT IN
,以NOT EXISTS
它削减时间降低到10:59,让孤独是我的一个巨大的增益.我仍然会尝试按照下面的建议进行group by语句,但是这需要完全重写存储过程并且可能需要一些时间......(正如我之前所说,我不是最好的SQL,但它正在启动在我身上成长.^^)
除了让查询本身更快地响应的变通方法之外,您是否考虑在表中维护一个列,告诉它是否在此集合中?它需要大量的维护,但如果ExcludedCodes
表不经常更改,那么进行维护可能会更好.例如,您可以添加BIT列:
ALTER TABLE dbo.Table1 ADD IsExcluded BIT;
Run Code Online (Sandbox Code Playgroud)
使其为NOT NULL并默认为0.然后您可以创建筛选索引:
CREATE INDEX n ON dbo.Table1(name)
WHERE IsExcluded = 0;
Run Code Online (Sandbox Code Playgroud)
现在你只需要更新一次表:
UPDATE t
SET IsExcluded = 1
FROM dbo.Table1 AS t
INNER JOIN dbo.ExcludedCodes AS x
ON t.Code = x.Code;
Run Code Online (Sandbox Code Playgroud)
并且正在进行中你必须使用两个表上的触发器来维护它.有了这个,您的查询将变为:
SELECT @Count = COUNT(Name)
FROM dbo.Table1 WHERE IsExcluded = 0;
Run Code Online (Sandbox Code Playgroud)
编辑
至于"NOT IN比LEFT JOIN慢"这里是一个简单的测试我只在几千行上执行:
编辑2
我不确定为什么这个查询不会做你想要的,并且比你的40K循环更有效:
SELECT src.Name, COUNT(src.*)
FROM dbo.Table1 AS src
INNER JOIN #temptable AS t
ON src.Name = t.Name
WHERE src.Code NOT IN (SELECT Code FROM dbo.ExcludedCodes)
GROUP BY src.Name;
Run Code Online (Sandbox Code Playgroud)
或LEFT JOIN等效:
SELECT src.Name, COUNT(src.*)
FROM dbo.Table1 AS src
INNER JOIN #temptable AS t
ON src.Name = t.Name
LEFT OUTER JOIN dbo.ExcludedCodes AS x
ON src.Code = x.Code
WHERE x.Code IS NULL
GROUP BY src.Name;
Run Code Online (Sandbox Code Playgroud)
我会花费不到27分钟的时间在这些查询中投入资金.我甚至建议顺序运行两个查询将比一个需要27分钟的查询快得多.
最后,您可以考虑索引视图.我不知道你的桌子结构以及你是否违反了任何限制,但值得调查恕我直言.