组织`where`以加快速度

时间:2015-04-10 17:16:54

标签: mysql

重要的事情

是否可以确定WHERE条件的最佳顺序以使其更快?例如,我有一个包含6个条件的查询。一些简单的,其他的子查询或函数。我的想法是对查询进行概要分析,以确定条件true的常见程度以及运行成本。

阅读示例

例如,我有它:

WHERE
    table.ageMin >= :ageFilter AND       #1 age-more-than
    table.ageMax <= :ageFilter AND       #2 age-less-than
    YEAR(table.date) >= :dateFilter AND  #3 year
    (SELECT ...) = TRUE AND              #4 first-query
    (SELECT ...) = FALSE AND             #5 second-query
    USER_FUNCTION(table.tag, :tagFilter) #6 user-function

所以,让我们说,在一个月内,我们有:

  1. 95%的情况都是如此;
  2. 69%的时间都是如此;
  3. 15%的情况都是如此;
  4. 97%的时间都是如此;
  5. 50%的时间都是如此;
  6. 在99%的时间都是如此;
  7. 考虑到(伪ms值):

    1. 是一个简单的条件,查询成本为0.005毫秒;
    2. 是一个简单的条件,查询成本为0.005毫秒;
    3. 使用MySQL YEAR()并花费0.030ms进行查询;
    4. 使用子查询和费用0.140ms进行查询;
    5. 使用子查询并花费0.260毫秒进行查询;
    6. 使用用户功能和成本0.450毫秒进行查询;
    7. 所以,我可能会这么想:

      1. #3将在85%的时间内失败,查询费用仅为0.030毫秒;
      2. #2将在31%的时间内失败,查询费用仅为0.005毫秒;
      3. #1将失败5%,但查询费用仅为0.005毫米;
      4. #5费用超过#4 + 0.120毫秒,但会在50%的时间内失败;
      5. #4花费0.140毫秒,但只失败了3%;
      6. #6花费0.450毫秒,但只失1%;
      7. 所以我的WHERE命令就像:

        WHERE
            YEAR(table.date) >= :dateFilter AND  #3 up, up
            table.ageMax <= :ageFilter AND       #2 maintained
            table.ageMin >= :ageFilter AND       #1 down down
            (SELECT ...) = FALSE AND             #5 up
            (SELECT ...) = TRUE AND              #4 down
            USER_FUNCTION(table.tag, :tagFilter) #6 maintained
        

        因此,如果我在一个月内有1.000.000个查询,那么在第一个例子中,我将会:

        1. 5%将在年龄上失败 - 超过,花费5.000秒,休息950.000;
        2. 31%将失败,年龄小于,花费4.750秒,休息655.500;
        3. 85%将在一年内失败,花费19.665秒,休息98.325;
        4. 3%将在第一个子查询中失败,花费13.765秒,休息95.375;
        5. 50%将在第二个子查询中失败,花费24.797秒,休息47.687;
        6. 1%将在用户功能中失败,花费21.459秒,休息47.210;
        7. 因此,在100万个查询中,只有47.210是真的。并且它花了89.436秒来处理所有查询很长一个月。

          在对我的WHERE重新排序之后,它将成为:

          1. 85%将在一年内失败,花费30.000秒,休息150.000;
          2. 31%将失败的年龄小于,花费750秒,休息103.500;
          3. 5%将在年龄上失败 - 超过,花费517秒,休息98.325;
          4. 50%将在第二个子查询中失败,花费25.564秒,休息49.165;
          5. 3%将在第一个子查询中失败,花费6.883秒,休息47.690;
          6. 1%将在用户功能中失败,花费21.460秒,休息47.210;
          7. 因此,在100万次查询中,它花费了85.174,比原始订单少了4.262秒。在这个简单的比较中差异是5%,但我有大约50个条件的表(一些复合,其他没有)。我试图修正顺序,查询从0.500ms减少到0.075ms。

            但是,这是一项艰苦的工作,逐一检查,并确定哪种更常见,成本更低。那么,有一些工具可以使这项工作吗?

4 个答案:

答案 0 :(得分:2)

WHERE子句中的条件顺序无关紧要。 MySQL查询优化器为查询执行了许多类型的changes,以使其尽可能快地运行。

由于子查询,您的查询速度很慢。优化器可以将某些类型的子查询转换为表连接,这种更改可以大大提高运行速度。

我无法建议对您的子查询进行任何改进,因为您没有提供这些改进。

您可以轻松改进条件YEAR(table.date) >= :dateFilter的评估。使用函数(YEAR())可以防止MySQL使用索引。如果您将其更改为比较table.date与一年中的第一天(例如,在2015-01-01中放置2015而不是dateFilter),那么MySQL可以使用索引和速度执行。

当然,如果您为该列创建了索引,MySQL会使用索引。确保列dateageMinageMax上有索引。

EXPLAIN放在查询前面,并根据EXPLAIN output format的文档检查结果,找出查询速度慢的原因以及如何改进查询。

答案 1 :(得分:1)

不,mysql中的优化器并不关心where条件的顺序。它使用统计信息(直方图)来确定应用where语句的顺序(AND使用正确的索引:准备好索引)。如果它真的没有目标,你可以使用一个提示并强制使用某个索引,但是你的查询只针对这一个案例进行了优化,这对于其他案例的性能来说真的是有害的

答案 2 :(得分:1)

MySQL的查询计划程序重新排序由WHERE连接在一起的AND子句,以提出它所猜测的最佳执行计划。

您不能通过弄乱查询中的子句顺序来影响这一点。

一旦你的桌子大部分被填充,你可以使用ANALYZE TABLE来影响它。

您可以通过使用与查询中的列匹配的列创建一个或多个复合索引来影响它。读这个。 http://use-the-index-luke.com/

如果您是基准测试内容,请务必在查询开头编写SELECT SQL_NO_CACHE而不是SELECT。否则,MySQL将满足来自缓存的重复查询并且显得非常快。

答案 3 :(得分:0)

如果我们订购(可能是提示强制)where条件,以便我们从第一个条件中消除最大行数,如果我们从#6条件开始消除99%的行,其余部分条件仅适用于剩余的1%,依此类推。所以我建议从条件中排序条件,以消除以最少的一行结束的最大行数。