【问题标题】:Order of WHERE predicates and the SQL optimizerWHERE 谓词的顺序和 SQL 优化器
【发布时间】:2016-11-19 20:28:45
【问题描述】:

在编写带有各种where 子句的 SQL 查询时(我只使用 MySQLsqlite),我通常对重新排序查询子句以放置首先是“最好的”(将删除更多行的那些),然后是其他“修饰”子句(几乎不会改变输出)。换句话说,我怀疑我是否真的会通过重新排序子句来帮助优化器更快地运行(特别是当有索引在起作用时),或者它是否可能是另一种过早优化的情况。优化人员通常比我聪明。

例如:

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 的更新答案,但请仔细阅读上一节的末尾

标签: mysql sql sql-order-by query-optimization where


【解决方案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、PostgresTeradata 的以下查询成功(我们现在将跳过版本信息):

      select 1 from t where i < 1 or 1/i < 1;
      

      SQL ServerPostgres 的以下查询失败,但 OracleTeradata

      的查询成功
      select 1 from t where 1/i < 1 or i < 1;
      

      但是,对于 OracleTeradata,以下查询确实会失败:

      select 1 from t where 1/i < 1 or i/1 < 1;
      

      我们学到了什么?
      一些优化器似乎尊重谓词的顺序(或至少以某种方式),而另一些优化器似乎按其估计成本重新排序谓词(例如,1/i &lt; 1i &lt; 1 更昂贵,但不是 i/1 &lt; 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
      

      【讨论】:

        猜你喜欢
        • 2021-05-06
        • 1970-01-01
        • 2022-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-13
        • 2016-05-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多