Mysql WHERE谓词和SQL优化器的顺序

Mysql WHERE谓词和SQL优化器的顺序,mysql,sql,sql-order-by,query-optimization,where,Mysql,Sql,Sql Order By,Query Optimization,Where,当使用各种where子句编写SQL查询时,我只使用MySQL和sqlite,我通常怀疑是否会对查询子句进行重新排序,将最好的子句放在第一位,这些子句将删除更多的行,而其他修饰子句稍后将几乎不会改变输出。换句话说,我怀疑我是否真的会通过重新排序子句来帮助优化器更快地运行,特别是在有索引的情况下,或者这可能是另一种过早优化的情况。优化器通常比我聪明 例如: select address.* from address inner join user on a

当使用各种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通常不为null,那么该检查将为90%的true,并且如果遵守查询顺序,那么将有许多虚拟检查,可以通过在前面放置国家/地区检查来避免这些检查


我应该处理吗?换句话说,where子句的顺序是否重要?

答案肯定是可能的。 优化器的方法很神秘

下面是一个基于被零除引起的异常的演示

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成功

但是,对于Oracle和Teradata,以下查询确实失败:

我们学到了什么? 有些优化器似乎尊重谓词的顺序,或者至少以某种方式尊重谓词的顺序,有些优化器似乎根据其估计成本对谓词进行重新排序,例如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

答案肯定是可能的。 优化器的方法很神秘

下面是一个基于被零除引起的异常的演示

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成功

但是,对于Oracle和Teradata,以下查询确实失败:

我们学到了什么? 有些优化器似乎尊重谓词的顺序,或者至少以某种方式尊重谓词的顺序,有些优化器似乎根据其估计成本对谓词进行重新排序,例如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

mysql优化器似乎有很好的文档记录,您可以在官方文档中找到许多有趣的注意事项


尤其是考虑到一个非常简单的事实。。。。sql不是一种过程语言,而是一种声明性语言。。这意味着写部件的顺序并不重要,重要的是声明了哪些元素。这一点在mysql优化文档中表现得很明显,其中重点只关注查询的组件以及optmizer如何在内部组件中转换它们

mysql优化器似乎有很好的文档记录,您可以在官方文档中找到许多有趣的注意事项


尤其是考虑到一个非常简单的事实。。。。sql不是一种过程语言,而是一种声明性语言。。这意味着写部件的顺序并不重要,重要的是声明了哪些元素。这一点在mysql优化的文档中很明显,其中重点只关注查询的组件,以及optmizer如何在内部组件中转换它们。顺序基本上是不相关的

在MySQL中,其中。。。还有

优化器将首先查找哪个部分可以使用索引。如果一个可以,一个不能,优化器将使用索引;顺序变得无关紧要了 如果和的两边都可以使用索引,MySQL通常会选择“更好”的索引。有时会出差错。同样,顺序被忽略。 如果任何一方都不能使用索引,则从左到右进行计算。但是获取行是执行查询的主要工作,因此如果AND的一端比另一端稍慢, 你可能不会注意到。当然,如果一边睡觉,你会注意到的。 除了语法错误之外,示例查询中还有另一个问题:优化器将有意识地决定从哪个表开始

如果它决定从user开始,address需要INDEXuser,country按任意顺序排列。 如果它决定以地址开头,用户需要id,国家或地区。 不清楚优化器是否会对NOTNULL测试感到烦恼,即使该列已被索引。
一句话:把时间花在专注上。

顺序基本上是不相关的

在MySQL中,其中。。。还有

优化器将首先查找哪个部分可以使用索引。如果一个可以,一个不能,优化器将使用索引;顺序变得无关紧要了 如果和的两边都可以使用索引,MySQL通常会选择“更好”的索引。有时会出差错。同样,顺序被忽略。 如果任何一方都不能使用索引,则从左到右进行计算。但是获取行是执行查询的主要工作,因此如果AND的一端比另一端稍慢,您可能不会注意到。当然,如果一边睡觉,你会注意到的。 除了语法错误之外,示例查询中还有另一个问题:优化器将有意识地决定从哪个表开始

如果它决定从user开始,address需要INDEXuser,country按任意顺序排列。 如果它决定以地址开头,用户需要id,国家或地区。 不清楚优化器是否会对NOTNULL测试感到烦恼,即使该列已被索引。
一句话:把时间花在你正在使用的数据库上。

。。。因为你的问题不是dbindependent@scaisEdge在结尾添加了一个音符。@DuduMarkovitz很难听到。为什么听起来这么糟糕?我的英语不太好,我很难知道我的问题听起来怎么样。@Peregring lk,你的英语很好,但问题太离题了。它应该像字典里的定义。如果还没有从主题开始,那么主要思想应该从第一行就清楚了。不要讲故事。从主要思想开始,然后使用简单明了的示例深入研究。@Peregring lkq,检查关于MySQL的更新答案,但是请仔细阅读上一节末尾的内容,您使用的是哪个数据库。。。因为你的问题不是dbindependent@scaisEdge在结尾添加了一个音符。@DuduMarkovitz很难听到。为什么听起来这么糟糕?我的英语不太好,我很难知道我的问题听起来怎么样。@Peregring lk,你的英语很好,但问题太离题了。它应该像字典里的定义。如果还没有从主题开始,那么主要思想应该从第一行就清楚了。不要讲故事。从主要思想开始,然后使用简单明了的示例进行深入研究。@Peregring lkq,检查关于MySQL的更新答案,不过请仔细阅读上一节末尾的内容