1

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

查询 1

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

查询 2

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

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

4

4 回答 4

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 

生成的计划如下所示:

在此处输入图像描述

如您所见,两者都使用索引。

于 2012-07-12T20:13:37.373 回答
4

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

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

于 2012-07-12T20:13:02.870 回答
2

SQL Server 使用谓词推送(又名谓词下推)将查询条件尽可能地移向源表。它不会按照你给它们加上括号的顺序盲目地做事。优化器使用复杂的规则(本质上是一种几何图形)来确定查询的含义,并根据需要重组其对数据的访问,以获得最佳性能,同时仍返回相同的最终数据集您的查询逻辑要求。

当查询变得越来越复杂时,优化器有时无法彻底搜索所有可能的执行计划,最终可能会出现次优结果。但是,您几乎可以假设像您提出的一个简单案例将始终被“透视”并优化掉。

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

我是否可以建议,将来,在此处提出此类问题之前,您只需检查自己的执行计划以验证它是否正在使用索引?您可以通过一些实验来回答您自己的问题。如果您仍有疑问,请发帖,但同时尝试做一些自己的研究,以表示对帮助您的人的尊重。

要查看执行计划,在 SQL Server Management Studio(2005 及更高版本)或 SQL 查询分析器(SQL 2000)中,您只需单击菜单栏上的“显示执行计划”按钮,运行查询,然后切换到底部显示执行计划的图形版本。一些小动作并将鼠标悬停在各个部分上会快速显示哪些索引正在用于哪些表。

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

于 2012-07-13T05:30:05.330 回答
0

这两个查询是相同的。第二个查询将在转换过程中与第一个查询一样进行转换。

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

于 2012-07-14T11:39:01.320 回答