【问题标题】:Two selects or one select + one join in SQL?SQL中的二选还是一选+一联接?
【发布时间】:2013-11-19 01:43:01
【问题描述】:

下面的代码 sn-ps 应该做同样的工作。

SELECT t1.* FROM table1 t1
INNER JOIN table2 t2
ON t1.ID = t2.IDService
WHERE t2.Code = @code

SELECT * FROM table1 t1
WHERE t1.ID IN (SELECT IDService FROM table2 WHERE Code = @code)

一般来说,哪一个是最好的解决方案?并且在计算上,最好有两个嵌套选择还是使用内连接更好?

编辑: 考虑到 table1 的 PK 是 ID 并且 table2 的 PK 是这对夫妇 (IDService,Code)。因此,修复代码(使用WHERE 子句)并将子句ON 应用于IDService,我可以假设每次选择的结果都是相同的。

【问题讨论】:

标签: sql sql-server-2008 join inner-join


【解决方案1】:

你认为他们应该做同样的工作的想法是不正确的。想象一下这个测试数据集:

T1

ID
----
1
2
3
4
5

T2

ID
---
1
1
1
2
2
3

DDL

CREATE TABLE dbo.T1 (ID INT NOT NULL);
INSERT dbo.T1 (ID) VALUES (1), (2), (3), (4), (5);

CREATE TABLE dbo.T2 (ID INT NOT NULL);
INSERT dbo.T2 (ID) VALUES (1), (1), (1), (2), (2), (3);

SELECT  *
FROM    dbo.T1
WHERE   T1.ID IN (SELECT T2.ID FROM dbo.T2);

SELECT  T1.*
FROM    dbo.T1
        INNER JOIN dbo.T2
            ON T1.ID = T2.ID;

结果

ID
---
1
2
3

ID
---
1
1
1
2
2
3

只有当您搜索的列是唯一的时,您的结果才会相同。

CREATE TABLE dbo.T1 (ID INT NOT NULL);
INSERT dbo.T1 (ID) VALUES (1), (2), (3), (4), (5);

CREATE TABLE dbo.T2 (ID INT NOT NULL);
INSERT dbo.T2 (ID) VALUES (1), (2), (3);

SELECT  *
FROM    dbo.T1
WHERE   T1.ID IN (SELECT T2.ID FROM dbo.T2);

SELECT  T1.*
FROM    dbo.T1
        INNER JOIN dbo.T2
            ON T1.ID = T2.ID;

即使结果相同,但执行计划却不同。使用IN 的第一个查询能够使用反半连接,这意味着它知道不需要 t2 中的数据,因此一旦找到单个匹配项,它就可以停止扫描进一步的匹配项。

如果您将第二个表限制为只有唯一值,那么您将看到相同的计划:

CREATE TABLE dbo.T1 (ID INT NOT NULL PRIMARY KEY);
INSERT dbo.T1 (ID) VALUES (1), (2), (3), (4), (5);

CREATE TABLE dbo.T2 (ID INT NOT NULL PRIMARY KEY);
INSERT dbo.T2 (ID) VALUES (1), (2), (3);

SELECT  *
FROM    dbo.T1
WHERE   T1.ID IN (SELECT T2.ID FROM dbo.T2);

SELECT  T1.*
FROM    dbo.T1
        INNER JOIN dbo.T2
            ON T1.ID = T2.ID;

总而言之,这两个查询不会总是产生相同的结果,它们也不会总是有相同的计划。这实际上取决于您的索引和数据/查询的宽度。

【讨论】:

    【解决方案2】:

    作为一个非常普遍的规则,JOIN 几乎总是比 SUB-QUERY 执行得更好,但也有例外。

    如果您要使用子查询,EXIST 子句在大多数用例中通常比 IN 执行得更好。

    对于测试用例,您可以查看site

    你应该遵循以下规则...

    1. 如果您需要来自多个表的数据,那么您可以随时使用 join。

    2. 如果您需要多个查询,并且每个子查询提供查询中涉及的表的一个子集,则可以使用子查询。

    3. 如果查询需要 NOT EXISTS 条件,那么您必须使用子查询,因为 NOT EXISTS 仅在子查询中运行;同样的原则也适用于 EXISTS 条件。

    4. PROCEDURE SQL 查询优化器将一些子查询更改为联接,联接通常处理起来效率更高。

    【讨论】:

    • JOIN 几乎总是比 SUB-QUERY 执行得更好。这对 MySQL 来说是正确的,因为 MySQL 将子查询视为临时表,并且不能将谓词推送到它认为合适的外部查询,但是 SQL Server 可以做到这一点,因此它没有真正依赖的一揽子规则。
    • @GarethD 我完全同意你的观点,但我不是在谈论会提供更少数据的查询,让我们想想一个给我 1,00,000 个值的子查询,然后加入肯定会表现得更好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-19
    • 2012-03-03
    相关资源
    最近更新 更多