2016-12-30 109 views
1

我有這個疑問:查詢中未使用索引。如何提高性能?

SELECT 
    * 
FROM 
    `av_cita` 
JOIN `av_cita_cstm` ON (
    (
     `av_cita`.`id` = `av_cita_cstm`.`id_c` 
    ) 
) 
WHERE 
    av_cita.deleted = 0 

此查詢時間超過120秒完成,但我已經添加的所有索引。

當我問執行計劃:

explain SELECT * FROM `av_cita` 
     JOIN `av_cita_cstm` ON ((`av_cita`.`id` = `av_cita_cstm`.`id_c`)) 
     WHERE av_cita.deleted = 0; 

我得到這個:

+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+ 
| id | select_type | table  | type | possible_keys  | key  | key_len | ref      | rows | Extra  | 
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+ 
| 1 | SIMPLE  | av_cita  | ALL | PRIMARY,delete_index | NULL | NULL | NULL      | 192549 | Using where | 
| 1 | SIMPLE  | av_cita_cstm | eq_ref | PRIMARY    | PRIMARY | 108  | rednacional_v2.av_cita.id |  1 |    | 
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+ 

delete_indexpossible_keys列中列出,但關鍵是null,並且它不使用該指數。

表和索引定義:

+------------------+--------------+------+-----+---------+-------+ 
| Field   | Type   | Null | Key | Default | Extra | 
+------------------+--------------+------+-----+---------+-------+ 
| id    | char(36)  | NO | PRI | NULL |  | 
| name    | varchar(255) | YES | MUL | NULL |  | 
| date_entered  | datetime  | YES | MUL | NULL |  | 
| date_modified | datetime  | YES |  | NULL |  | 
| modified_user_id | char(36)  | YES |  | NULL |  | 
| created_by  | char(36)  | YES | MUL | NULL |  | 
| description  | text   | YES |  | NULL |  | 
| deleted   | tinyint(1) | YES | MUL | 0  |  | 
| assigned_user_id | char(36)  | YES | MUL | NULL |  | 
+------------------+--------------+------+-----+---------+-------+ 
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name   | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| av_cita |   0 | PRIMARY   |   1 | id    | A   |  192786 |  NULL | NULL |  | BTREE  |   |    | 
| av_cita |   1 | delete_index  |   1 | deleted   | A   |   2 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | name_index   |   1 | name    | A   |  96393 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | date_entered_index |   1 | date_entered  | A   |  96393 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | created_by   |   1 | created_by  | A   |   123 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | assigned_user_id |   1 | assigned_user_id | A   |  1276 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | deleted_id   |   1 | deleted   | A   |   2 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | deleted_id   |   2 | id    | A   |  192786 |  NULL | NULL |  | BTREE  |   |    | 
| av_cita |   1 | id     |   1 | id    | A   |  192786 |  NULL | NULL |  | BTREE  |   |    | 
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

我怎樣才能提高此查詢的性能?

+0

您可能想要顯示「av_cita」的表格和所有索引定義。 – mustaccio

+0

對不起,男人,[url = http://i.imgur.com/F4KPAnm.png] [img] http://imgur.com/F4KPAnml.png [/ img] [/ url] –

+0

http:// imgur.com/F4KPAnml.png http://imgur.com/irgBnldl.png –

回答

0

該查詢正在失去進行連接的時間。我強烈建議在av_cita_cstm.id_c上創建和索引。那麼該計劃可能會更改爲使用av_cita_cstm表的索引,這比PRIMARY要好得多。因此PRIMARY將在ac_cita上使用。

我認爲這會帶來很大的改善。如果確保delete_index使用兩個字段進行定義:(deleted, id),然後將SQL語句的where條件移動到join條件中,您可能仍會獲得更多改進。但我不確定MySql會認爲這是可能的。

+0

謝謝你的快速回答。我會嘗試 !! –

+0

我做到了,並採取相同的結果。無論如何 –

+0

你能否像你對'av_cita'所做的那樣向你的問題添加'av_cita_cstm'上現有索引的信息? – trincot

0

deleted上的索引不被使用可能是因爲優化器已經決定全表掃描比使用索引便宜。如果在表中大約20%或更多的行上找到您搜索的值,MySQL往往會做出這個決定。

以類推的方式,想一想書後面的索引。你可以理解爲什麼像「」這樣的常見詞彙沒有編入索引。只讀封面封面比翻轉索引要容易得多,索引只會告訴你「」出現在大多數頁面上。

如果你認爲MySQL已經做出了錯誤的決定,你可以把它假裝表掃描比使用一個特定的指數更加昂貴:

SELECT 
    * 
FROM 
    `av_cita` FORCE INDEX (deleted_index) 
JOIN `av_cita_cstm` ON (
    (
     `av_cita`.`id` = `av_cita_cstm`.`id_c` 
    ) 
) 
WHERE 
    av_cita.deleted = 0 

閱讀http://dev.mysql.com/doc/refman/5.7/en/index-hints.html有關索引提示的更多信息。不要過度使用索引提示,它們僅在極少數情況下才有用。大多數情況下,優化器做出正確的決定。

您的EXPLAIN計劃顯示,您加入av_cita_cstm已經在使用唯一索引(線索爲「type:eq_ref」,也是「rows:1」)。我認爲該表中不需要任何新索引。

我注意到EXPLAIN顯示av_cita上的表掃描大概估計192549行。我真的很驚訝,這需要120秒。在任何功能相當強大的計算機上,運行速度要快得多。

這使我不知道,如果你有別的東西,需要在此服務器上的調整或配置:

  • 哪些進程正在服務器上運行?很多應用程序,也許?其他進程是否也在此服務器上運行緩慢?你需要增加服務器的功能,還是將應用程序移動到他們自己的服務器上?

    如果你在MySQL 5.7,嘗試查詢sys架構:本:

    select * from sys.innodb_buffer_stats_by_table 
    where object_name like 'av_cita%'; 
    
  • 同時運行有其他昂貴的SQL查詢?

  • 您是否分配了MySQL的innodb_buffer_pool_size?如果它太小,它可能會瘋狂地回收RAM中的頁面,因爲它會掃描您的表格。

    select @@innodb_buffer_pool_size; 
    
  • 您是否超額分配innodb_buffer_pool_size?一旦我幫助調整運行速度非常緩慢的服務器。原來他們有一個4GB的緩衝池,但只有1GB的物理RAM。操作系統瘋狂交換,導致一切運行緩慢。

另一個想法:你們充分展示了該列av_cita,但不表結構av_cita_cstm。你爲什麼取SELECT *?你真的需要所有的列嗎?後面的表中是否有巨大的BLOB/TEXT列?如果是這樣,它可能會從磁盤讀取大量不需要的數據。

當你問SQL的問題,如果你運行

SHOW CREATE TABLE av_cita\G 
SHOW TABLE STATUS LIKE 'av_cita'\G 

而且還運行其它表av_cita_cstm相同的命令,並且包括在上面你的問題的輸出,這將有助於。