一尘不染

SQL Server Join/where 处理顺序

sql-server

我们需要第一个表的结果(当连接其他表时)在连接(这个问题的内部连接)之前尽可能小,以使我们的查询更快一点。

例如,应该这样:

SELECT *
FROM   ( SELECT * FROM table1 WHERE col = @val ) t
INNER JOIN table2 ON col = col2

比以下更好/更快:

SELECT *
FROM table1
INNER JOIN table2 ON col = col2
WHERE table1.col = @val

我的理论如下(这可能不是正确的实现,我试图从我读过的 SQL Server 2008 内部书籍(MSFT Press)中记住):

  1. 查询处理器首先获取左表(table1)
  2. 在过滤掉必要的行(如果适用)之前加入第二个表(table2)并形成笛卡尔积
  3. 然后用最后的 SEELCT 语句执行 WHERE、ORDER BY、GROUP BY、HAVING 子句。

因此,如果在上面的语句 #1 中,表较小,则 SQL 引擎在形成笛卡尔积时要做的工作较少。然后,当您到达 where 语句时,您将在内存中从中筛选出一个缩减的结果集。

我可能离题太远了,这是不真实的。就像我说的,这是一个理论。

你的意见?

注意:我只是刚刚想到这个问题,还没有机会自己进行任何测试。

注 2:标记为 SQL Server,因为我对 MySql 等的实现一无所知。无论如何请随时回答/评论


阅读 79

收藏
2022-11-16

共1个答案

一尘不染

查询的逻辑处理在MSDN上(由 Microsoft SQL Server 团队编写,而不是第 3 方)

1. FROM
2. ON
3. JOIN
4. WHERE
5. GROUP BY
6. WITH CUBE or WITH ROLLUP
7. HAVING
8. SELECT
9. DISTINCT
10. ORDER BY
11. TOP

一个派生表遵循这个,然后外部查询再次执行它等等

这是合乎逻辑的:不是实际的。不管 SQL Server 实际上是如何做的,这些语义都是字面意思。“实际”由查询优化器 (QO) 确定,您避免使用您提到的中间 Cartesion 产品。

值得一提的是,SQL 是声明式的:您说的是“什么”而不是“如何”,就像您在过程式/命令式编程(Java、.net)中所说的那样。所以说“这发生在那之前”在很多情况下是错误的(例如短路假设或 L-to-R WHERE 顺序)

在您上面的例子中,QO 将生成相同的计划,无论其结构如何,因为它是一个简单的查询。

但是,QO 是基于成本的,对于复杂的查询,可能需要 2 周才能生成理想的计划。所以它确实“足够好”,但实际上并非如此。

因此,您的第一个案例可能有助于优化器找到更好的计划,因为这两个查询的逻辑处理顺序不同。但它可能不会。

我在 SQL Server 2000 上使用了这个技巧,使报告查询的速度提高了 60 倍。随着 QO 逐个改进版本,它会更好地解决这些问题。

2022-11-16