簡體   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