2011-03-05 124 views
1

在我的Web應用程序中,我製作了一個內部消息傳遞系統。我想在每個頁面上放置一個'上一個'和'下一個'鏈接(用戶在查看郵件的地方)。在MySQL中優化ORDER BY LIMIT查詢

爲了獲得下一個和以前的ID我執行兩個查詢:

對於前一個:

SELECT id FROM pages WHERE (id<$requestedPageId) ORDER BY id DESC LIMIT 1

併爲下一個:

SELECT id FROM pages WHERE (id>$requestedPageId) ORDER BY id LIMIT 1

EXPLAIN說查詢類型是「範圍」,行列表示它將檢查所有行小於或大於頁面的id(大數字)。 Extra行說「使用where」。

看來MySQL忽略了我只需要一行。 MySQL是否足夠聰明,可以優化這種查詢,這樣它就可以找到頁面的行並搜索第一個匹配的行。

有沒有更好的方法來獲取下一頁和上一頁的ID?

其他注意事項:

  • 這個問題似乎在每一個ORDER BY限制類型的查詢存在(例如:當我分裂一長串多頁。)。
  • Where子句不是這麼簡單(我想讓用戶訪問他有權訪問的下一個/上一個頁面,儘管沒有連接)
  • 所有列出現在WHERE索引(id是主鍵)
  • 變量被保護以防止注入。

EDIT1:

所以我目前使用的查詢:

SELECT id 
FROM reports 
WHERE (id<$requestedPageId) AND ((isPublic=1) OR (recipientId=$recipient)) 
ORDER BY id DESC 
LIMIT 1 

或當我重新因素它作爲回答說:

SELECT MAX(id) 
FROM reports 
WHERE (id<$requestedPageId) AND ((isPublic=1) OR (recipientId=$recipient)) 

回答

3

對於前面

SELECT MAX(id) FROM pages WHERE id<$requestPageId 

並且接下來

SELECT MIN(id) FROM pages WHERE id>$requestedPageId 
+0

它優化了這個簡單情況下的表格。但只要我在where子句中添加一個附加條件,它就會檢查所有行。 (EXPLAIN類型將全部)。我要編輯我的原始文章,並將其放入我正在使用的查詢中。 – Calmarius 2011-03-05 12:19:35

+0

您是否在isPublic和recipientId上設置了索引? – 2011-03-05 13:20:52

1

數據庫的行爲與預期相同。您的查詢是一個範圍查詢,因爲符號較少(編號爲< $ requestedPageId)。 OR語句使得使用單個索引查找結果變得更加困難。而排序結果意味着它必須得到所有匹配的行才能執行排序,即使你只需要1行。

您無法將其作爲「常量」類型查詢,但您可以使用索引,子查詢和/或聯合語句對其進行優化。

下面是一個查詢來統治他們。我並不是說這是最好的解決方案,而只是解決問題的一種方法。首先,如果您創建兩個索引,一個用於recipientId,另一個用於isPublic,則此查詢效果更好。

SELECT 
GREATEST(
    (SELECT MAX(id) FROM reports 
    WHERE id < $requestedPageId AND recipientId = $recipient), 
    (SELECT MAX(id) FROM reports 
    WHERE id < $requestedPageId AND isPublic = 1) 
) AS prev_id 
LEAST(
    (SELECT MIN(id) FROM reports 
    WHERE id > $requestedPageId AND recipientId = $recipient), 
    (SELECT MIN(id) FROM reports 
    WHERE id > $requestedPageId AND isPublic = 1) 
) AS next_id