【问题标题】:SQL Query excuting very slow: Need OptimizationSQL 查询执行速度很慢:需要优化
【发布时间】:2021-03-06 21:22:49
【问题描述】:

以下执行速度非常慢,需要很长时间才能执行。即使结果集为空,也需要大约 280 秒。查询中有一些 case 语句。对优化查询的一些帮助将不胜感激。

执行计划: 该计划取决于日期变量输入,日期范围的字段将在 where 子句中更改。 eg: 如果date = '1' 则根据a.created_date 查询日期范围,如果date = '2' 则根据t.active_datetime 查询日期范围

SQL 查询:

SELECT  @n:=@n+1 No,  a.name customer_name, a.id_number AS customer_id, a.email AS email_address, CONCAT(a.mobile_country_code, '-', a.mobile_number) AS contact_no,
t.status AS status, a.created_date AS registration_date,  a.account_type, a.account_id AS account_no, c.wallet_id AS wallet_account_no, t.old_serial_no AS r_id,
t.active_datetime AS activation_date, v.number AS registration_no,  v.class AS lass,  (CASE WHEN t.is_free = true THEN 'Yes'  ELSE 'No'  END ) AS replacement,
a.reg_source AS channel, (CASE WHEN a.reg_source = 'ADMIN' THEN t.last_modified_by  ELSE 'SYSTEM'  END )  AS activated_by, t.replacement_date AS replacement_date, 
t.new_serial_no AS new_r_id, d.description AS reason, t.terminated_datetime AS tag_termination_date
FROM abc a 
LEFT JOIN def b ON (b.id = a.id) 
LEFT JOIN ghi c ON (c.id = b.id),  tags t
LEFT JOIN jkl v ON (v.id = t.id)
LEFT JOIN mno d ON (d.code = t.reason_code),
(SELECT @n:= 0) AS n , (SELECT @date := '3') AS date
WHERE
a.account_type IN ( 'PRIVATE') AND  a.account_status IN ( 'ACTIVE') AND t.status IN ('ACTIVE') AND
a.reg_source IN ('ADMIN') AND   
CASE 
WHEN @date = '1' THEN a.created_date BETWEEN '2020-11-24'  AND '2020-11-24'
WHEN @date = '2' THEN t.active_datetime BETWEEN '2020-11-24'  AND '2020-11-24'
WHEN @date = '3' THEN t.replacement_date BETWEEN '2020-11-24'  AND '2020-11-24'
WHEN @date = '4' THEN t.terminated_datetime BETWEEN '2020-11-24'  AND '2020-11-24'  
END ;

【问题讨论】:

  • 您好 - 请提供此查询的执行计划
  • @NickW 感谢您的回复。该计划取决于日期变量输入,日期范围的字段将在 where 子句中更改。 eg:如果date = '1' 则根据a.created_date 查询日期范围,如果date = '2' 则根据t.active_datetime 查询日期范围
  • 好的,那么无论日期值如何,还是仅针对特定日期值,查询都很慢?如果您提供最慢日期值的解释计划,那么我们可以从它开始
  • 它总是执行缓慢。即使没有满足 where 子句的记录也需要很长时间。所以,我怀疑这可能是由于这些案例陈述。
  • 你没有给我们足够的信息来帮助你很好。 Please read this,然后edit您的问题,为我们提供更多信息。

标签: mysql sql datetime mysql-workbench query-optimization


【解决方案1】:

尝试添加索引以帮助加快搜索速度。

CREATE INDEX abc_for_big_query
          ON abc (account_type, account_status, reg_source, created_date);

CREATE INDEX tags_for_big_query_active ON tags (status, active_datetime);
CREATE INDEX tags_for_big_query_replacement ON tags (status, replacement_date );
CREATE INDEX tags_for_big_query_terminated ON tags (status, terminated_datetime );

这些索引将允许查询规划器使用index range scans 来执行搜索操作。它们比全表扫描更有效。

当您优化此查询时,请将其视为四个完全不同的查询,每个查询对应您的 @date 变量的值。为什么?搜索条件差异很大。

如果您绝对需要最佳性能,您可能需要将其重写为四个不同的查询。但是最近的 MySQL 查询计划器可能允许您保留这种四向查询。

注释

  • 确保您的日期数据类型是 DATE、DATETIME 或 TIMESTAMP。如果您将日期存储在文本字符串中,您将很难获得良好的性能。

  • 你有这样的 where 子句: a.created_date BETWEEN '2020-11-24' AND '2020-11-24'

    这实际上意味着a.created_date = '2020-11-24 00:00:00'。为什么?因为常量日期2020-11-24 实际上扩展为2020-11-24 00:00:00。而val BETWEEN x and x 表示val = x

    如果您想随时在2020-11-24 上使用created_date 的所有内容,请使用此

     WHERE a.created_date >= '2020-11-24'
       AND a.created_date <  '2020-11-24' + INTERVAL 1 DAY
    

    这仍将使用我建议的索引。

【讨论】:

    【解决方案2】:
    @n:=@n+1
    

    在未来的版本中,@variables 的使用将被禁止。如果这是ROW_NUMBER,那么该函数可能会提供您所需要的。

    你好像没用b;摆脱它。

    如果需要“右”表中的行,请不要使用LEFT

    这可能是最大的速度杀手:

    , tags t
    

    不要混用 JOIN,。确保每个JOIN 都有一个ON 子句。

    构造查询而不是像使用@date 那样使其动态化。这可以提供显着的加速。之后,添加这些索引:

    a: INDEX(account_type, account_status, reg_source, created_date)
    
    t: INDEX(status, active_datetime),
    t: INDEX(status, replacement_date),
    t: INDEX(status, terminated_datetime)
    

    【讨论】:

      猜你喜欢
      • 2016-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      相关资源
      最近更新 更多