2011-06-30 120 views
4

我該如何讓這個查詢運行得更快......?我如何使這個查詢運行得更快?

 
SELECT account_id, 
      account_name, 
      account_update, 
      account_sold, 
      account_mds, 
      ftp_url,   
      ftp_livestatus, 
      number_digits, 
      number_cw, 
      client_name, 
      ppc_status, 
      user_name 
FROM  
     Accounts, 
     FTPDetails, 
     SiteNumbers, 
     Clients, 
     PPC, 
     Users 

WHERE Accounts.account_id = FTPDetails.ftp_accountid 
AND  Accounts.account_id = SiteNumbers.number_accountid 
AND  Accounts.account_client = Clients.client_id  
AND  Accounts.account_id = PPC.ppc_accountid 
AND  Accounts.account_designer = Users.user_id 
AND  Accounts.account_active = 'active' 
AND  FTPDetails.ftp_active = 'active' 
AND  SiteNumbers.number_active = 'active' 
AND  Clients.client_active = 'active'  
AND  PPC.ppc_active = 'active' 
AND  Users.user_active = 'active' 
ORDER BY 
     Accounts.account_update DESC 

感謝提前:)

EXPLAIN查詢結果:

first part of table

second part of table

我真的沒有任何外鍵設置...我試圖避免對數據庫進行修改,因爲它不得不完成修改即將進行大修。

只有主鍵是每個表的ID例如account_id,ftp_id,ppc_id ...

+1

你有什麼指標在桌子上? –

+1

發佈您的索引和EXPLAIN輸出供人們評估。否則,他們只會猜測。 – jishi

+1

...和EXPLAIN計劃以及每個表的行數和索引的基數 – symcbean

回答

3

使用EXPLAIN找出可以使用哪個索引以及實際使用哪個索引。必要時創建一個適當的索引。

如果FTPDetails.ftp_active只有兩個有效條目'active''inactive',請使用BOOL作爲數據類型。

作爲一個方面說明:我強烈使用明確的建議加入的,而不是含蓄的:

SELECT 
    account_id, account_name, account_update, account_sold, account_mds, 
    ftp_url, ftp_livestatus, 
    number_digits, number_cw, 
    client_name, 
    ppc_status, 
    user_name 
FROM Accounts 
INNER JOIN FTPDetails 
    ON Accounts.account_id = FTPDetails.ftp_accountid 
    AND FTPDetails.ftp_active = 'active' 
INNER JOIN SiteNumbers 
    ON Accounts.account_id = SiteNumbers.number_accountid 
    AND SiteNumbers.number_active = 'active' 
INNER JOIN Clients 
    ON Accounts.account_client = Clients.client_id 
    AND Clients.client_active = 'active' 
INNER JOIN PPC 
    ON Accounts.account_id = PPC.ppc_accountid 
    AND PPC.ppc_active = 'active' 
INNER JOIN Users 
    ON Accounts.account_designer = Users.user_id 
    AND Users.user_active = 'active' 
WHERE Accounts.account_active = 'active' 
ORDER BY Accounts.account_update DESC 

這使得查詢更加易讀,因爲聯接條件是接近被加入了表的名稱。

+0

感謝那2秒更快:) 我跑瞭解釋,但不知道信息實際告訴我什麼?或如何使用它... – JPickup

+0

@JPickup:在這裏發佈解釋計劃,將其添加到問題中。 –

0

說明,基準不同的選項。對於初學者來說,我確信有幾個查詢會比這個怪物更快。首先,因爲查詢優化器將花費大量時間來檢查什麼連接順序是最好的(5!= 120個可能性)。其次,像SELECT ... WHERE ....active = 'active'這樣的查詢將被緩存(儘管它取決於數據量的變化)。

+0

到目前爲止,我一直在使用多個語句,但我被要求爲用戶添加函數以便按任意值篩選結果......並且不知道如何在不選擇所有數據的情況下執行此操作的方法選擇語句? – JPickup

+0

良好的優化器不會檢查所有的可能性 - 對於這個查詢來說,這將遠遠超過120(這不僅是JOIN的順序,而且還包括每個JOIN使用什麼方法以及使用什麼索引以及檢查條件的順序)。 –

+0

@ypercube好的優化器是[可配置的](http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_optimizer_search_depth)。 – DrTyrsa

4

指標

  • 你需要 - 至少 - 對在一個JOIN條件下使用的每個字段的索引。

  • 出現在WHEREGROUP BYORDER BY子句中的字段上的索引大部分時間也很有用。

  • 當在一個表中JOIN(或WHERE或GROUP BY或ORDER BY)中使用兩個或更多字段時,這些(兩個或更多)字段的複合(組合)索引可能比獨立索引更好。例如在SiteNumbers表中,可能的索引是化合物(number_accountid, number_active)(number_active, number_accountid)

  • 布爾型(ON/OFF,活動/非活動)字段中的條件有時會減慢查詢速度(因爲索引不具有選擇性,因此不是很有用)。在這種情況下,重構(父親正常化)表格是一種選擇,但可能可以避免增加的複雜性。


除了一般的建議(檢查解釋計劃,增加在需要的索引,查詢的測試變化),

我注意到,在您的查詢存在部分笛卡爾乘積。表Accounts與三個表FTPDetailsSiteNumbersPPC有一對多的關係。這樣做的結果是,如果您有例如1000個帳戶,並且每個帳戶與10個FTPDetails,20個SiteNumbers和3個PPC相關,則每個帳戶600行(10x20x3的產品)將返回查詢。共有600K行,其中有許多數據被複制。

您可以改爲將基本數據(帳戶和其他表)的查詢拆分爲三加一。這樣,只有34K行數據(具有較小的長度)的將被轉移:

Accounts JOIN Clients JOIN Users 
    (with all fields needed from these tables) 
    1K rows 

Accounts JOIN FTPDetails 
    (with Accounts.account_id and all fields from FTPDetails) 
    10K rows 

Accounts JOIN SiteNumbers 
    (with Accounts.account_id and all fields from SiteNumbers) 
    20K rows 

Accounts JOIN PPC 
    (with Accounts.account_id and all fields from PPC) 
    3K rows 

,然後使用從在客戶端側的4和查詢數據,以顯示組合的信息。



我想補充以下指標:

Table Accounts 
    index on (account_designer) 
    index on (account_client) 
    index on (account_active, account_id) 
    index on (account_update) 

Table FTPDetails 
    index on (ftp_active, ftp_accountid) 

Table SiteNumbers 
    index on (number_active, number_accountid) 

Table PPC 
    index on (ppc_active, ppc_accountid) 
+0

爲什麼不是 '表客戶端 index(client_id,client_active)'和'Table Users index(user_id,user_active)'? – Ron

+1

@sunrong我不記得爲什麼我沒有爲「客戶端」和「用戶」添加任何索引建議。重讀我的回答和問題,我認爲(客戶和用戶)的處理方式不同,因爲他們似乎與帳戶有一對一的關係,而不是一對多。索引也應該有幫助。 –

0

你的一個主要問題是在這裏:x.y_active = 'active'

問題:低基數
有源現場是一個帶有2個可能值的布爾型字段,因此它具有非常低的基數。 MySQL(或任何有關此問題的SQL在30%或更多行具有相同值時不會使用索引)。
強制索引是無用的,因爲它會讓你的查詢更慢,而不是更快。

解決方案:你的分區表
一種解決方案是在active列分區你的表。
這會排除所有非活動字段的考慮因素,並會使select的行爲就好像您實際上在xxx-active字段中具有工作索引一樣。

旁註
請永遠不要使用隱where連接,它太容易出錯,consufing是有用的。
改爲使用類似Oswald's answer的語法。

鏈接:
基數:http://en.wikipedia.org/wiki/Cardinality_(SQL_statements)
基數和索引:http://www.bennadel.com/blog/1424-Exploring-The-Cardinality-And-Selectivity-Of-SQL-Conditions.htm
MySQL分區:http://dev.mysql.com/doc/refman/5.5/en/partitioning.html

+0

是否有任何書籍/閱讀材料,你會建議在數據庫設計和SQL語句? – JPickup