【问题标题】:How to correctly create non-clustered index to help stored procedure如何正确创建非聚集索引来帮助存储过程
【发布时间】:2020-10-26 01:00:31
【问题描述】:

我正在 SQL Server 中准备一个存储过程。基本上,我这里有两个表,表 A 和 B,这两个表在 Col4 上连接。此存储过程将根据表 B 中的属性过滤表 A,例如 where 子句中的 Col41Col42Col41Col42 都是 float 数据类型)。

表 A:

        Col1    Col2    Col3    Col4
Row1    **      **      **      **
Row2    **      **      **      **

表 B:

        Col5    Col4    Col41   Col42
Row1    **      **      **      **
Row2    **      **      **      **

两个表的记录很多,所以我打算用非聚集索引来帮助查询(两个表的第一列都设置为主键)。

当我如下图创建了这个非聚集索引,然后在存储过程(临时索引)中使用后将其丢弃,性能相当不错。

CREATE NONCLUSTERED INDEX IX_1 ON tableB (Col41, Col42)


DROP INDEX IF EXISTS IX_1 ON tableB

但是,如果我直接将相同的非聚集索引添加到tableB(永久索引)中,要么右键单击tableB的索引文件夹,要么运行以下代码,性能会差很多。好像非聚集索引虽然创建了,但是没有被使用过。

CREATE NONCLUSTERED INDEX IX_1 ON tableB (Col41, Col42) 

无法弄清楚为什么运行结果会变成这样。任何人都可以就如何解决它提供任何想法吗?谢谢。

【问题讨论】:

  • 创建索引并不意味着它会被使用。这取决于与您使用的值相关的数据分布
  • 您是唯一执行此过程的人吗(例如,在开发环境中)?有没有其他人在那个环境中做任何事情?该过程是否带有任何参数?如果您是唯一一个运行/测试它的人,您是否总是使用相同的参数值运行它?
  • 编辑您的问题以包含两个查询的actual execution plans - 答案将在其中。
  • 嗨@Mitch Wheat,你能多谈谈数据分布吗,或者你能列出一些我可以通过的相关链接吗?谢谢
  • @allmhuran,嗨,Allmhuran,我确信我是迄今为止唯一使用此存储过程的人,我多次使用相同的参数尝试此 sp。

标签: sql sql-server non-clustered-index


【解决方案1】:

对于您的情况,您需要两个索引 -

tableB(Col41, Col42)
tableA(Col4)

如果您仍然看到问题,如 AlwaysLearning 所述,请检查执行计划,它可以告诉您如何访问数据的详细信息。

【讨论】:

  • 谢谢 ch_g。实际上 Col4 是主键,而且似乎不起作用。
【解决方案2】:

正如@Mitch Wheat 提到的,添加索引并不能确保它会一直被使用。还有一件事,不要在存储过程中创建和删除索引,除非您在临时表上创建。创建索引是一项昂贵的操作。最好在开发代码之外单独进行。

这取决于特定查询的查询和索引的选择性。有一个叫做“引爆点”的东西会检查,无论是使用索引还是直接从表中读取,对于特定的查询都是有好处的。 Read more on Tipping Point by Kimberly Tripp

关于您的查询,当您告诉 col41 和 col42 将始终用于过滤并使用 Col4 与 TableA 连接时,我建议您像下面这样覆盖索引,以使索引可搜索。如果组合是唯一的,则创建唯一索引。

CREATE NONCLUSTERED INDEX Idx_TableB_Col41_Col42_Col4 ON TableB(Col41,Col42,Col4)

但是,在这里您必须查看列的选择性才能看到列的顺序:Col41 和 Col42。选择性较高的列将出现在左侧,然后是选择性较低的列在右侧。

有关查找列的选择性,请参阅列统计信息。会有第二个结果集,它告诉列的密度。越少,列的选择性就越高。

EXEC DBCC SHOW_STATISTICS(TableB, ColumnStatisticsName)

另外,在 TableA 上为 Col4 创建索引。如果列是唯一的,则创建唯一索引。

CREATE NONCLUSTERED INDEX Idx_TableA_col4 ON TableA(Col4)

CAVEAT:以上内容也不保证始终使用索引。没有看到执行计划和实际查询,很难分辨。上述指南也专门针对一个查询。我建议您看看,如果您可以将上述索引与现有查询合并到其他索引以减少表上的索引占用空间。

【讨论】:

  • 谢谢 Venka,我已经尝试过用你的方法在三列上创建非聚集索引,但它不起作用。我也尝试过显示执行计划。由于此处无法添加图片,因此我在此处发布了另一个问题(stackoverflow.com/questions/62763249/…)。您认为有足够的信息来诊断问题吗?
猜你喜欢
  • 1970-01-01
  • 2021-01-14
  • 2013-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 2017-05-08
  • 2021-09-23
相关资源
最近更新 更多