我应该在 MySQL 中处理 SQL 查询优化吗

Should I take care of SQL query optimisation in MySQL

在MySQL DBMS 中,程序员在编写SQL 时是否应该注意查询优化(如选择最佳关系代数查询)?或者是 DBMS 的责任。

进一步解释我的意思。在这个例子中: SELECT * FROM Staff s, Branch b WHERE s.branchNo = b.branchNo AND (s.position = 'Manager' AND b.city = 'London')

MySQL 的查询优化器是否有效地决定如何分配谓词的括号(WHERE 子句)? (例如,取决于每个表的大小,或来自系统统计信息的任何信息)

这是程序员的责任;此 "responsibility" 无法传输到 DBMS。

尽管 MySQL 查询优化器可能看起来很神秘和神奇,但它只是一个计算机程序。它只能做它被编程要做的事情。它不会调用任何 "magic" 将低效的 SQL 查询转换为高效的查询。

作为一个简单的例子,考虑这两个查询(假设 dtt 中的 DATE、DATETIME 或 TIMESTAMP 列):

一个:

SELECT t.foo
  FROM t 
 WHERE t.dt >= '2015-01-05'
   AND t.dt <  '2015-01-05' + INTERVAL 1 DAY

两个:

SELECT t.foo
  FROM t 
 WHERE DATE(t.dt) = '2015-01-05'

这些查询指定了相同的结果。对于这些查询之一,MySQL 优化器可以选择使用索引范围扫描操作。另一个不行。

程序员有 "responsibility" 提供 SQL 允许 DBMS 有效利用资源的文本。


考虑另一个简单的例子:

 SELECT t.foo
   FROM t
  WHERE t.foo = 'bar'

对比

 SELECT s.foo
   FROM ( SELECT t.* FROM t ) s
  WHERE s.foo = 'bar'

对比

 SELECT t.foo
   FROM t
  HAVING t.foo = 'bar'

这三个查询指定了相同的结果,但是如果我们查看 EXPLAIN 输出,我们会发现我们没有得到相同的查询计划。


底线:如果我们要在 "programmer" 或 "query optimizer" 之间进行选择,分配 "responsibility" 以有效利用资源...查询优化器不能胜任该任务的简单示例。它只能做它被编程要做的事情。所以,如果非要选择的话,最终的责任在程序员。


跟进

问: 在本例中:

SELECT * FROM Staff s, Branch b WHERE s.branchNo = b.branchNo 
AND (s.position = 'Manager' AND b.city = 'London') 

MySQL 的查询优化器是否有效地决定如何分配谓词的括号(WHERE 子句)? (例如,取决于每个 table 的大小,或来自系统统计信息的任何信息)?

A: 对于查询优化器来说,谓词就是谓词。谓词周围多余的括号不会混淆优化器。 (您示例中的括号将被丢弃,它们不会更改查询计划。

感谢使用 table 别名。 (这使得查询和 EXPLAIN 输出都更短,更易于阅读。)

但放弃连接操作的老式逗号语法。使用 JOIN 关键字代替逗号。并将连接谓词移至 ON 子句。此外,指定您需要的最少列集 returned;不要 return 使用不需要的 * 和 return 列。在这个例子中,s.branchNob.branchNo 都不需要 return,其中一个可以省略,并使结果集更小。 (指定要 returned 的列还可以让 DBA 为覆盖索引做出有效的选择。)

确保您有适当的索引,并查看 EXPLAIN 输出以了解 MySQL 将要执行的操作。 (更好的是,使用 EXPLAIN EXTENDED 和 SHOW WARNINGS,以更好地了解 MySQL 对您的语句做了什么)

SELECT s.branchNo
     , s.position
     , b.city
  FROM Staff s
  JOIN Branch b
    ON b.branchNo = s.branchNo
 WHERE s.position = 'Manager'
   AND b.city = 'London'

作为获得最佳性能的第一步,我们需要一个索引,该索引具有在 WHERE 子句中的一个等式谓词中引用的前导列(如果这将结果集限制为小于 10% 或 20 table 中行的百分比。例如:

... ON Branch (city)
... ON Staff (branchNo, position)

如果我们没有 suitable 索引,那么 MySQL 将求助于嵌套循环扫描。我们不会注意到小集上的任何性能问题。但在更大的集合上,这些操作将变得低效到足以吃掉我们的午餐。

不幸的是,优化器不会自动创建最合适的索引。确保 suitable 索引可用是程序员的责任。

InnoDB 存储引擎使统计数据保持最新,它在这方面做得很好。在 MyISAM tables 上执行 ANALYZE TABLE 将确保优化器有合理的可用统计信息。

总而言之:我们不能只向优化器抛出一些 SQL 文本并期望我们将从 MySQL 中获得最佳性能。所以,这个责任最终还是落在了程序员身上。