2016-11-25 57 views
0

我如何提高性能這個查詢,同時還獲得所需的所有信息..如何提高SQL查詢多個連接表的性能

SELECT 
    tr.id, tr.request_status, tr.note, tr.created_date, 
    c.name AS customer_name, c.mobile_phONe, 
    u.full_name AS created_by_name, tt.name AS ticket_type_name 
FROM 
    ticket_request tr 
LEFT JOIN 
    ticket_type tt ON tt.id = tr.ticket_type_id 
LEFT JOIN 
    users u ON u.id = tr.created_by 
LEFT JOIN 
    customer c ON c.id = tr.customer_id 
WHERE 
    tr.is_deleted != 1 
    AND tr.user_id IN (SELECT u.id FROM users u WHERE u.status = '1') 
GROUP BY 
    tr.id 
ORDER BY 
    tr.created_date DESC 
LIMIT 0,20 

目前,該查詢在7-10秒內運行。

  • ticket_request表有大約10萬行
  • customers表有300K左右行
  • usersticket_type沒有那麼多(約1K行)
+0

添加索引到所有的連接列。你已經做過了嗎? –

+1

我刪除了不兼容的數據庫標記。爲您實際使用的數據庫添加標籤。 –

+0

@TimBiegeleisen是的,我已經完成 –

回答

1

下面的加速技術是免除LIMIT第一個,只有在那之後,再做所有的JOINs

SELECT tr3.id, tr3.request_status, tr3.note, tr3.created_date, 
     c.name AS customer_name, c.mobile_phONe, 
     u2.full_name AS created_by_name, 
     tt.name AS ticket_type_name 
    FROM 
    (
     SELECT tr1.id 
      FROM ticket_request tr1 
      JOIN users u1 ON u1.id = tr1.created_by 
      WHERE u1.status = '1' 
       AND tr1.is_deleted != 1 
      ORDER BY tr1.created_date DESC 
      LIMIT 0,20 
    ) AS tr2 
    JOIN ticket_request AS tr3 ON tr3.id = tr2.id 
    JOIN user AS u2 ON u2.id = tr3.created_by 
    LEFT JOIN ticket_type tt ON tt.id = tr3.ticket_type_id 
    LEFT JOIN customer c ON c.id = tr3.customer_id 
    ORDER BY tr3.created_date 

JOINs,所述一箇中的 「衍生自」 表TR2,都在觸摸只有20行之後;這是加速的很大一部分。

這可能是一樣好:

SELECT d.id, d.request_status, d.note, d.created_date, 
     c.name AS customer_name, c.mobile_phONe, d.created_by_name, 
     tt.name AS ticket_type_name 
    FROM 
    (
     SELECT tr.id AS tr_id, tr.request_status, tr.note, tr.created_date, 
       tr.ticket_type_id, tr.customer_id 
       u.full_name AS created_by_name 
      FROM ticket_request tr 
      JOIN users u ON u.id = tr.created_by 
      WHERE u.status = '1' 
       AND tr.is_deleted != 1 
      ORDER BY tr.created_date DESC 
      LIMIT 0,20 
    ) AS d 
    LEFT JOIN ticket_type tt ON tt.id = d.ticket_type_id 
    LEFT JOIN customer c ON c.id = d.customer_id 
    ORDER BY d.created_date 
+0

我還沒有嘗試過,但我認爲如果你把LIMIT置於頂端,那麼在LIMIT上限查詢中的某些滿意結果不能滿足較低的條件,那麼整個查詢的結果可能小於20行對。 –

+0

@VinhDatHa - 請說明「put on top」和「upper」是什麼意思。我想到了「SELECTs」和「outer」和「inner」或「derived」。 (「派生」)是這種「子查詢」的技術術語。 –

+0

好吧,我想我現在明白了,謝謝 –

0

我假設你正在使用MySQL。如果不是,這個答案可以稍微修改以適應另一個數據庫,但這個概念應該保持不變。您ticket_request表之間

ALTER TABLE ticket_type ADD INDEX (id); 
ALTER TABLE users ADD INDEX (id); 
ALTER TABLE customer ADD INDEX (id);  -- important 

要解釋爲什麼指數會有所幫助,考慮第一LEFT JOIN:您可以添加索引,其涉及您的左邊的右邊與ticket_request列加入所有的ID列ticket_type表。如果沒有索引,對於ticket_request中的每條記錄,數據庫將不得不掃描整個ticket_type表以查找與連接條件相匹配的記錄。從性能角度來看,這是昂貴的。但是對於索引,數據庫可以更快地完成此操作,因爲它「知道」匹配記錄的準確位置(或幾乎完全匹配)。

雖然您提到只有customer表非常大,但您仍可以將索引添加到其他表中。未來,他們可能會變得更大。涉及customer的加入很可能是您查詢中的瓶頸。

+0

是的,我正在使用MySQL。我假設主要是默認索引,對吧? 而且我也索引了所有需要的外鍵。 –

+0

@VinhDatHa我爲你添加了MySQL標籤。儘管如此,如果你首先做到這一點,情況會更有意義。 –

0

這裏的優化最大的機會是LIMIT 0,20

  1. ​​是沒有意義的,應予刪除。

  2. create index ticket_request_ix_is_deleted_created_date on ticket_request (is_deleted,created_date) and change tr.is_deleted != 1 to tr.is_deleted = 0

    或者

    create index ticket_request_ix_created_date on ticket_request (created_date)

0
SELECT 
    tr.id, tr.request_status, tr.note, tr.created_date, 
    c.name AS customer_name, c.mobile_phONe, 
    u.full_name AS created_by_name, tt.name AS ticket_type_name 
FROM 
    ticket_request tr 
LEFT JOIN 
    ticket_type tt ON tt.id = tr.ticket_type_id and tr.is_deleted != 1 
LEFT JOIN 
    users u ON u.id = tr.created_by 
JOIN 
    users u1 ON u1.id = tr.user_id and u1.status = '1' 
LEFT JOIN 
    customer c ON c.id = tr.customer_id 
GROUP BY 
    tr.id 
ORDER BY 
    tr.created_date DESC 
LIMIT 0,20 

嘗試這一點,將與更好的性能工作,調整爲按您的要求

+0

這會給出錯誤的結果。 –

-1

比索引其他,在應用層上可以使用的Memcached(如果你使用PHP)喜歡的東西。這也會給你很好的表現。