需要帮助提高SQL查询性能

时间:2016-04-21 14:32:04

标签: mysql

这是我的简化历史表结构:

id | property_id | price   | created_at          | updated_at          | deleted_at
1  |      1      |   100   | 2016-04-10 01:00:00 | 2016-04-10 01:00:00 | NULL
2  |      1      |   300   | 2016-04-10 01:00:00 | 2016-04-10 01:00:00 | NULL
3  |      1      |   300   | 2016-04-10 02:00:00 | 2016-04-10 02:00:00 | NULL
4  |      2      |   200   | 2016-04-10 03:00:00 | 2016-04-10 03:00:00 | NULL
1  |      2      |   150   | 2016-04-10 04:00:00 | 2016-04-10 04:00:00 | NULL

我需要:

  1. 我想获取符合特定条件的记录,特别是created_at字段在过去24小时内
  2. 我需要获得紧接在#1
  3. 中记录之前的记录
  4. 进一步过滤结果#1,记录的价格列在记录的历史记录中具有不同的值,而不是-1
  5. 到目前为止,这是我的查询,但有点慢:

    SELECT *
      FROM `history` `t1`
     WHERE `t1`.`created_at` >= '2016-04-13 00:00:00'
       AND `t1`.`created_reason` = 'Scraped'
       AND `t1`.`price` > -1
       AND (SELECT `t2`.`price`
              FROM `history` `t2`
             WHERE `t2`.`property_id` = `t1`.`property_id`
               AND `t2`.`created_at` < `t1`.`created_at`
               AND `t2`.`price` > -1
             ORDER BY DATE(`t2`.`created_at`) DESC
             LIMIT 1
           ) <> `t1`.`price`
     GROUP BY `t1`.`property_ad_id`
    

    有关如何提高绩效的任何建议吗?

1 个答案:

答案 0 :(得分:0)

这里有一些建议。

使用EXPLAIN获取查询执行计划。

正在为从t1返回的每个行执行相关子查询。这可能会大大降低性能。

相关子查询正在对函数的结果执行ORDER BY。这意味着MySQL必须为满足谓词的每一行计算该表达式,然后执行排序操作。 (使用LIMIT 1,MySQL可能不必对整个集合进行完全排序,但它确实需要至少执行一次传递才能获得第一行。)

因为DATE()函数正在消耗时间组件,如果t2中有多行满足其他谓词(早期created_at),相同的最新日期和不同时间,那么它们中的哪一个是不确定的行将首先排序。您可能会从04:00开始排队,而不是从17:00开始排队

建议:引用一个裸列,并确保有适当的索引。

建议:获得&#34;最大值&#34;创建于(有效使用索引)

建议:在前一行的48小时,72小时,一周内,你要在t2后面看一个下限?

建议:确保t1上的外部查询和t2上的子查询都有合适的索引。 (可能那些需要两个不同的索引)

作为第一次改进,一些小调整......

SELECT t1.*
  FROM history t1
 WHERE t1.created_at >= '2016-04-13 00:00:00'
   AND t1.created_reason = 'Scraped'
   AND t1.price > -1
   AND t1.price <> 
       (
         SELECT t2.price
           FROM history t2
          WHERE t2.property_id = t1.property_id
            AND t2.created_at  < t1.created_at
            AND t2.created_at  > t1.created_at + INTERVAL -30 DAY
            AND t2.price > -1
          ORDER BY t2.created_at DESC
          LIMIT 1
       )
 GROUP BY t1.property_ad_id

最合适的指数可能是

... ON history(created_reason,created_at,property_id,price)
... ON history(property_id,created_at,price)

为了优化GROUP BY(避免排序操作),我们也可以考虑尝试使用前导列property_ad_id的索引。这是一个很长的镜头,但可能值得一试,看看EXPLAIN是否显示它正在使用......

... ON history(property_ad_id,created_reason,created_at,property_id,price)