可以优化此SQL查询以更快地运行吗?

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,但它正在启动在我身上成长.^^)

Aar*_*and 5

除了让查询本身更快地响应的变通方法之外,您是否考虑在表中维护一个列,告诉它是否在此集合中?它需要大量的维护,但如果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分钟的查询快得多.

最后,您可以考虑索引视图.我不知道你的桌子结构以及你是否违反了任何限制,但值得调查恕我直言.