【问题标题】:Adding specific index to SQL Server table to improve performance向 SQL Server 表添加特定索引以提高性能
【发布时间】:2019-04-13 21:09:06
【问题描述】:

我对一个表的查询很慢。

SELECT (some columns)
FROM Table

此表有一个 ID (integer, identity (1,1)) 主索引,这是此表上的唯一索引。

查询有一个WHERE 子句:

WHERE Field05 <> 1 
  AND (Field01 LIKE '%something%' OR Field02 LIKE '%something%' OR 
       Field03 LIKE'%something%' OR Field04 LIKE'%something%')
  • Field05bit, not null
  • Field01NVarchar(255)
  • Field02NVarchar(255)
  • Field03Nchar(11)
  • Field04Varchar(50)

执行计划显示“聚集索引扫描”导致执行缓慢。

我尝试添加索引:

CREATE NONCLUSTERED INDEX IX_Aziende_RagSoc ON dbo.Aziende (Field01);
CREATE NONCLUSTERED INDEX IX_Aziende_Nome ON dbo.Aziende (Field02);
CREATE NONCLUSTERED INDEX IX_Aziende_PIVA ON dbo.Aziende (Field03);
CREATE NONCLUSTERED INDEX IX_Aziende_CodFisc ON dbo.Aziende (Field04);
CREATE NONCLUSTERED INDEX IX_Aziende_Eliminata ON dbo.Aziende (Field05);

同样的表现,执行计划再次显示“聚集索引扫描” 我删除了这 5 个索引,只添加了一个索引:

CREATE NONCLUSTERED INDEX IX_Aziende_Ricerca
ON Aziende (Field05)
INCLUDE (Field01, Field02, Field03, Field04)

性能相同,但在这种情况下执行计划会发生变化。

更复杂但总是很慢。

我删除了这个索引并添加了一个不同的索引:

CREATE NONCLUSTERED INDEX IX_Aziende_Ricerca
ON Aziende (Field05,Field01,Field02,Field03,Field04)

相同的性能,在这种情况下,执行计划与之前的情况保持一致。

执行总是很慢。

我没有其他想法......有人可以帮忙吗?

【问题讨论】:

  • 使用 LIKE '%something%' 和前导 % 会使这些列上的索引无用 - SQL Server 永远无法在此类比较中使用任何索引。
  • 有趣的......和非常糟糕的新......
  • 你可以试试CREATE NONCLUSTERED INDEX IX_Aziende_Ricerca ON Aziende (Field05,Field01,Field02,Field03,Field04) INCLUDE (some columns) WHERE Field05 &lt;&gt; 1,不过这里确实没什么可优化的。

标签: sql sql-server optimization indexing


【解决方案1】:

评论太长了。

首先,您应该使用Field05 = 0 而不是Field05 &lt;&gt; 1。平等对于优化器来说更容易阅读和更好。在这种特殊情况下不会有什么不同,除非您有一个以 Field05 开头的聚集索引,或者如果几乎所有值都是 1(也就是说,0 具有高度选择性)。

其次,一般来说,您只能使用全文索引来优化字符串模式匹配。这又具有其他限制,例如查找单词或前缀(但不以通配符开头)。

一个例外是如果“某物”是一个常数。在这种情况下,您可以添加带有索引的持久计算列,以捕获这些列中是否存在该值。不过,我猜“某事”并不是一成不变的。

这会让您获得全文索引或重新考虑您的数据模型。也许您正在将内容存储在字符串中——比如标签列表——实际上应该在一个单独的表中。

【讨论】:

  • "Something" 在每次执行时都会发生变化。但是“某事”通常只是四个字段之一的一部分,因此我必须使用 LIKE '%something%',如果全文索引不需要通配符...
【解决方案2】:

只是为了附和几个 cmets。 即使存在索引,SQL Server 也倾向于进行表扫描,除非它认为 Searched 字段的基数小于 1%。考虑到这一点,位字段的索引中永远不会有任何值。 (基数 50%!)

您可能会考虑的一个选项是创建一个过滤索引 (WHERE Field05 = 0) 然后您可以在此索引中包含您的其他字段。 请注意,这只会在您没有从表中选择任何其他列时对您有所帮助。

您能否检查您的数据中有多少比例 Field5=0 ?- 如果这很小(例如,低于 10%),那么过滤索引可能会有所帮助。

我看不出有什么方法可以避免某种扫描 - 最好的方法可能是索引扫描。

另一种选择(本质上是一样的!)是创建一个架构绑定索引视图,其中包含您需要的所有列,并将 field5=0 过滤器硬编码到视图中。

再一次 - 除非您确定 Selected Column 列表将是表中列的一小部分,否则 SQL 可能会通过表扫描更快。如果您只从一个非常宽的表中选择少数列,那么覆盖这些列的索引可能会有所帮助,即使它仍然是一次扫描 - 每页的行数将比扫描整个表多。

总而言之-如果您可以保证将选择表格cols的一小部分 AND field5 = 0 表示表中的少数行,那么带有 Includes 的过滤索引可能是有价值的。

EG

在 dbo.Aziende(ID) 上创建非聚集索引 ix 包括 (Field01,Field02,Field03,Field04, [select 使用的其他列]) WHERE (field5=0)

祝你好运!

【讨论】:

    【解决方案3】:

    经过一番斗争,我忘记了添加索引的想法。 索引没有任何变化。

    我更改了构建查询的 C# 代码,现在我尝试理解从函数接收到的“something”参数的含义。 如果它是类型 1,那么我在 Field01 上构建一个 WHERE 如果它是类型 2,那么我在 Field02 上构建一个 WHERE 如果它是类型 3,那么我在 Field03 上构建一个 WHERE 如果是类型 4,那么我在 Field04 上构建一个 WHERE

    这样,执行时间变成了之前的 1/4。 客户很满意。

    【讨论】:

      猜你喜欢
      • 2014-03-26
      • 2015-11-17
      • 2017-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 2016-05-09
      • 1970-01-01
      相关资源
      最近更新 更多