2013-04-26 84 views
3

我有一個MySQL表,其中有大約2000萬行數據。MySQL索引導致查詢變慢

+-------------+-------------+------+-----+---------+----------------+ 
| Field  | Type  | Null | Key | Default | Extra   | 
+-------------+-------------+------+-----+---------+----------------+ 
| id   | bigint(20) | NO | PRI | NULL | auto_increment | 
| b_id  | int(11)  | YES | MUL | NULL |    | 
| order  | bigint(20) | YES | MUL | NULL |    | 
| date  | date  | YES |  | NULL |    | 
| time  | time  | YES |  | NULL |    | 
| channel  | varchar(8) | YES | MUL | NULL |    | 
| data  | varchar(60) | YES |  | NULL |    | 
| date_system | date  | YES | MUL | NULL |    | 
| time_system | time  | YES |  | NULL |    | 
+-------------+-------------+------+-----+---------+----------------+ 

我對(B_ID,頻道,日期)的非唯一索引來加速之類的查詢:

select date, left(time,2) as hour, round(data,1) as data 
from data_lines 
where channel='1' 
    and b_id='300' 
    and date >='2013-04-19' 
    and date <='2013-04-26' 
group by date,hour 

的問題是,我的刀片有時會有所重疊,所以我想用「ON DUPLICATE KEY UPDATE',但是這需要一個唯一的索引。因此,我在(b_id,頻道,日期,時間)上創建了一個唯一索引,因爲這是確定是否存在雙重值的四個主要特徵。插入現在工作正常,但我的選擇查詢是不能接受的慢。

我不明白爲什麼,因爲添加了新的指數我選擇變得更慢:

  • 是一次非常獨特,索引變得非常大 - >和慢?
  • 我應該刪除非唯一索引來加快速度嗎?
  • 是我的不好查詢?
  • 其他想法歡迎!

對於記錄(order,date_system和time_system)根本不在索引或選擇中使用,但確實包含數據。插入從C和Python運行,並從PHP中選擇。

每請求的解釋查詢:

mysql> explain select date, left(time,2) as hour, round(data,1) as data 
from data_lines 
where channel='1' 
    and b_id='300' 
    and date >='2013-04-19' 
    and date <='2013-04-26' 
group by date,hour; 

+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys     | key  | key_len | ref   | rows | Extra          | 
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | data_lines| ref | update_index,b_id,comp_index | comp_index | 16  | const,const | 3548 | Using where; Using temporary; Using filesort | 
+----+-------------+-----------+------+--------------------------------+------------+---------+-------------+------+----------------------------------------------+ 

的update_index是我的唯一的(B_ID,頻道,日期,時間)指數和comp_index是(B_ID,頻道,日期)我的非唯一索引。

指標爲:

+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table  | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| data_lines|   0 | PRIMARY  |   1 | id   | A   | 17918898 |  NULL | NULL |  | BTREE  |   |    | 
| data_lines|   0 | id_UNIQUE |   1 | id   | A   | 17918898 |  NULL | NULL |  | BTREE  |   |    | 
| data_lines|   0 | update_index |   1 | channel  | A   |   17 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   0 | update_index |   2 | b_id  | A   |   17 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   0 | update_index |   3 | date  | A   |  44244 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   0 | update_index |   4 | time  | A   | 17918898 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | box_id  |   1 | b_id  | A   |   17 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | idx   |   1 | order  | A   | 17918898 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | comp_index |   1 | b_id  | A   |   17 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | comp_index |   2 | channel  | A   |  6624 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | comp_index |   3 | date  | A   |  165915 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | date_system |   1 | date_system | A   |   17 |  NULL | NULL | YES | BTREE  |   |    | 
| data_lines|   1 | mac   |   1 | mac   | A   |   17 |  NULL | NULL | YES | BTREE  |   |    | 
+-----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
+0

請爲您的查詢顯示'explain'語句..您創建的所有索引.. – Meherzad 2013-04-26 07:17:40

+0

嗨Meherzad,感謝您的幫助。將上面的解釋命令添加到我的上面的格式中。 – lleto 2013-04-26 07:26:49

+1

嘗試顯式指定'USE INDEX(update_index)'。 – Meherzad 2013-04-26 07:31:57

回答

2

嘗試直接在您的查詢中指定USE INDEX(update_index)

優化程序在選擇索引時選擇錯誤選項,因爲查詢速度變慢。

希望這能解決你的問題.. :)

0
  • 由於PRIMARY KEYUNIQUE KEY,擺脫無用UNIQUE(id)的。
  • 我們正在談論的任何專欄NULL?如果沒有,請讓他們NOT NULL。 (在升級UNIQUE索引之前,這很重要。)
  • 除非您需要其他查詢,DROPcomp_index。它不會在4列unique_index上提供額外的好處(朝向INSERTSELECT)。
  • 您是否在其他地方使用id?如果沒有,則將4列唯一索引提升爲PRIMARY KEY。這一步可能會加快速度,因爲現在它不會在索引和數據之間來回跳動(獲得data)。
  • 剩下4個其他指標;看看你是否真的需要他們。(我建議這樣做,因爲上一步會使二級索引變得更笨。)
  • 如果使用MyISAM,則更改爲InnoDB。

在做大量的ALTERs時,在一個語句中做 - 它會快得多。

ALTER TABLE ... 
    DROP COLUMN id, 
    DROP PRIMARY KEY, 
    DROP INDEX `id_UNIQUE`, 
    DROP INDEX comp_index, 
    ADD PRIMARY KEY(channel, b_id, date, time), 
    ALTER COLUMN ... NOT NULL, 
    ... 
    ENGINE=InnoDB; 

或者,要更加謹慎:CREATE被修改的表,然後INSERT...SELECT來填充它。然後測試。最終做RENAME TABLE來實現它。

datetime分成兩列而不是單個datetime通常是一個壞主意。但我不會推它,因爲它可能不會影響這個問題。

+0

我正在閱讀'是否有任何我們正在談論的列NULL?如果不是,請將它們設爲NOT NULL。 (在升級UNIQUE索引之前,這是很重要的)。'我認爲這不適用於InnoDB數據庫,根據高性能SQL第3版的說法,「InnoDB存儲空值只需一位,所以它可以非常節省空間對於人口稀少的數據「。 – 2018-02-08 20:37:45

+0

@AlWang - 但你使用了什麼'ROW_FORMAT'? – 2018-02-09 03:24:42

+0

@AlWang - 另外,請閱讀關於在'UNIQUE'索引中使用'NULL'值是否被認爲不相等的問題。 – 2018-02-09 03:25:39