繁体   English   中英

有时MySQL停止使用正确的索引

[英]Sometimes MySQL stops using right index

我有几次遇到这种情况:快速运行的查询在没有任何更改的情况下在一秒钟内以1000-10_000倍的速度开始工作。 MySQL停止使用适当的索引,而我必须使用FORCE INDEX(..) 查询具有10-300M记录的大表时会发生这种情况。

MySQL:5.6.23(AWS RDS,db.r3.xlarge)

最后一个问题:

table1(175M条记录)

CREATE TABLE `table1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `site_id` int(11) NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `type` varchar(25) DEFAULT NULL,
  ...
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_table1_on_site_id_and_..._and_type_and_...` (`site_id`,`...`,`type`,`...`),
  KEY `index_table1_on_created_at_and_site_id` (`created_at`,`site_id`),
  KEY `index_table1_on_site_id_and_type_and_created_at_and_...` (`site_id`,`type`,`created_at`,`...`) USING BTREE,
  KEY `index_table1_on_site_and_type_and_..._and_created` (`site_id`,`type`,`..._id`,`created_at`),
) ENGINE=InnoDB AUTO_INCREMENT=... DEFAULT CHARSET=utf8

table2(2M条记录)

CREATE TABLE `table2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `table1_id` int(11) NOT NULL,
  ...
  PRIMARY KEY (`id`),
  ...
) ENGINE=InnoDB AUTO_INCREMENT=... DEFAULT CHARSET=utf8

请求:

SELECT  `table1`.* FROM `table1` 
INNER JOIN `table2` ON `table2`.`table1_id` = `table1`.`id` 
WHERE `table1`.`type` IN ('...', '...') 
  AND `table1`.`site_id` = ... 
  AND (table1.created_at >= '...') 
  AND (table1.created_at <= '...')  
ORDER BY `table1`.`id` DESC LIMIT 30 offset 0;

现在是420秒到10-80毫秒了

FORCE INDEX请求:

SELECT  `table1`.* FROM `table1` USE INDEX (`index_table1_on_site_id_and_type_and_created_at_and_...`) 
INNER JOIN `table2` ON `table2`.`table1_id` = `table1`.`id` 
WHERE `table1`.`type` IN ('...', '...') 
  AND `table1`.`site_id` = ... 
  AND (table1.created_at >= '...') 
  AND (table1.created_at <= '...')  
ORDER BY `table1`.`id` DESC LIMIT 30 offset 0;

〜85毫秒

说明:无FORCE

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table1
         type: index
possible_keys: PRIMARY,index_table1_on_site_id_and_..._and_type_and_...,index_table1_on_created_at_and_site_id,index_table1_on_type,index_table1_on_site_id_and_type_and_created_at_and_...,index_table1_on_site_and_type_and_..._and_created
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 9257179
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: table2
         type: eq_ref
possible_keys: ...
          key: ...
      key_len: 4
          ref: db.table1.id
         rows: 1
        Extra: Using index

FORCE

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table1
         type: range
possible_keys: index_table1_on_site_id_and_type_and_created_at_and_...
          key: index_table1_on_site_id_and_type_and_created_at_and_...
      key_len: 88
          ref: NULL
         rows: 499
        Extra: Using index condition; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: table2
         type: eq_ref
possible_keys: ...
          key: ...
      key_len: 4
          ref: db.table1.id
         rows: 1
        Extra: Using index

有什么解决方案可以避免这种不可预测的MySQL行为? 我无法将FORCE INDEX添加到所有请求中,该怎么办?

PS:

SELECT * FROM `table1` 
INNER JOIN `table2` ON `table2`.`table1_id` = `table1`.`id` 
WHERE `table1`.`site_id` = ... ;

仅返回122条记录

PSS:疯狂,但是请求可以在更长时间内更快地工作

AND (table1.created_at >= '2016-07-01') AND (table1.created_at <= '2016-07-07)  

420秒

AND (table1.created_at >= '2016-06-01') AND (table1.created_at <= '2016-07-07)      

85毫秒

如果表已更改,则可以尝试运行ANALYZE TABLEhttp://dev.mysql.com/doc/refman/5.7/en/analyze-table.html )来同步更新统计信息。 InnoDB 保留优化器统计信息 ,这有一些限制

根据日期范围,我也想知道如果您这样做

AND (table1.created_at >= '2016-06-01') AND (table1.created_at <= '2016-06-07)'

假设较旧的数据具有更稳定的统计信息,并且大小无关紧要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM