2011-12-11 16 views
3

我有一張int字段的表,我們稱之爲createTime。該表由幾百萬條記錄組成。現在我想運行查詢:偏差限制(「LIMIT 500000,10」)即使在索引後也很慢?

select * from `table` order by `createTime` desc limit 500000, 10 

我創建了一個指數爲createTime,但在查詢運行慢得令人難以置信。什麼原因?我該如何改進它?

這裏是EXPLAIN說:

id 1 
select_type simple 
table table 
type index 
possible_keys null 
key createTime 
key_len 4 
ref null 
rows 500010 
extra 

至於補償,它的工作速度更快時,它的小。

+0

您是否嘗試過使用EXPLAIN關鍵字查看MySql正在做什麼?實際上,EXPLAIN從'table'命令中選擇* by createTime' desc limit 500000,10.出於興趣,什麼數據類型是createTime? – dash

+0

我在問題中解釋過這是一個int。 EXPLAIN表示沒有什麼有趣的地方,它使用創建的索引,它估計的行數爲500010. –

+0

(索引創建之前*的性能是怎樣的?什麼是沒有偏移的限制?偏移量更小的限制?) – 2011-12-11 20:42:29

回答

8

一般規則:avoid OFFSET for large tables

[A] S上的偏移量增加時,所採取的查詢執行 逐漸增加,這可能意味着處理非常大的表 將需要極長的時間。原因是因爲抵消工作 對錶未被索引的表中的行的物理位置。因此 要在偏移量x處查找一行,數據庫引擎必須遍歷從0到x遍歷 的所有行。

一般的經驗法則是「從來沒有在限制子句中使用補償」。對於 小型表格,您可能不會注意到任何區別,但對於具有超過一百萬行的表格 ,您將看到性能提高 。

+2

我寧願*「避免大OFFSET」* –

+0

@ypercube:但大'OFFSET'爲小桌子很好。 –

+0

你的意思是當OFFSET大於表格大小?我猜就是這樣。毫無意義但很好。 –

0

我認爲索引不會改變任何東西。使用offset, limit表示「讀取偏移量+限制數據集並丟棄它們的偏移量」。如果你真的想爲這樣一個大表分頁或類似的東西,你應該使用一種方法,你可以將結果限制在查詢的WHERE部分。這些類型的查詢將受益於正確的索引。

使用日期時間,解決方案可能是使用時間段來顯示數據。例如。你可以顯示每週的每一天的鏈接,並建立你的查詢,如「WHERE createDate>'2011-12-11'和crateDate <'2011-12-12'。

2

如果你有一個。唯一的列在理想情況下將它createTime本身:

SELECT "table".* 
    FROM "table" 
    INNER JOIN (
    SELECT "createTime" 
     FROM "table" 
     ORDER BY "createTime" DESC 
     LIMIT 500000, 10 
) AS "limit" ON "table"."createTime" = "limit"."createTime" 

如果createTime不是唯一的,但你有另一列,它是獨一無二的,那麼你會發現你需要創建在createTime一個綜合指數和您的另一列命令此查詢有效運行:

SELECT "table".* 
    FROM "table" 
    INNER JOIN (
    SELECT "createTime", "unique" 
     FROM "table" 
     ORDER BY "createTime" DESC 
     LIMIT 500000, 10 
) AS "limit" ON "table"."unique" = "limit"."unique" 
+1

謝謝,但這個查詢仍然需要幾秒鐘才能運行。對於一個網站來說這是不可接受的。沒有更快的方法來實現基於createTime列的分頁嗎? –

相關問題