选择数据后索引是否仍然有效?

时间:2012-07-12 20:03:23

标签: sql-server join indexing

我想要加入两个表,它们都有我想要加入的列的索引。

QUERY 1

SELECT * FROM [A] INNER JOIN [B] ON [A].F = [B].F;

QUERY 2

SELECT * FROM (SELECT * FROM [A]) [A1] INNER JOIN (SELECT * FROM B) [B1] ON [A1].F=[B1].F

第一个查询显然会使用索引,第二个查询怎么样? 在执行括号中的两个select语句之后,会发生join,但我的猜测是索引无助于加快查询速度,因为它几乎是一个新表..

4 个答案:

答案 0 :(得分:5)

查询的执行方式与您建议的完全不同,首先执行内部查询,然后将结果与外部查询结合使用。优化器将采用您的查询,并将查看许多可能的方法,以通过各种连接顺序,索引使用等等获取您的数据,并提出一个感觉最佳的计划。

如果您执行两个查询并查看各自的执行计划,我认为您会发现它们使用的完全相同。

这是一个相同概念的简单例子。我创建了我的架构:

CREATE TABLE A (id int, value int)
CREATE TABLE B (id int, value int)

INSERT INTO A (id, value)
VALUES (1,900),(2,800),(3,700),(4,600)

INSERT INTO B (id, value)
VALUES (2,800),(3,700),(4,600),(5,500)

CREATE CLUSTERED INDEX IX_A ON A (id)
CREATE CLUSTERED INDEX IX_B ON B (id)

并运行您提供的查询。

SELECT * FROM A INNER JOIN B ON A.id = B.id 
SELECT * FROM (SELECT * FROM A) A1 INNER JOIN (SELECT * FROM B) B1 ON A1.id = B1.id 

生成的计划如下所示:

enter image description here

正如您所看到的,两者都使用索引。

答案 1 :(得分:4)

有可能SQL Server查询优化器能够检测到查询2实际上与查询1相同并使用相同的索引方法。

是否发生这种情况取决于很多因素:您的表格设计,表格统计信息,查询的复杂性等。如果您想确切知道,请让SQL Server查询分析器显示执行计划即可。以下是一些帮助您入门的链接:

答案 2 :(得分:2)

SQL Server使用predicate pushing(a.k.a。谓词下推)将查询条件尽可能地移向源表。它不会按照你括号的顺序盲目地做事。优化器使用复杂的规则 - 本质上是一种几何 - 来确定查询的含义,并根据需要重新调整对数据的访问,以便在仍然获得最佳性能的同时返回查询逻辑所需的最终数据集。

当查询变得越来越复杂时, 是优化器无法彻底搜索所有可能的执行计划的点,并且可能最终会出现次优的情况。但是,你几乎可以假设像你所呈现的一个简单的情况是总是被“透视”并被优化掉。

所以答案是你应该获得与两个查询组合起来一样好的表现。现在,如果您加入的值是复合的,即它们是计算或连接的结果,那么您几乎肯定不会得到您想要的谓词推送有用,因为服务器不会或不能根据部分字符串或执行反向算术之后进行搜索。

我可以建议将来,在这里提出这样的问题之前,你只需要自己检查执行计划,以验证它是否正在使用索引?您可以通过一些实验回答您自己的问题。如果你仍然有问题,那就来发帖,但同时尝试做一些你自己的研究,作为尊重帮助你的人的标志。

要查看执行计划,可以在SQL Server Management Studio(2005及更高版本)或SQL查询分析器(SQL 2000)中单击菜单栏上的“显示执行计划”按钮,运行查询,然后切换到底部的选项卡,显示执行计划的图形版本。稍微捅一下并将鼠标悬停在各个部分上会很快显示哪些索引在哪些表上使用。

但是,如果事情不符合您的预期,请不要自动认为服务器出错了。它可能决定在不使用索引的情况下扫描主表的成本更低 - 而且几乎总是正确的。扫描可以更便宜的原因有很多,其中一个是非常小的表,另一个是服务器统计猜测它必须返回的行数超过表的重要部分。

答案 3 :(得分:0)

这两个查询都是相同的。在转换期间,第二个查询将与第一个查询相同。

但是,如果您有特定要求,我会建议您输入整个代码。然后回答您的问题要容易得多。