20

我在表 T 的 A、B、C、D 列上有一个索引

我有一个查询,它从 WHERE 子句中的 A、B、C 中提取。

将使用该索引还是需要一个仅包含 A、B、C 的单独索引?

4

8 回答 8

15

David B 是正确的,您应该检查执行计划以验证正在使用的索引。

将使用该索引还是需要一个仅包含 A、B、C 的单独索引?

要回答问题的最后一部分,我认为这是核心的基础主题(与直接解决方案相反),几乎没有理由对索引列的子集进行索引。如果您的索引是 (A, B, C, D),则针对 (A, B, C) 的 WHERE 很可能会导致索引搜索,这是理想的情况 - 索引包含引擎需要的所有信息直接进入结果集。我相信这适用于数字类型和字符串类型中的相等性测试,尽管它可以用 LIKE '%'s 分解)。另一方面,如果您的 WHERE 仅引用了 D,那么您很可能会以索引扫描结束,这意味着 SQL 引擎必须扫描 A、B 和 C 的所有组合,然后检查 D 是否满足您的条件,然后再决定是否将该行添加到结果集中。在一个特别大的表上,当我发现自己必须对“D”列进行大量查询时,我只为 D 添加了一个额外的索引,并且看到了大约 90% 的性能提升。

编辑:我还应该推荐在 SQL Management Studio 中使用数据库引擎优化顾问。它会告诉您您的表是否没有理想地为您要运行的查询建立索引。

于 2008-09-25T20:11:25.327 回答
8

这取决于!

WHERE A like '%x%'
  and B = 1
  and C = 1
//
WHERE A = 1
  OR B = 1
  OR C = 1
//
WHERE DateAdd(dd, 1, A) = '2008-01-01'
  AND B = 1
  AND C = 1

这些都不会依赖索引,因为索引没有用。

单击“显示估计的执行计划”以确认潜在的索引使用情况。

于 2008-09-25T19:49:20.920 回答
5

在 Oracle 数据库中,这称为复合索引(12g 文档但对早期版本有效)

复合索引可以加快 SELECT 语句的数据检索,其中 WHERE 子句引用复合索引中列的所有前导部分。因此,定义中使用的列的顺序很重要。通常,最常访问的列排在最前面。

所以在你的情况下,是的。该索引将/可以使用。这可以通过使用解释计划来验证。

如果 MS SQLSERVER 不同(我怀疑它可能),您将需要一个新的答案。

编辑: 还应该提到它只会考虑使用索引..这并不一定意味着它会使用它。

Edit2: Oracle 11g 及更高版本现在有一个选项,允许它跳过索引中的列。因此对 A、B 和 D 的查询可能仍会使用索引

于 2008-09-25T19:45:54.127 回答
4

将使用索引,是的。哪些索引会产生更优化的查询计划是相当聪明的,它应该没有问题。

与这类事情一样,不要相信我的话 - 对其进行基准测试。创建一个表,用代表性数据填充它,查询它,索引它,然后再次查询它。

于 2008-09-25T19:49:24.727 回答
2

索引包含查询中未使用的列这一事实不会阻止它被使用。

这并不是说它肯定被使用,它可能由于不同的原因而被忽略(可能是因为一个或多个其他索引更有用)。

与往常一样,对估计的执行计划进行调查,看看可能会发生什么。

于 2008-09-25T19:56:31.200 回答
2

从简单的等号查找开始(WHERE A=1 and B='Red' and C=287)是的,索引将(最有可能)被使用。索引将首先用于帮助优化器“猜测”与选择匹配的行数,然后再实际访问这些行。

作为对 David B 关于“like”谓词的评论的回应,SQLServer 可能仍会使用索引,这取决于您选择的内容。例如,如果您选择 count(*),那么 SQLServer 可能会扫描索引并计算与 where 子句匹配的命中,因为索引较小并且需要扫描的 IO 较少。即使您从基表中选择一些列,它也可能决定这样做,这取决于 SQLServer 对索引的选择性。

于 2008-09-25T19:57:16.237 回答
1

一般来说,是的,所有现代数据库都足够聪明地做到这一点。也有例外,例如,如果表上的统计数据显示其中的数据量足够小,以致全表读取效率更高,那么索引将被打折,但作为一项规则,您可以依赖它在适当情况下。

因此,您可以在设计索引时利用这一点。举例来说,我有一个表,其中包含 A、B、C 作为键值,列 Y 和 Z 包含我知道将经常被语句检索的数据

SELECT Y FROM table WHERE A = alpha and B = beta and C = gamma 

SELECT Z FROM table WHERE A = alpha and B = beta and C = gamma 

我通常会在 A、B、C、X、Z 上创建一个索引——假设 X 和 Z 是一些相当小的字段。这样做的原因是我知道上面语句中的访问路径将使用索引,并且由于我要检索的数据已经在读取的索引中,因此不需要单独读取检索表数据本身所需的数据块将需要。在某些情况下,此策略可以显着加快数据检索速度。当然,您需要为更新成本和磁盘空间付费,因此您需要在应用它之前了解您的数据库在做什么,但由于在大多数数据库中读取次数大大超过写入次数,因此通常值得考虑。

于 2008-09-25T20:06:22.750 回答
1

这是另一个“取决于”答案……它还取决于您的桌子有多大……

我同意其他所有提到检查执行计划以验证您的索引是否正在使用的人的观点。

这里有几篇关于阅读执行计划的文章,你会觉得它们很有用:

http://www.sqlservercentral.com/articles/Administering/executionplans/1345/ http://www.codeproject.com/KB/database/sql-tuning-tutorial-1.aspx

还有一篇关于搜索与扫描的好文章,我推荐:http: //blogs.msdn.com/craigfr/archive/2006/06/26/647852.aspx

Craig Freedman 的博客上有一篇好文章,这里还有一篇你应该会觉得有用的文章。本文是关于 SQL Server 用于确定要使用哪个索引的一些因素...

http://blogs.msdn.com/craigfr/archive/2006/07/13/664902.aspx

小心!杰夫

于 2008-09-25T21:15:43.020 回答