2011-12-29 67 views
1

我已經得到了這個表:簡單的MySQL索引問題

CREATE TABLE IF NOT EXISTS `test1_nopart` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `idAccount` int(10) unsigned NOT NULL, 
    `data` mediumint(8) unsigned NOT NULL, 
    `date` date NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `date` (`date`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

我填這個表有10個000 000行。 按日期的再分配是同質

EXPLAIN SELECT * FROM `test1_nopart` WHERE date = "2014-03-04" 

下面是結果

id select_type table  type  possible_keys key  key_len  ref  rows  Extra 
1 SIMPLE  test1_nopart  ALL  NULL   NULL NULL  NULL 7875981  Using where 

=>而不解釋爲3.6sec的3000行(約)

正如可以看到的結果不使用索引,這是不是possible_keys列的一部分!

與覆蓋索引的方式相同的請求

EXPLAIN SELECT date FROM `test1_nopart` WHERE date = "2014-03-04" 

結果:

id select_type  table  type  possible_keys key  key_len  ref  rows  Extra 
1 SIMPLE  test1_nopart index NULL   date  3  NULL 7875981  Using where; Using index 

=>而不解釋爲2.8sec的3000行(約)

爲什麼結果MySQL沒有正確使用這個索引(DATE)?

信息: - VM服務器(我們的開發環境,我不知道什麼是硬件組成) - 的MySQL 5.5.8

SHOW INDEX FROM test1_nopart 

結果:

Table Non_unique Key_name Seq_in_index Column_name  Collation Cardinality  Sub_part Packed Null Index_type Comment  Index_comment 
test1_nopart 0 PRIMARY  1 id A 7875981  NULL NULL  BTREE   
test1_nopart 1 date 1 date A 6077 NULL NULL  BTREE   
  • 對於日期2014年3月4日=> 3134行
  • 總(彙總)=> 7 875 488
  • 表中有2556個不同的'日期'值
+0

什麼是'SHOW INDEX的輸出從test1_nopart',尤其是指數基數?另外,爲什麼將您的列命名爲MySQL的保留字? – 2011-12-29 17:19:30

+0

哎唷,看來6077很低... – nemenems 2011-12-29 17:36:04

+0

基數不是真正的問題。當您運行查詢'SELECT COUNT(1)datecount,'date' FROM test1_nopart GROUP BY'date' WITH ROLLUP;'你會看到真正的基數。您還會看到2014-03-14佔用了多少行。 – RolandoMySQLDBA 2011-12-29 17:40:51

回答

0

只是一個預感 - 也許它與單詞date有關。

儘量給一些提示到MySQL,你要使用的領域,而不是保留字:

SELECT date FROM `test1_nopart` WHERE `test1_nopart`.`date` = "2014-03-04" 
+0

無關字日期,我tryed以'和它玩同一 – nemenems 2011-12-29 17:38:10

1

MySQL查詢優化器認爲該日期索引的索引遍歷包括潛入集羣指數(內部稱爲gen_clust_index)。鑑於此,MySQL查詢優化器想通,這是更容易執行的第一個查詢全表掃描,並在scecond查詢全索引掃描。

您可能還需要看到指數的基數和多少行每個不同的值了。

執行以下操作:

SELECT COUNT(1) datecount,`date` FROM test1_nopart GROUP BY `date` WITH ROLLUP; 

根據你的評論,你會得到6077點不同的行。你還說有大約10,000,000行。運行此查詢,而不是:

SELECT COUNT(1) datecount FROM test1_nopart WHERE `date` = '2014-03-14'; 

請注意計數和總數。

的10,000,000

5%爲50萬

如果有更多的有50萬行的日期「2014-03-14」,那麼MySQL將永遠不會正確使用索引該特定值。

我不信任SHOW INDEXES FROM test1_nopart;因爲表是InnoDB的。 MyISAM會顯示確切的數字。 InnoDB根據潛水指數編制索引。

如果任何日期的datecount超過行總數的5%,MySQL查詢優化器會扔了它的手,做一個完整的掃描。

UPDATE

OK是拇指的5%的規則是窗外。嘗試通過創建不同的覆蓋索引來欺騙MySQL Query Optimizer:

ALTER TABLE test1_nopart ADD INDEX date_id_ndx (`date`,id); 

並嘗試再次查詢您的查詢。

+0

我覺得我是在這種情況下,因爲我有一個非常低的基數(6077) – nemenems 2011-12-29 17:37:32

+0

對於日期2014年3月4日=> 3134,總(彙總)7 875 488 – nemenems 2011-12-29 17:49:07

+0

您認爲這是一件壞事嗎? – nemenems 2011-12-29 17:52:05

0

這是我的想法。

在我們試圖通過date獲得data的第一種情況下,由於基數非常低,MySQL不使用date上的索引。和優化器使用以下命令: - 二次指數 - 集羣來訪問行 - 表來獲取數據。

在第二種情況下,當我們試圖通過date得到date更容易去通表使用索引,因爲MySQL能檢索索引選擇數據太(我的意思是MySQL的可掃描索引而不是整個表以獲得相同的數據)。使用以下命令: - 二次指數