我应该在 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 查询转换为高效的查询。
作为一个简单的例子,考虑这两个查询(假设 dt
是 t
中的 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.branchNo
和 b.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 中获得最佳性能。所以,这个责任最终还是落在了程序员身上。
在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 查询转换为高效的查询。
作为一个简单的例子,考虑这两个查询(假设 dt
是 t
中的 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.branchNo
和 b.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 中获得最佳性能。所以,这个责任最终还是落在了程序员身上。