WHERE 谓词的顺序和 SQL 优化器
Posted
技术标签:
【中文标题】WHERE 谓词的顺序和 SQL 优化器【英文标题】:Order of WHERE predicates and the SQL optimizer 【发布时间】:2016-11-19 20:28:45 【问题描述】:在编写带有各种where
子句的 SQL 查询时(我只使用 mysql 和 sqlite),我通常对重新排序查询子句以放置首先是“最好的”(将删除更多行的那些),然后是其他“修饰”子句(几乎不会改变输出)。换句话说,我怀疑我是否真的会通过重新排序子句来帮助优化器更快地运行(特别是当有索引在起作用时),或者它是否可能是另一种过早优化的情况。优化人员通常比我聪明。
例如:
select address.* from address inner join
user on address.user = user.id
where address.zip is not null and address.country == user.country
如果我们知道address.zip
通常不为空,则该检查将有 90% 为真,并且如果查询顺序得到遵守,则会有很多虚拟检查,可以通过放置 country
来避免检查之前。
我应该照顾它吗?换句话说,where
子句的顺序是否重要?
【问题讨论】:
您使用的是哪个数据库? ...因为您的问题不是独立于数据库的 @scaisEdge 在末尾添加了注释。 @DuduMarkovitz 很难听到。为什么听起来那么糟糕? (我的英语不太好,我很难知道我的问题听起来如何)。 @Peregring-lk,你的英语很好,但问题太模糊了。它应该像字典定义一样。如果主题中还没有,那么第一行的主要思想应该很清楚。不要讲故事。从主要思想开始,然后使用简单明了的示例进行深入研究。 @Peregring-lkq,查看有关 MySQL 的更新答案,但请仔细阅读上一节的末尾 【参考方案1】:mysql 优化器似乎有据可查,您可以在官方文档中找到许多有趣的注意事项..http://dev.mysql.com/doc/refman/5.7/en/where-optimizations.html
特别要考虑一个非常简单的事实......已编写,但重要的是仅声明了哪些元素的事实。这在关于 mysql 优化的文档中很明显,其中重点仅放在查询的组件以及它们如何通过 optmizer 在内部组件中进行转换
【讨论】:
【参考方案2】:顺序几乎无关紧要。
在 MySQL 中,使用WHERE ... AND ...
,
AND
的两边都可以使用索引,MySQL通常会选择“更好”的那个。 (有时它会出错。)同样,订单被忽略了。
如果双方都不能使用索引,它会从左到右进行评估。但是...获取行是执行查询的大部分工作,因此如果AND
的一侧比另一侧慢一点,您可能不会注意到。 (当然,如果一侧是SLEEP(3)
,你会注意到的。)
您的示例查询中还有另一个问题(除了语法错误):优化器将有意识地决定从哪个表开始。
如果它决定以user
开头,address
需要INDEX(user, country)
以任一顺序。
如果它决定以address
开头,则user
需要(id, country)
的任一顺序。
尚不清楚优化器是否会打扰 NOT NULL
测试,即使该列已编入索引。
底线:花时间专注于optimal indexes。
【讨论】:
【参考方案3】:答案肯定是可能的。 神秘的是优化器的方式。
这里是一个基于被零除引起的异常的演示。
create table t (i int);
insert into t (i) values (0);
Oracle、SQL Server、Postgres 和 Teradata 的以下查询成功(我们现在将跳过版本信息):
select 1 from t where i < 1 or 1/i < 1;
SQL Server 和 Postgres 的以下查询失败,但 Oracle 和 Teradata
的查询成功select 1 from t where 1/i < 1 or i < 1;
但是,对于 Oracle 和 Teradata,以下查询确实会失败:
select 1 from t where 1/i < 1 or i/1 < 1;
我们学到了什么?
一些优化器似乎尊重谓词的顺序(或至少以某种方式),而另一些优化器似乎按其估计成本重新排序谓词(例如,1/i < 1
比 i < 1
更昂贵,但不是 i/1 < 1
)。
对于那些尊重谓词顺序的人,我们可能可以通过将轻等待谓词放在 OR 运算符和经常错误的谓词放在 AND 运算符来提高性能。
话虽如此,由于数据库不能保证保留谓词的顺序,即使其中一些目前似乎这样做,你绝对不能指望它。
MySQL 5.7.11
此查询立即返回:
select 1 from t where i < 1 or sleep(3);
此查询在 3 秒后返回:
select 1 from t where sleep(3) or i < 1
【讨论】:
以上是关于WHERE 谓词的顺序和 SQL 优化器的主要内容,如果未能解决你的问题,请参考以下文章