[英]How would I make this query run faster?
我怎樣才能使這個查詢運行得更快......?
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
提前致謝:)
解釋查詢結果:
我真的沒有設置任何外鍵...我試圖避免對數據庫進行更改,因為很快就必須進行全面檢修。
只有主鍵是每個表的 id,例如 account_id、ftp_id、ppc_id...
索引
您需要 -至少- 在JOIN
條件中使用的每個字段的索引。
出現在WHERE
或GROUP BY
或ORDER BY
子句中的字段索引在大多數情況下也很有用。
當在一個表中,兩個或多個字段用於 JOIn(或 WHERE 或 GROUP BY 或 ORDER BY)時,這些(兩個或多個)字段的復合(組合)索引可能比單獨的索引更好。 例如,在SiteNumbers
表中,可能的索引是復合(number_accountid, number_active)
或(number_active, number_accountid)
。
Boolean(開/關,活動/非活動)字段中的條件有時會減慢查詢速度(因為索引不是選擇性的,因此不是很有幫助)。 在這種情況下,重組(父親規范化)表是一種選擇,但您可能可以避免增加的復雜性。
除了通常的建議(檢查 EXPLAIN 計划,在需要的地方添加索引,測試查詢的變體),
我注意到在您的查詢中有一個部分笛卡爾積。 表Accounts
與三個表FTPDetails
、 SiteNumbers
和PPC
具有一對多的關系。 例如,如果您有 1000 個帳戶,並且每個帳戶都與 10 個 FTPDetails、20 個 SiteNumbers 和 3 個 PPC 相關,則查詢將為每個帳戶返回 600 行(10x20x3 的乘積)。 總共有 600K 行,其中重復了許多數據。
您可以將查詢拆分為三加一以獲取基本數據(帳戶和 rest 表)。 這樣,只會傳輸 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)
使用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
這使得查詢更具可讀性,因為連接條件接近正在連接的表的名稱。
解釋,對不同的選項進行基准測試。 對於初學者,我確信有幾個查詢會比這個怪物更快。 首先,因為查詢優化器將花費大量時間檢查最佳連接順序(5.=120 種可能性),其次,像SELECT... WHERE....active = 'active'
這樣的查詢將被緩存(盡管這取決於數據更改的數量)。
您的主要問題之一在這里: x.y_active = 'active'
問題:基數低
活動字段是具有 2 個可能值的 boolean 字段,因此它的基數非常低。 MySQL(或任何 SQL 在 30% 或更多的行具有相同值時不會使用索引)。
強制索引是無用的,因為它會使您的查詢變慢,而不是更快。
解決方案:對表進行分區
一種解決方案是在active
列上對表進行分區。
這將排除所有非活動字段,並使select
的行為就像您實際上在xxx-active
字段上有一個工作索引一樣。
邊注
請永遠不要使用隱式where
連接,它太容易出錯並且無法使用。
請改用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.ZDFC35FDC70D2E298
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.