2016-09-22 59 views
1

我正在與一箇舊的遺留項目,我有一個非常緩慢的查詢問題。我可以通過添加新索引或如何改進查詢來改進此查詢嗎?

我有以下的數據庫模式:

table: search_api_db_full_index_text 
rows : 1612226 
+------------+------------------+------+-----+---------+-------+ 
| Field  | Type    | Null | Key | Default | Extra | 
+------------+------------------+------+-----+---------+-------+ 
| item_id | bigint(20)  | NO | PRI | NULL |  | 
| field_name | varchar(255)  | NO | PRI | NULL |  | 
| word  | varchar(50)  | NO | PRI | NULL |  | 
| score  | int(10) unsigned | NO |  | 0  |  | 
+------------+------------------+------+-----+---------+-------+ 

indexes for: search_api_db_full_index_text 
+-------------------------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table       | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------------------------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| search_api_db_full_index_text |   0 | PRIMARY |   1 | item_id  | A   |  42323 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_text |   0 | PRIMARY |   2 | field_name | A   |  134023 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_text |   0 | PRIMARY |   3 | word  | A   |  1608286 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_text |   1 | word_field |   1 | word  | A   |  402071 |  20 | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_text |   1 | word_field |   2 | field_name | A   |  229755 |  NULL | NULL |  | BTREE  |   |    | 
+-------------------------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 



table: search_api_db_full_index_field_event_date_mutli_field_date_opt 
rows: 100421  
+---------+------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+---------+------------+------+-----+---------+-------+ 
| item_id | bigint(20) | NO | PRI | NULL |  | 
| value | bigint(20) | NO | PRI | NULL |  | 
+---------+------------+------+-----+---------+-------+ 

indexes for: search_api_db_full_index_field_event_date_mutli_field_date_opt 
+----------------------------------------------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table               | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+----------------------------------------------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| search_api_db_full_index_field_event_date_mutli_field_date_opt |   0 | PRIMARY |   1 | item_id  | A   |  50380 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_field_event_date_mutli_field_date_opt |   0 | PRIMARY |   2 | value  | A   |  100760 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_field_event_date_mutli_field_date_opt |   1 | value |   1 | value  | A   |  100760 |  NULL | NULL |  | BTREE  |   |    | 
+----------------------------------------------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 



table: search_api_db_full_index_field_event_date_mutli_field_date_o_1 
rows: 100099 
+---------+------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+---------+------------+------+-----+---------+-------+ 
| item_id | bigint(20) | NO | PRI | NULL |  | 
| value | bigint(20) | NO | PRI | NULL |  | 
+---------+------------+------+-----+---------+-------+ 

indexes for search_api_db_full_index_field_event_date_mutli_field_date_o_1 
+----------------------------------------------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table               | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+----------------------------------------------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| search_api_db_full_index_field_event_date_mutli_field_date_o_1 |   0 | PRIMARY |   1 | item_id  | A   |  50160 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_field_event_date_mutli_field_date_o_1 |   0 | PRIMARY |   2 | value  | A   |  100320 |  NULL | NULL |  | BTREE  |   |    | 
| search_api_db_full_index_field_event_date_mutli_field_date_o_1 |   1 | value |   1 | value  | A   |  100320 |  NULL | NULL |  | BTREE  |   |    | 
+----------------------------------------------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

目前,下面的查詢需要約170秒的執行。

這很奇怪,因爲在過去它從未如此緩慢。 (大部分爲10-12秒)

該查詢由Drupal視圖生成,沒有左連接,查詢運行速度非常快。理想情況下,我想通過添加額外的索引來解決這個問題。可能嗎?

SELECT SQL_NO_CACHE 
    t.item_id AS item_id, 
    SUM(score) AS score, 
    t.word LIKE '%test%' AS w0 
FROM 
    search_api_db_full_index_text t 
     LEFT OUTER JOIN 
    search_api_db_full_index_field_event_date_mutli_field_date_opt t_2 ON t.item_id = t_2.item_id 
     LEFT OUTER JOIN 
    search_api_db_full_index_field_event_date_mutli_field_date_o_1 t_3 ON t.item_id = t_3.item_id 
WHERE 
    ((t.word LIKE '%test%' ESCAPE '\\')) 
     AND (field_name IN ('body:value' , 'field_event_organiser:title', 
     'field_event_place:title', 
     'field_image_caption', 
     'title')) 
     AND (((t_2.value >= '1474502400') 
     AND (t_3.value <= '1537660799'))) 
GROUP BY t.item_id , item_id , w0 
ORDER BY score DESC; 


Output from explain:  
+------+-------------+-------+-------+---------------+---------+---------+-----------------------------------+-------+-----------------------------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref        | rows | Extra              | 
+------+-------------+-------+-------+---------------+---------+---------+-----------------------------------+-------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | t_2 | range | PRIMARY,value | value | 8  | NULL        | 35410 | Using where; Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | t_3 | ref | PRIMARY,value | PRIMARY | 8  | drupal7_.t_2.item_id    |  2 | Using where; Using index         | 
| 1 | SIMPLE  | t  | ref | PRIMARY  | PRIMARY | 8  | drupal7_.t_2.item_id    | 38 | Using where            | 
+------+-------------+-------+-------+---------------+---------+---------+-----------------------------------+-------+-----------------------------------------------------------+ 

編輯:

如果我強迫索引查詢執行時間會從170-240秒降低到30-50秒。但它仍然很慢。

SELECT SQL_NO_CACHE 
    t.item_id AS item_id, 
    SUM(score) AS score, 
    t.word LIKE '%test%' AS w0 
FROM 
    search_api_db_full_index_text t 
     LEFT OUTER JOIN 
    search_api_db_full_index_field_event_date_mutli_field_date_opt t_2 FORCE INDEX (PRIMARY) ON t.item_id = t_2.item_id 
     LEFT OUTER JOIN 
    search_api_db_full_index_field_event_date_mutli_field_date_o_1 t_3 FORCE INDEX (PRIMARY) ON t.item_id = t_3.item_id 
WHERE 
    ((t.word LIKE '%test%' ESCAPE '\\')) 
     AND (field_name IN ('body:value' , 'field_event_organiser:title', 
     'field_event_place:title', 
     'field_image_caption', 
     'title')) 
     AND (((t_2.value >= '1474502400') 
     AND (t_3.value <= '1537660799'))) 
GROUP BY t.item_id , item_id , w0 
ORDER BY score DESC; 

當我還迫使search_api_db_full_index_text指數word_field的查詢工作,因爲它應該(小於1秒)

SELECT SQL_NO_CACHE 
    t.item_id AS item_id, 
    SUM(score) AS score, 
    t.word LIKE '%test%' AS w0 
FROM 
    search_api_db_full_index_text t FORCE INDEX (word_field) 
     LEFT OUTER JOIN 
    search_api_db_full_index_field_event_date_mutli_field_date_opt t_2 FORCE INDEX (PRIMARY) ON t.item_id = t_2.item_id 
     LEFT OUTER JOIN 
    search_api_db_full_index_field_event_date_mutli_field_date_o_1 t_3 FORCE INDEX (PRIMARY) ON t.item_id = t_3.item_id 
WHERE 
    ((t.word LIKE '%test%' ESCAPE '\\')) 
     AND (field_name IN ('body:value' , 'field_event_organiser:title', 
     'field_event_place:title', 
     'field_image_caption', 
     'title')) 
     AND (((t_2.value >= '1474502400') 
     AND (t_3.value <= '1537660799'))) 
GROUP BY t.item_id , item_id , w0 
ORDER BY score DESC; 
+0

你有索引名爲'value'嗎? – Shadow

+0

@Shadow添加查詢並在沒有連接的情況下「解釋」輸出。我有在兩個表search_api_db_full_index_field_event_date_mutli_field_date_opt名字'value'列值指數,search_api_db_full_index_field_event_date_mutli_field_date_o_1 –

+0

對不起,要求不加入,這個問題是在加入添加一個表,而不是用在表中的解釋後實現加入的左側。看到我下面更新的答案。 – Shadow

回答

1

的問題是與search_api_db_full_index_field_event_date_mutli_field_date_opt表的連接。該表的別名爲t_2,並在解釋結果的第一行的額外列中顯示:Using where; Using index; Using temporary; Using filesort

從性能的角度來看,使用臨時文件,使用filesort相當糟糕。從key列可以看出,MySQL決定使用value索引,該索引支持where子句,但不支持該聯接。

由於此表中主鍵涵蓋item_idvalue領域,我會嘗試強制MySQL通過force index索引提示加入t_2時使用的主索引。顯然,MySQL優化器對於在這個查詢中使用哪個索引做出了錯誤的決定。

+0

你認爲mysql有可能因爲行數增加而改變優化路徑嗎?這個查詢很慢,但從來沒有這麼慢..我不知道我是否可以增加一些mysql設置,比如join_buffer_size等...... –

+1

MySQL改變它對使用哪個索引的看法是絕對有可能的。指數統計數據基於抽樣。檢查索引的基數,你也可以嘗試強制MySQL更新它們。這裏有關於這些主題的問題SO – Shadow

+1

請參閱http://stackoverflow.com/questions/34851674/can-cardinality-differ-for-duplicate-indexes-in-mysql或http://stackoverflow.com/questions/38302435/mysql-table-index-cardinality – Shadow