在阅读了 Slow SQL query, not sure how to optimize之后,我开始思考查询的一般性能。当然,我们需要第一个表的结果(当其他表被连接时)在连接之前尽可能小(这个问题的内部连接),以使我们的查询更快一点。
例如,应该这样:
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)中记住):
- 查询处理器首先获取左表(table1)
- 加入第二个表 (table2) 并在过滤出必要的行之前形成笛卡尔积(如果适用)
- 然后使用 SEELCT 语句最后执行 WHERE、ORDER BY、GROUP BY、HAVING 子句。
因此,如果在上面的语句#1 中,表更小,则 SQL 引擎在形成笛卡尔积时要做的工作更少。然后,当您到达 where 语句时,您将在内存中筛选出一个缩减的结果集。
我可能离题太远了,这是不真实的。就像我说的,这是一个理论。
你的意见?
注意:我只是想到了这个问题,还没有机会自己进行任何测试。
注2:标记为SQL Server,因为我对MySql等的实现一无所知。请随时回答/评论
查询的逻辑处理在MSDN上(由 Microsoft SQL Server 团队编写,而不是第 3 方)
派生表紧随其后,然后外部查询再次执行等等
这是合乎逻辑的:不是实际的。不管 SQL Server 实际是如何做的,这些语义都是不折不扣的。“实际”由查询优化器(QO)确定,您避免使用您提到的中间 Cartesion 产品。
值得一提的是,SQL 是声明性的:您说“什么”而不是“如何”,就像您对过程/命令式编程(Java、.net)所说的那样。因此,在许多情况下说“这发生在此之前”是错误的(例如假设短路或从左到右的 WHERE 顺序)
在上述情况下,无论 QO 的结构如何,它都会生成相同的计划,因为它是一个简单的查询。
但是,QO 是基于成本的,对于复杂的查询,可能需要 2 周才能生成理想的计划。所以它确实“足够好”,但实际上并非如此。
因此,您的第一个案例可能会帮助优化器找到更好的计划,因为 2 个查询的逻辑处理顺序不同。但它可能不会。
我在 SQL Server 2000 上使用了这个技巧,使报告查询的速度提高了 60 倍。随着 QO 不断改进版本,它会更好地解决这些问题。
而你提到的书:有一些争议
参见SO和后续链接:https ://stackoverflow.com/q/3270338/27535
SQL 查询本质上不是过程式的,连接运算符没有从上到下的处理。示例查询中的表顺序对执行计划没有影响,因为它们在逻辑上是等效的,并且将生成完全相同的计划。
您已经评估了查询优化器在为此查询生成计划时可能考虑的两个选项。影响计划选择的主要因素是所涉及表的统计数据以及与任何候选计划中的操作员选择相关的成本。
一个非常简单的两表连接(例如您的示例)可以满足数百个不同执行计划中的任何一个。优化器通过比较这些计划的成本来决定哪种方式是回答您的查询的最佳方式。
它有时会出错,您可以通过改进索引、更新统计信息和应用提示来帮助它做出更好的选择。在极少数情况下,您可能希望通过使用 FORCE ORDER 提示来强制执行顺序,但应谨慎使用。这是一把敲碎坚果的锤子,优化器通常可以通过提供更好的信息来制定更好的计划。