如何优化此查询并减少其执行时间

时间:2017-05-25 18:57:32

标签: mysql sql performance

我有一个查询:

select      * 
from        `ads_fact` 
inner join  `dim_make`  on  `dim_make`.`make_id` = `ads_fact`.`make_id` 
inner join  `dim_model` on  `dim_model`.`model_id` = `ads_fact`.`model_id` 
inner join  `dim_state` on  `dim_state`.`state_id` = `ads_fact`.`state_id` 
inner join  `dim_source` on `dim_source`.`source_id` = `ads_fact`.`source_id` 
inner join  `dim_fuel_type` on `dim_fuel_type`.`fuel_type_id` = `ads_fact`.`fuel_type_id`
inner join  `dim_body_type` on `dim_body_type`.`body_type_id` = `ads_fact`.`body_type_id` 
where       1=1 
&&          date_time >= DATE_SUB(CURDATE(), INTERVAL 14 DAY) 
&&          ad_status=0 
order by    ad_id DESC 
limit 20 
offset 0

我尝试了一些东西,但它的响应时间仍然超过7秒,任何人都可以帮我优化这个查询。

3 个答案:

答案 0 :(得分:0)

你可以做几件事:

  1. 避免在查询中使用函数 - 在查询之前使用变量,然后在WHERE子句中使用该变量
  2. SET @threshold_date = DATE_SUB(CURDATE(), INTERVAL 14 DAY); SELECT .... ..... WHERE date_time >= @threshold_date

    1. 确保您在相应列上有索引 - 您在其上执行JOIN和WHERE(date_time,ad_status,make_id,model_id,state_id,...)

答案 1 :(得分:0)

优化器可能并没有很好地处理这个问题。假设所有过滤器都来自ads_fact表...首先尝试创建过滤表:

CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS (
  SELECT      * 
  FROM        `ads_fact`
  WHERE       1=1 
  AND         year > 2009 
  AND         date_time >= DATE_SUB(CURDATE(), INTERVAL 14 DAY)
  AND         ad_status=0 
  ORDER BY    ad_id DESC 
  LIMIT 20 
  OFFSET 0
)

然后将其加入其他表:

SELECT      * 
FROM        temp1 
INNER JOIN  `dim_make`  ON `dim_make`.`make_id` = temp1.`make_id` 
INNER JOIN  `dim_model` ON `dim_model`.`model_id` = temp1.`model_id` 
INNER JOIN  `dim_state` ON `dim_state`.`state_id` = temp1.`state_id` 
INNER JOIN  `dim_source` ON `dim_source`.`source_id` = temp1.`source_id` 
INNER JOIN  `dim_fuel_type` ON `dim_fuel_type`.`fuel_type_id` = temp1.`fuel_type_id`
INNER JOIN  `dim_body_type` ON `dim_body_type`.`body_type_id` = temp1.`body_type_id` 

基本上,这将保证优化器对尽可能小的记录集进行所有过滤。然后将过滤后的集合连接回其他表。您当前的查询很可能正在完成所有连接,然后过滤,排序和限制(或者以低效的顺序执行操作,因为它无法提出一个好的计划)。

答案 2 :(得分:0)

dim_makePRIMARY KEY(make_id)吗?我们来看SHOW CREATE TABLE dim_make

ads_factINDEX(status, date_time)吗?我们来看SHOW CREATE TABLE ads_fact

如果ORDER BY date_time DESC可以,那么运行速度会快得多(在添加上述索引之后)。

如果您担心date_time中的重复值,请执行

ORDER BY date_time DESC, ad_id DESC

如果在修复了"分页"的第一个页面后,您发现后续页面太慢,请参阅why pagination via OFFSET can be bad上的文章。

另一个问题......你正在接近"过度规范化":

  • state也可以是2字节CHAR(2) CHARACTER SET ascii,而不是4字节INT
  • fuel_type可以是1字节ENUM('unk', 'gas', 'diesel', 'electric', 'hybrid', 'natural gas', 'hydrogen'),也可以是1字节CHAR(1) CHARACTER SET ascii,其值类似于' G',' D&#39 ;,' H'等

(我不认为JOINs是您的主要性能问题;我认为索引是。)