【发布时间】:2010-09-13 05:26:51
【问题描述】:
我在表 T 的 A、B、C、D 列上有一个索引
我有一个从 T 中提取的查询,其中包含 WHERE 子句中的 A、B、C。
将使用索引还是需要单独的索引,仅包含 A、B、C?
【问题讨论】:
标签: sql sql-server sql-execution-plan
我在表 T 的 A、B、C、D 列上有一个索引
我有一个从 T 中提取的查询,其中包含 WHERE 子句中的 A、B、C。
将使用索引还是需要单独的索引,仅包含 A、B、C?
【问题讨论】:
标签: sql sql-server sql-execution-plan
一般来说是的,所有现代数据库都足够聪明,可以做到这一点。也有例外,例如,如果表上的统计数据显示其中的数据量足够小,以致全表读取效率更高,那么索引将被打折,但作为一项规则,您可以依赖它在适当的地方。
因此,您可以在设计索引时利用这一点。举例来说,我有一个表,其中包含 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 是一些相当小的字段。原因是我知道上面语句中的访问路径将使用索引,并且因为我要检索的数据已经在索引中读取,所以没有单独读取数据块需要检索表数据本身。在某些情况下,此策略可以显着加快数据检索速度。当然,您需要为更新成本和磁盘空间付费,因此您需要在应用它之前了解您的数据库在做什么,但由于在大多数数据库中读取数量大大超过写入数量,因此通常值得考虑。
【讨论】:
在 Oracle 数据库中,这称为 Composite Index(12g 文档,但对早期版本有效)
复合索引可以加快 SELECT 语句的数据检索,其中 WHERE 子句引用复合索引中所有列的前导部分。因此,定义中使用的列的顺序很重要。通常,最常访问的列排在最前面。
所以在你的情况下,是的。该索引将/可以使用。这可以通过使用解释计划来验证。
如果 MS SQLSERVER 不同(我怀疑它可能),您将需要一个新的答案。
编辑: 还应该提到它只会考虑使用索引。这并不一定意味着它会使用它。
编辑2: Oracle 11g 和更高版本现在有一个选项允许它跳过索引中的列。所以对 A、B 和 D 的查询可能仍然使用索引
【讨论】:
David B 说得对,您应该检查执行计划以验证索引是否正在使用。
是否会使用该索引,或者是否需要一个仅包含 A、B、C 的单独索引?
要回答问题的最后一部分,我认为这是核心的基础主题(与直接解决方案相反),几乎从来没有理由对索引列的子集进行索引.如果您的索引是 (A, B, C, D),则针对 (A, B, C) 的 WHERE 很可能会导致索引 seek,这是理想的情况 - 索引包括引擎需要直接进入结果集的所有信息。我相信这适用于数字类型和字符串类型中的相等性测试,尽管它可以用 LIKE '%'s 分解)。另一方面,如果你的 WHERE 只引用了 D,你很可能会得到一个索引 scan,这意味着 SQL 引擎必须扫描 A、B 和C,然后检查 D 是否满足您的条件,然后再决定是否将该行添加到结果集中。在一个特别大的表上,当我发现自己必须对列“D”进行大量查询时,我只为 D 添加了一个额外的索引,性能提高了大约 90%。
编辑:我还应该推荐使用 SQL Management Studio 中的数据库引擎优化顾问。它会告诉您您的表是否没有为您要运行的查询理想地建立索引。
【讨论】:
这是另一个“视情况而定”的答案...它还取决于您的桌子有多大...
我同意其他所有提到检查执行计划以验证您的索引是否正在使用的人的观点。
这里有几篇关于阅读执行计划的文章,您会觉得它们很有用:
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
保重! 杰夫
【讨论】:
视情况而定!
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
这些不会依赖索引,因为索引没有用。
点击“显示估计的执行计划”以确认潜在的索引使用情况。
【讨论】:
从简单的等号查找开始(WHERE A=1 and B='Red' and C=287)是的,索引将(最有可能)被使用。索引将首先用于帮助优化器“猜测”与选择匹配的行数,然后再实际访问这些行。
针对 David B 关于“like”谓词的评论,SQLServer 可能仍会使用索引,这取决于您选择的内容。例如,如果您选择 count(*),则 SQLServer 可能会扫描索引并计算与 where 子句匹配的命中,因为索引更小并且需要更少的 IO 来扫描。即使您从基表中选择一些列,它也可能会决定这样做,这取决于 SQLServer 对索引的选择性。
【讨论】:
索引包含查询中未使用的列这一事实不会阻止它被使用。
这并不是说它肯定会被使用,它可能因为不同的原因而被忽略(也许是因为一个或多个其他索引更有用)。
与往常一样,对估计的执行计划进行调查,看看可能会发生什么。
【讨论】:
将使用索引,是的。哪些索引会产生更优化的查询计划是相当聪明的,它应该没有问题。
对于这类事情,不要相信我的话 - 对其进行基准测试。创建一个表,用代表性数据填充它,查询它,索引它,然后再次查询。
【讨论】: