2013-08-25 90 views
1
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+ 
| Field      | Type                   | Null | Key | Default | Extra   | 
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+ 
| type      | enum('Website','Facebook','Twitter','Linkedin','Youtube','SeatGeek','Yahoo') | NO | MUL | NULL |    | 
| name      | varchar(100)                 | YES | MUL | NULL |    | 
| processing_interface_id | bigint(20)                 | YES | MUL | NULL |    | 
| processing_interface_table | varchar(100)                 | YES | MUL | NULL |    | 
| create_time    | datetime                  | YES | MUL | NULL |    | 
| run_time     | datetime                  | YES | MUL | NULL |    | 
| completed_time    | datetime                  | YES | MUL | NULL |    | 
| reserved     | int(10)                  | YES | MUL | NULL |    | 
| params      | text                   | YES |  | NULL |    | 
| params_md5     | varchar(100)                 | YES | MUL | NULL |    | 
| priority     | int(10)                  | YES | MUL | NULL |    | 
| id       | bigint(20) unsigned               | NO | PRI | NULL | auto_increment | 
| status      | varchar(40)                 | NO | MUL | none |    | 
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+ 

select * from remote_request use index (processing_order) where remote_request.status = 'none' and type = 'Facebook' and reserved = '0' order by priority desc limit 0, 40; 

該表格接收極大量的寫入和讀取操作。每個remote_request最終都是一個進程,根據請求的類型,它可以產生0到5個其他remote_request之間的任何地方,以及請求的作用。Mysql查詢優化多列索引解決了這種緩慢?

該表目前坐落在大約350萬條記錄上,當網站本身負載很重時,它會進入蝸牛速度,並且我有50多個或更多的實例同時運行。 (REST請求是表的目的,以防萬一您不確定)。

隨着表的增長,情況越來越糟。我可以每天清理已處理的請求,但最終不會解決問題。

我需要的是這個查詢始終有一個非常低的響應率。

以下是表格中的當前索引。

+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table   | Non_unique | Key_name       | Seq_in_index | Column_name    | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| remote_request |   0 | PRIMARY       |   1 | id       | A   |  2403351 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | type_index      |   1 | type      | A   |   18 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | processing_interface_id_index |   1 | processing_interface_id | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | processing_interface_table_index |   1 | processing_interface_table | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | create_time_index    |   1 | create_time    | A   |  160223 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | run_time_index     |   1 | run_time     | A   |  343335 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | completed_time_index    |   1 | completed_time    | A   |  267039 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | reserved_index     |   1 | reserved     | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | params_md5_index     |   1 | params_md5     | A   |  2403351 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | priority_index     |   1 | priority     | A   |   716 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | status_index      |   1 | status      | A   |   18 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | name_index      |   1 | name      | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   1 | priority     | A   |   200 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   2 | status      | A   |   200 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   3 | type      | A   |   200 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   4 | reserved     | A   |   200 |  NULL | NULL | YES | BTREE  |   |    | 
+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

任何想法如何解決這個問題?是不是可以做出某種複雜的索引來自動排列優先級,然後將前40個匹配'Facebook'類型?它目前正在掃描多於500k行的表格,然後返回效率非常低的結果。

一些其他的版本,我一直在擺弄查詢的是:

select * from remote_request use index (type_index,status_index,reserved_index,priority_index) where remote_request.status = 'none' and type = 'Facebook' and reserv       ed = '0' order by priority desc limit 0, 40 

這將是驚人的,如果我們能根據多麼請求的多種類型的輸入get下1000行掃描的行表。

在此先感謝,除了最有經驗的mysql專家之外,這對大多數人來說可能是一個真正的胡桃夾子?

+0

即使你不能顯示數據的強度,SQLfiddle的例子會更容易看到問題 – skv

回答

1

您的四列索引有正確的列,但順序錯誤。

您希望索引先查找匹配的行,然後按三列進行查找。你正在查找三個相等的條件,所以你知道一旦索引找到匹配行的集合,這些行的順序基本上與前三列相關。所以要解決這個問題,可以在第四列中添加你想要排序的列。

如果這樣做,那麼ORDER BY將成爲無操作,因爲查詢可以按照它們存儲在索引中的順序讀取行。

所以我將創建下列指標:

CREATE INDEX processing_order2 ON remote_request 
(status, type, reserved, priority); 

有可能不是前三列的順序太大的意義,因爲他們都在平等的條件與AND結合。但priority列屬於最後。

您也可以閱讀我的演示文稿How to Design Indexes, Really

順便說一下,如果您有正確的索引,則不需要使用USE INDEX(),MySQL的優化程序會在大部分時間自動選擇它。但USE INDEX()可以阻止優化器考慮您創建的新索引,因此它成爲代碼維護的缺點。

+0

我真的很喜歡這個答案,讓我試試看。 –

+0

這就像是600000%的優化。非常感謝。 –

+0

很高興幫助!你可以看到索引中的列真的很重要。學習如何預測最佳列並不難。 –

1

這不是一個完整的答案,但它是太長了評論:

你實際上在所有這些指標的搜索?如果沒有擺脫一些。額外的索引減慢了寫入。

其次在您的查詢中使用EXPLAIN,並且在您執行操作時不指定索引。看看MySQL如何處理它而不是強迫一個選項(通常它是正確的)。

最後,排序可能是最傷害你的。如果你不排序,它可能會很快得到記錄。它可以掃描和分類每一個符合您的標準行之前,它可以返回前40

選項:

  1. 嘗試創建一個視圖(如不熟悉與觀點,但它可能工作)
  2. 將此表拆分爲更小的表格
  3. 使用第三方工具,如 Sphinx或Lucene創建專用索引以進行搜索。 (我 之前使用過Sphinx,你可以在 http://sphinxsearch.com/找到它)。
  4. 或者使用NoSQL解決方案進行研究,您可以使用Map功能來執行此操作。

編輯我讀了一些關於使用VIEW,我不認爲它會幫助你在你的情況,因爲你有這麼大的表。請參閱此線程中的答案:Using MySQL views to increase performance

+0

1)視圖我不認爲是好事,因爲它最終將不得不重新計算很多......至於插入它強制重新計算視圖? 2)更小的桌子不會爲這個特殊的東西工作,我想我可以根據類型分開桌子。 3)shinx似乎矯枉過正。 4)沒有SQL也似乎過度殺死只是尚未..就索引,我確實使用其他地區85%的其他查詢更快,所以刪除它們不是一個真正的選擇每個說..然而,我喜歡你的迴應。它絕對的想法。我可能不得不打破它的類型。 –

+0

是的,你是對的。結果會被緩存,但如果你有很多寫入,它可能會傷害你。 – Cfreak