2013-11-01 56 views
1

我有一個非常簡單的表,用於在成員配置文件上記錄訪問,具有多列鍵(member_id,visitor_id,month_visited)和更精確的日期。 month_visited是一個類似CHAR(7)的列:'2013-10'Mysql沒有在哪裏使用索引

每個新月,我想在另一個表中壓縮上個月的數據,然後刪除它。

我的要求很簡單:

DELETE FROM visits WHERE month_visited = '2013-10' 

它需要年齡刪除這些行,就像我的專用服務器上幾分鐘。當我查詢簡單的SELECT COUNT(*) FROM visits時也是如此。

我有2013-10的180萬條目。

但它需要時間。當我嘗試

EXPLAIN SELECT * FROM visits WHERE month_visited = "2013-10" 

它告訴我:

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE visits ref idx_month_visited idx_month_visited 21 const 1782148 Using where 

「使用,其中」,嚴重?

編輯:對不起,我忘了指定,我還增加了指數只是month_visited列:)(如EXPLAIN顯示,實際上,但它不使用它...)

我怎麼能改善這些(顯然)簡單的查詢?我是MySQL的noob,但我不認爲這是很正常的,它需要幾分鐘時間來執行這些查詢。

感謝您的任何意見!如果第一關鍵部件均在條件中使用

此致

+0

這張表有多少行? –

+0

我在問,因爲在我有限的體驗中,當沒有使用索引時,它通常是因爲使用它並沒有什麼幫助;也就是說,與全表掃描相比,它不會節省太多時間(當索引的基數很低時,這往往會發生) –

+0

另外,刪除是一個「寫」操作。索引優化讀操作,代價是寫操作更加昂貴(因爲寫操作時索引重建)。所以,你有一些複雜的指數這一事實並沒有幫助,但會加重問題。 –

回答

3

我在這個答案中總結我的意見。

一般來說,當一個索引沒有被使用時,這是因爲使用它沒有多大幫助。也就是說,與全表掃描相比,這不會節省太多時間(當索引的基數較低時,這往往會發生)。這似乎就是這種情況,因爲表中的行數與您要選擇的行數相同。在這種情況下,全面掃描通常比使用索引便宜。

另外,刪除是一個「寫」操作。索引優化讀操作,代價是寫操作更加昂貴(因爲寫操作時索引重建)。所以,你有一些複雜的指數這一事實並沒有幫助,但會加重問題。索引在縮小要檢索的行數時有意義;否則它不會帶來真正的收益,甚至會帶來額外的開銷。另外,在最好的情況下,索引可以使SELECT更高效。但它不會使寫入(插入,更新和刪除)工作更快;相反,它會使它們表現更差。

所以,你應該儘量擺脫不是絕對必要的指標。記住一個索引是一種折衷,這可能會使讀取操作(選擇)更快,但會使寫入操作(插入,更新,刪除)變慢。這是因爲索引必須在寫入後重新編譯。

您可能會想嘗試一下:「如果要從表中刪除多行,使用DELETE QUICK和OPTIMIZE TABLE可能會更快,這會重建索引而不是執行多個索引塊合併操作「。 dev.mysql.com/doc/refman/5.0/en/delete.html

還有另外一個選擇(可能工作與否,只是在這裏大聲思考):如果你想從visitss中刪除幾行,也許你可以將行「WHERE month!='2013-10'插入到輔助表中,TRUNCATE訪問,然後將輔助表中的行插入到訪問中,最後截斷aux表。然而,正如你指出的那樣,你在這個過程正在運行的時候需要提供某種鎖定

1

多列密鑰只能被使用。在你的情況,這意味着你的鑰匙(member_id, visitor_id, month_visited)將只用於如果你的條件包括

  • member_id或
  • member_id和visitor_id
  • member_id和visitor_id和month_visited。

創建一個具有month_visited作爲第一個組件的密鑰。

+0

對不起,我忘了指定我還在month_visited上添加了一個INDEX,就像它在EXPLAIN中顯示的那樣,但是,Mysql似乎並不願意使用它! –

+0

僅供參考:我已經啓動了我的PHP腳本(執行數據壓縮,以及爲json備份選擇行,以及刪除行),並且它已運行超過30分鐘,現在仍然不行完了。 –