比较这两个查询.将筛选器放在联接条件或WHERE子句中更快吗.我一直觉得它在加入标准上更快,因为它会在最短的时间内减少结果集,但我不确定.

我将构建一些测试来查看,但我还想了解哪些测试更清晰易读.

Query 1

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
INNER JOIN  TableB b
        ON  x.TableBID = b.ID
WHERE       a.ID = 1            /* <-- Filter here? */

Query 2

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
        AND a.ID = 1            /* <-- Or filter here? */
INNER JOIN  TableB b
        ON  x.TableBID = b.ID

EDIT

我进行了一些测试,结果表明它实际上非常接近,但WHERE子句实际上稍微快一点!=)

我完全同意在WHERE条款上应用过滤器更有意义,我只是好奇它对性能的影响.

ELAPSED TIME WHERE CRITERIA: 143016 ms
ELAPSED TIME JOIN CRITERIA: 143256 ms

TEST

SET NOCOUNT ON;

DECLARE @num    INT,
        @iter   INT

SELECT  @num    = 1000, -- Number of records in TableA and TableB, the cross table is populated with a CROSS JOIN from A to B
        @iter   = 1000  -- Number of select iterations to perform

DECLARE @a TABLE (
        id INT
)

DECLARE @b TABLE (
        id INT
)

DECLARE @x TABLE (
        aid INT,
        bid INT
)

DECLARE @num_curr INT
SELECT  @num_curr = 1
        
WHILE (@num_curr <= @num)
BEGIN
    INSERT @a (id) SELECT @num_curr
    INSERT @b (id) SELECT @num_curr
    
    SELECT @num_curr = @num_curr + 1
END

INSERT      @x (aid, bid)
SELECT      a.id,
            b.id
FROM        @a a
CROSS JOIN  @b b

/*
    TEST
*/
DECLARE @begin_where    DATETIME,
        @end_where      DATETIME,
        @count_where    INT,
        @begin_join     DATETIME,
        @end_join       DATETIME,
        @count_join     INT,
        @curr           INT,
        @aid            INT

DECLARE @temp TABLE (
        curr    INT,
        aid     INT,
        bid     INT
)

DELETE FROM @temp

SELECT  @curr   = 0,
        @aid    = 50

SELECT  @begin_where = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
    INNER JOIN  @b b
            ON  x.bid = b.id
    WHERE       a.id = @aid
        
    SELECT @curr = @curr + 1
END
SELECT  @end_where = CURRENT_TIMESTAMP

SELECT  @count_where = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @curr = 0
SELECT  @begin_join = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
            AND a.id = @aid
    INNER JOIN  @b b
            ON  x.bid = b.id
    
    SELECT @curr = @curr + 1
END
SELECT  @end_join = CURRENT_TIMESTAMP

SELECT  @count_join = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @count_where AS count_where,
        @count_join AS count_join,
        DATEDIFF(millisecond, @begin_where, @end_where) AS elapsed_where,
        DATEDIFF(millisecond, @begin_join, @end_join) AS elapsed_join

推荐答案

就性能而言,它们是相同的(并产生相同的计划)

从逻辑上讲,如果你用LEFT JOIN替换INNER JOIN,你应该做出仍然有意义的操作.

在你的情况下,这看起来是这样的:

SELECT  *
FROM    TableA a
LEFT JOIN
        TableXRef x
ON      x.TableAID = a.ID
        AND a.ID = 1
LEFT JOIN
        TableB b
ON      x.TableBID = b.ID

或者这个:

SELECT  *
FROM    TableA a
LEFT JOIN
        TableXRef x
ON      x.TableAID = a.ID
LEFT JOIN
        TableB b
ON      b.id = x.TableBID
WHERE   a.id = 1

前一个查询不会返回除1之外的a.id的任何实际匹配,因此后一个语法(带WHERE)在逻辑上更加一致.

Sql相关问答推荐

带有双引号的json在Presto中是否有区别对待?

Snowflake SQL比较克隆x原始计数

更新在两个或多个面中具有交点的面

计算分段的总权重

使用占位符向SQL INSERT查询添加 case

Lag()函数的差异:R与SQL(将R代码转换为SQL)

当一个视图在Postgres中失效时?

将重复的值更新为下一个空闲数字

将所有XML文件导入到SQL Server中

从包含PostgreSQL中的JSON值的列中提取列表或目录

如何根据行状态设置正确的标志

在UNION查询中查找MIN

将用户授予另一个用户不授予权限

SQL JSON_QUERY 使用列中的值构造 json 路径并接收错误

MySQL中的递归查询邻接表深度优先?

如何 for each id创建长度等于id长度的不同日期序列?

PostgreSQL中如何提取以特定字符开头的字符串中的所有单词?

如何在插入时将字符串'03-January-2023'转换为日期时间

根据潜在空值的条件对记录进行计数

计算 PostgreSQL 中的平均会话长度