2017-02-15 25 views
0

比方說,我有三個表格 - 用戶,服務器和付款。每個用戶可以有多個服務器,每個服務器可以有多個支付。我們還想說,我想查找最近的付款並獲取有關付款所附的服務器/客戶的信息。下面是一個查詢,可以這樣做:JOINs以奇怪的順序完成;弄亂了ORDER BY?

SELECT * 
FROM payments p 
JOIN customers c ON p.custID = c.custID 
JOIN servers s ON s.serverID = p.serverID 
WHERE c.hold = 0 
    AND c.archive = 0 
ORDER BY p.paymentID DESC 
LIMIT 10; 

的問題是,當我運行此查詢我得到這個解釋一下:

id select_type table type possible_keys   key    key_len ref     rows  Extra 
1 SIMPLE  c  ref PRIMARY,hold_archive  hold_archive  3   const,const   28728 Using where; Using index; Using temporary; Using filesort 
1 SIMPLE  p  ref custID     custID    5   customers.custID 3  Using where 
1 SIMPLE  s  eq_ref PRIMARY     PRIMARY   4   payments.serverID 1  Using index 

的問題是,查詢需要一段時間才能運行。如果我刪除了ORDER BY,它就變成10倍。但我需要ORDER BY。這裏的EXPLAIN當我刪除ORDER BY:

id select_type table type possible_keys   key    key_len ref     rows  Extra 
1 SIMPLE  c  ref PRIMARY,hold_archive  hold_archive  3   const,const   28728 Using where; Using index 
1 SIMPLE  p  ref custID     custID    5   customers.custID 3  Using where 
1 SIMPLE  s  eq_ref PRIMARY     PRIMARY   4   payments.serverID 1  Using index 

因此,這裏最大的區別是,「使用臨時」和「使用文件排序」是從Extra列缺。

在這種情況下,似乎是因爲我在執行ORDER BY的列不是EXPLAIN中的第一列。

另一種觀察。如果我刪除其中一個WHERE子句(同時保留ORDER BY),它會加速類似,但我需要兩個地方。下面是一個例子的解釋:

id select_type table type possible_keys   key    key_len ref     rows  Extra 
1 SIMPLE  p  index custID,serverID   PRIMARY   4   NULL    10  Using where 
1 SIMPLE  c  eq_ref PRIMARY,hold_archive  PRIMARY   4   payments.custID  1  Using where 
1 SIMPLE  s  eq_ref PRIMARY     PRIMARY   4   payments.serverID 1  Using index 

這裏的ORDER BY列/是/正在/在EXPLAIN的第一列完成。但是,爲什麼MySQL重新安排表加入的順序,我怎樣才能做到這一點,所以它不這樣做?你可以強制索引在MySQL中,但它似乎不會幫助..

任何想法?

+0

有了這樣的問題,您還需要爲所有相關表提供SHOW CREATE TABLE語句 – Strawberry

+1

快速猜測:如果沒有ORDER BY子句,則服務器會返回符合條件的前10條記錄,一旦達到該數字就停止處理。它可能以'customer'表開始,因爲這個表上有一個過濾器,然後查找相關的'payments',然後在'servers'上查找相匹配的。工作得很好。然而,當你添加'ORDER BY'時,首先需要創建一個* all *匹配記錄的列表('c' =>'p' =>'s'),然後將'paymentID'然後從該列表中選擇從「最低」開始的前10個。 – deroby

回答

1

快10倍 - 它可以找到「任何10行」比「找到所有可能的行,排序它們,然後交付10」快得多。

WHEREORDER BY命中不同的列很難優化。

付款的百分比是多少hold=0 and archive=0?這聽起來像一小部分?每個表中有多少行?

還有什麼需要INDEX(hold, archive)?如果沒有,請擺脫它。這似乎只是在這裏造成麻煩。

如果hold=0 and archive=0是常見的,那麼您寧願執行就像您的第3個EXPLAIN - 這是掃描payments降序。其中大多數匹配WHERE,它會通常`找到10匹配行之前需要打不超過10行。

另一種解決方案(除去索引除外)是在查詢中將JOIN更改爲STRAIGHT_JOIN。這告訴優化器,你知道的更好,並且payments應該先被掃描,customers秒。如果我以前的段落適用,那很好。

但是,如果你尋找archive=1,查詢就會搞砸了(通過變慢)。