哪个SQL查询更快? 过滤连接标准或Where子句?
比较这两个查询。 将filter放在连接条件或在子句中更快吗? 我一直觉得join标准的速度会更快,因为它会尽可能减less结果集,但是我不确定。
我将要build立一些testing来看,但我也想得到更清晰的阅读意见。
查询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? */
查询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
编辑
我跑了一些testing,结果显示它实际上非常接近,但WHERE
子句实际上稍微快一点! =)
我绝对同意,在WHERE
子句上应用filter更有意义,我只是对性能影响感到好奇。
ELAPSED TIME CRITERIA: 143016 ms
ELAPSED TIME JOIN CRITERIA: 143256 ms
testing
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 @aa CROSS JOIN @bb /* 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 @aa INNER JOIN @xx ON a.id = x.aid INNER JOIN @bb 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 @aa INNER JOIN @xx ON a.id = x.aid AND a.id = @aid INNER JOIN @bb 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
replaceINNER 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编译器将把两者都转换成一个执行计划,在该执行计划中,在连接之下进行过滤(即,如同filterexpression式出现在连接条件中一样)。
外连接是另一回事,因为filter的位置改变了查询的语义。
就这两种方法而言。
- JOIN / ON用于连接表格
- WHERE用于筛选结果
虽然你可以以不同的方式使用它们,但对我来说,这似乎总是一种气味。
在出现问题时处理性能。 那么你可以看看这样的“优化”。
使用任何查询优化器worh一分…他们是相同的。
这个连接的位置不太可能成为决定性能的因素。 我并不十分熟悉tsql的执行计划,但很可能会自动优化类似的计划。
规则#0:运行一些基准,看看! 真正知道哪个更快的唯一方法就是尝试一下。 这些types的基准testing非常容易使用SQL分析器来执行。
另外,检查使用JOIN和WHERE子句编写的查询的执行计划,以查看哪些差异突出。
最后,正如其他人所说,这两个应该由任何像样的优化器,包括SQL Server内置的一个相同的待遇。
它快吗? 试试看看。
哪个更容易阅读? 对我来说,第一个看起来更“正确”,因为移动的条件与join没有任何关系。
我想,第一,因为它使数据更具体的filter。 但是您应该看到执行计划 ,就像任何优化一样,因为在数据大小,服务器硬件等方面可能会有很大的不同。