慢速查询日志记录测试期间快速查询

时间:2017-11-14 12:55:52

标签: mysql performance mysql-slow-query-log

我的慢查询日志中包含以下查询时间和检查行的查询:

# Query_time: 26.370100  Lock_time: 0.000213  Rows_sent: 0  Rows_examined: 30976475

如果我将日志中的确切查询复制并粘贴到phpmyadmin并运行它,结果会立即生效,即使对该查询执行EXPLAIN也不会显示索引中的缺陷或结构不良。

据我所知,由于某些原因,一小部分查询无法使用索引,并且在测试期间尝试重现该事件几乎是不可能的。

我应该如何防止这些偶尔出现的慢查询在绝大多数情况下按预期工作?

---编辑#1 ---

我的创建表格是:

CREATE TABLE msgs (
  id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  sender text NOT NULL,
  receiver text NOT NULL,
  cont blob NOT NULL,
  img text NOT NULL,
  orient text NOT NULL,
  d_t datetime NOT NULL,
  convo text NOT NULL,
  u_code text NOT NULL,
  viewed datetime NOT NULL,
  stat int(11) NOT NULL,
  device text NOT NULL,
  addr text NOT NULL,
  PRIMARY KEY (id),
  KEY msg_u_code (`u_code`(24)),
  KEY receiver (`receiver`(24)),
  KEY sender (`sender`(24)),
  KEY img (`img`(28)),
  KEY convo (`convo`(49))
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE usrs (
  id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  usr_name text NOT NULL,
  img text NOT NULL,
  orient text NOT NULL,
  `password` text NOT NULL,
  u_code text NOT NULL,
  d_t datetime NOT NULL,
  stat int(11) NOT NULL,
  device text NOT NULL,
  addr text NOT NULL,
  PRIMARY KEY (id),
  KEY img (`img`(28)),
  KEY usr_code (`u_code`(24))
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

我的慢查询日志条目是:

 # Time: 171115  6:26:37
 # User@Host: xxx[xxx] @ localhost []
 # Thread_id: 25524888  Schema: xxx  QC_hit: No
 # Query_time: 32.423430  Lock_time: 0.000425  Rows_sent: 1  Rows_examined: 30998008
 # Rows_affected: 0
 use xxx;
 SET timestamp=1510723597;
 select msg_cont, msg_u_code, msg_d_t, msg_viewed, usr_u_code, usr_name from
        (select
            msgs.id as msg_id,
            msgs.cont as msg_cont,
            msgs.u_code as msg_u_code,
            msgs.d_t as msg_d_t,
            msgs.viewed as msg_viewed,
            usrs.u_code as usr_u_code,
            usrs.usr_name as usr_name
            from msgs
            left join usrs on msgs.sender = usrs.u_code
    where  msgs.convo = 'aaaaaaaaaabfbaghdgcigfid_aaaaaaaaaabeiaccjfhjfach'
      and  (msgs.sender = 'aaaaaaaaaabfbaghdgcigfid'
              or  msgs.receiver = 'aaaaaaaaaabfbaghdgcigfid'
           )
      and  msgs.stat = '1'
      and  usrs.stat = '1'
      and  usrs.u_code not in('aaaaaaaaaabfaagfbgggiejh',
                              'aaaaaaaaaabfabgbjdfjigbd',
                ...... !!!!![here go 400 more usr_u_codes]!!!!!
                          )
      and  msgs.id > 30997997
        ) a order by msg_id asc;

注意,此查询应包含不在函数中的平均400个元素。

---编辑#2 ---

Explain of the query

2 个答案:

答案 0 :(得分:0)

您可能拥有"查询缓存"打开。它捕获查询及其结果集。当您再次运行完全相同的查询时,它只是回显保存的结果集,而不是重新评估它。

可以通过在语句中添加尽可能少的空格,或者通过说SELECT SQL_NO_CACHE ...来避免质量控制。

为了进一步讨论查询需要查看31M行的原因,让我们看看查询和SHOW CREATE TABLE

查询后

我想首先关注ON msgs.sender = usrs.u_code和"前缀"索引。

根据示例值,似乎senderu_code和其他几列可能总是在一个较小的长度?如果是这样,那么

  • TEXT更改为VARCHAR(nn),其中nn是一些现实限制;
  • 摆脱前缀(例如:KEY sender (sender(24)) - > KEY (sender)

这些更改应使JOIN更有效,从而提高性能。如果这还不够,请回来寻求更多建议。

答案 1 :(得分:0)

虽然我无法解释为什么MySQL偶尔决定不在非常明显且非常常见的查询中使用索引,但解决方案只是强制索引。

在我的特定情况下:

select msg_cont, msg_u_code, msg_d_t, msg_viewed, usr_u_code, usr_name from
        (select
            msgs.id as msg_id,
            msgs.cont as msg_cont,
            msgs.u_code as msg_u_code,
            msgs.d_t as msg_d_t,
            msgs.viewed as msg_viewed,
            usrs.u_code as usr_u_code,
            usrs.usr_name as usr_name
            from msgs FORCE INDEX (convo)
            left join usrs FORCE INDEX (u_code) on msgs.sender = usrs.u_code
    where  msgs.convo = 'aaaaaaaaaabfbaghdgcigfid_aaaaaaaaaabeiaccjfhjfach'
      and  (msgs.sender = 'aaaaaaaaaabfbaghdgcigfid'
              or  msgs.receiver = 'aaaaaaaaaabfbaghdgcigfid'
           )
      and  msgs.stat = '1'
      and  usrs.stat = '1'
      and  usrs.u_code not in('aaaaaaaaaabfaagfbgggiejh',
                              'aaaaaaaaaabfabgbjdfjigbd',
                ...... !!!!![here go 400 more usr_u_codes]!!!!!
                          )
      and  msgs.id > 30997997
        ) a order by msg_id asc;

慢查询日志证明此解决方案有效,因为没有新的慢速条目出现。