MySQL查询需要20+秒?

2lpgd968  于 2023-04-29  发布在  Mysql
关注(0)|答案(1)|浏览(127)

我收集了诊断结果,但我不确定为什么会这样。我没有看到任何大的锁时间,或者大量的子查询被意外运行。
查询:

SELECT message, level, logged_at FROM application_logs
 WHERE application_id = 5 AND
       message NOT LIKE '(build)%' AND
       logged_at >= ( 
           SELECT launched_at 
           FROM application_sessions 
           WHERE application_id = 5 
           ORDER BY id DESC LIMIT 1
        ) 
        ORDER BY id DESC LIMIT 500;

我对每个连接到站点的用户运行此查询1次。它目前以大约6/秒的速度运行,并且需要很长时间,这是一个大问题。
application_logs约为2。500万行和application_sessions约20 k行。我可能应该清除application_logs〈7天或什么。
解释:它还在运行,裸露着
慢查询日志:

SELECT message, level, logged_at 
 FROM application_logs 
 WHERE application_id = 9 AND message NOT LIKE '(build)%' 
 AND logged_at >= (
   SELECT launched_at 
   FROM application_sessions 
   WHERE application_id = 9 
   ORDER BY id DESC LIMIT 1
   ) 
 ORDER BY id DESC LIMIT 100;

用户@Host:remote[remote] @ [**************] Thread_id:14180方案:****QC_hit:无查询时间(_T):21.056101锁定时间:0.000102行_已发送:19行_已检查:233153 Rows_effected:0字节(_sent):3421

SET timestamp=1681832466;
SELECT message, level, logged_at 
FROM application_logs 
WHERE application_id = 9 AND message NOT LIKE '(build)%' 
AND logged_at >= (
    SELECT launched_at 
    FROM application_sessions 
    WHERE application_id = 9 
    ORDER BY id DESC LIMIT 1
) ORDER BY id DESC 
LIMIT 100;
ttcibm8c

ttcibm8c1#

application_logs表上的查询如下所示,其中WHERE子句重新排序。在查询中编写的子句的顺序对性能没有影响;我重新安排了它们,只是为了帮助解释事情。

SELECT message, level, logged_at 
  FROM application_logs 
 WHERE application_id = 9           -- equality matches first
   AND logged_at >= something       -- a single range match second
   AND message NOT LIKE '(build)%'  -- miscellaneous matches third
 ORDER BY id DESC                   -- ordering
 LIMIT 100

您可以在该表上使用multicolumn覆盖索引来加速此查询。

ALTER TABLE application_logs CREATE INDEX app_logged_message_id
        (application_id, logged_at, message, id DESC);

使用BTREE索引类似于访问表中行的排序列表。您的查询使用此索引,如下所示。
1.它使用所需的application_id和大于所需起始点的第一个logged_at值(来自子查询)随机访问第一行的索引。
1.然后,它按顺序访问 index(而不是 table),查找与message NOT LIKE子句匹配的行。
1.它按您想要的顺序取出id值,并在达到限制时停止扫描。
试试看,可能会有帮助。
通过类似的逻辑,您的子查询可以从这个索引中受益。

ALTER TABLE application_sessions CREATE INDEX app_id_launched
        (application_id, id DESC, launched_at);

服务器可以随机访问所需行的索引,并检索该行的launched_at列,非常快。
要获得理解这类事情所需的信息,请执行prefix your query with EXPLAIN。然后examine EXPLAIN输出。
Read this for a more thorough explanation

相关问题