2013-10-15 13 views
0

優化查詢我有一個InnoDB表levels在MySQL5.6

 
+--------------------+--------------+------+-----+---------+-------+ 
| Field    | Type   | Null | Key | Default | Extra | 
+--------------------+--------------+------+-----+---------+-------+ 
| id     | int(9)  | NO | PRI | NULL |  | 
| level_name   | varchar(20) | NO |  | NULL |  | 
| user_id   | int(10)  | NO |  | NULL |  | 
| user_name   | varchar(45) | NO |  | NULL |  | 
| rating    | decimal(5,4) | NO |  | 0.0000 |  | 
| votes    | int(5)  | NO |  | 0  |  | 
| plays    | int(5)  | NO |  | 0  |  | 
| date_published  | date   | NO | MUL | NULL |  | 
| user_comment  | varchar(255) | NO |  | NULL |  | 
| playable_character | int(2)  | NO |  | 1  |  | 
| is_featured  | tinyint(1) | NO | MUL | 0  |  | 
+--------------------+--------------+------+-----+---------+-------+ 

共有約4萬行。由於前端功能,我需要使用各種過濾器和排序來查詢此表。他們在playable_character,rating,playsdate_publisheddate_published可以過濾顯示在最後一天,每週,每月或任何時間(過去3年)。還有分頁。因此,根據用戶選擇,查詢可以看,例如,像這些之一:

SELECT * FROM levels 
WHERE playable_character = 0 AND 
    date_published BETWEEN date_sub(now(), INTERVAL 3 YEAR) AND now() 
ORDER BY date_published DESC 
LIMIT 0, 1000; 

SELECT * FROM levels 
WHERE playable_character = 4 AND 
    date_published BETWEEN date_sub(now(), INTERVAL 1 WEEK) AND now() 
ORDER BY rating DESC 
LIMIT 4000, 1000; 

SELECT * FROM levels 
WHERE playable_character = 5 AND 
    date_published BETWEEN date_sub(now(), INTERVAL 1 MONTH) AND now() 
ORDER BY plays DESC 
LIMIT 1000, 1000; 

我開始了一個索引idx_date_char(date_published, playable_character)這裏的第一個例子查詢工作偉大 - 基本上什麼這是由date_published訂購。使用EXPLAIN,我得到'使用索引條件',這很好。我想我明白爲什麼索引能夠工作,因爲在WHERE和ORDER BY子句中存在相同的兩個索引列。

我的問題是通過playsrating訂購的查詢。我知道我正在介紹第三列,但在我的生活中,我無法得到一個效果良好的索引,儘管嘗試了我能想到的每一個變化:每個訂單中三到四個組合索引,以及等等。也許查詢可能寫入不同?

我要補充一點,ratingplays總是質疑爲DESC。只有date_published可能是DESCASC

任何建議非常感謝。 TIA。

+0

你有沒有嘗試覆蓋索引,像'ON(date_sub ASC,playable_character ASC,rating DESC)''?請注意,第一列按升序排列,最後一列以降序排列,因爲您的查詢具有'ORDER BY rating DESC' + limit ... – a1ex07

+0

對於第一個查詢,'(playable_character,date_published)'上的索引會更好。對於第二和第三,它更復雜,不容易優化。 –

+0

@ypercube - 我本可以發誓,昨天速度較慢,並且在EXPLAIN額外專欄中給了我一個'where'。但你是對的,我只是比較它們,它更快(並且是'使用索引條件')。 – Hal50000

回答

1

看來你會很好地利用這種方式來分類的每個查詢的數據:

  1. playable_character,date_published
  2. playable_character,date_published,評級
  3. playable_character,date_published,扮演

請記住,您需要在第一個查詢中排序的數據恰好是第二個和第三個查詢需要的數據的子集,因此我們可以獲得r它的ID。

還要注意,添加DESCASC到索引語法正確,但實際上並沒有改變任何東西因爲這種功能目前不支持(預計在未來支持所以這就是爲什麼它的存在)。所有索引都按升序存儲。更多信息here

因此,這些都是你應該創建索引:

ALTER TABLE levels ADD INDEX (playable_character, date_published, rating) 
ALTER TABLE levels ADD INDEX (playable_character, date_published, plays) 

那裏跑的比阿甘快這應該使3個查詢。

+0

謝謝。有趣的事情正在發生。首先,這兩個指標確實運作良好,但是有一種情況他們沒有。考慮這個:'SELECT count(*)FROM levels WHERE playable_character = 0;/*'1724061'*/ SELECT count(*)FROM levels WHERE playable_character = 10;/*'6718'* /'當date_published是3年時,它基本上是每個記錄。在EXPLAIN中,當行(在EXPLAIN中)大約700,000行時,會彈出'where where',並且查詢性能會下降到極限。你知道發生了什麼事嗎? – Hal50000

+0

索引越「獨特」,數據獲取的速度越快。如果你有幾十萬條與查詢相匹配的記錄(在where子句中),那麼你將不得不對數十萬條數據進行排序。在這些情況下沒有太多的事情要做,因爲數據是如何分佈的。下一步應該增加諸如'read_rnd_buffer_size'和'sort_buffer_size'的資源。請查看此[鏈接](http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_sort_buffer_size)以獲取有關它們的信息。或者在http://dba.stackexchange.com提問。他們可以幫助你更多:) –

+0

@Mosty Mostacho read_rnd_buffer_size和sort_buffer_size設置可以非常危險的設置來調整..Hal50000現在問這裏http://dba.stackexchange.com/questions/51771/how-to-optimize-indexes -on-mysql-query-with-various-sorts about the settings .. –

1

您的where子句和order by中使用的列應該是索引的一部分。我有你想要的

(playable_character, date_published DESC, rating DESC, plays DESC) 

索引我會把可玩角色的原因首先是ID小學,那麼所有這些日期內的問題。評分和比賽僅用於協助ORDER BY條款)。

想想像這樣的索引。如果您按照Date_Published排序,那麼Playable_Character,請考慮一個盒子的房間。每個盒子都有一個日期。在給定日期的那個盒子裏,你按照字符順序排列它們。所以,你需要3年的數據才能通過,你必須在過去的3年中打開所有的盒子,並找到你正在尋找的角色。

現在,想起它是這樣的。每個盒子都是按字符排列的,其中的所有日期都是預先排序的。所以,你去一個盒子,打開它......移動到有問題的日期,並從你想要的X-Y範圍內抓取記錄。現在,您可以通過這些記錄申請一個簡單的訂單。

+0

謝謝,解釋有助於理解索引和查詢的性質。 – Hal50000

1

當您的查詢包含範圍謂詞如BETWEEN時,索引中列的順序非常重要。

  • 首先,包括由平等謂詞引用的一個或多個列。
  • 接下來,包含一個由範圍謂詞引用的列。
  • 範圍謂詞引用的列之後的索引中的任何其他列不能用於其他範圍謂詞或用於排序。
  • 如果您沒有範圍謂詞,則可以爲排序順序添加一列。

因此,您的第一個查詢可以從(playable_character, date_published)上的索引中受益。排序應該是無操作的,因爲優化器只會按索引順序讀取行。

第二個和第三個查詢綁定做一個文件,因爲你有一個範圍謂詞,然後你按不同的列進行排序。如果您只有等式謂詞,則可以使用第三列來避免文件排列,但當您有範圍謂詞時,這不起作用。

您可以期待的最好的條件是減少結果集的大小,以便它可以在內存中進行排序,而不需要執行太多的操作sort merge passes。您可以通過增加sort_buffer_size來提供幫助,但請注意不要太多,因爲它是按每個線程分配的。

索引定義中的ASC/DESC關鍵字在MySQL中沒有區別。
參見http://dev.mysql.com/doc/refman/5.6/en/create-index.html

這些關鍵字允許用於指定升序或降序的索引值存儲未來擴展。目前,他們被解析但被忽略;索引值始終以升序存儲。

相關問題