[英]MySQL: long running LEFT JOIN query performance
一個 MySQL 數據庫包含兩個表: customer和custmomer_orders
客戶表包含 8000 萬個條目和 80 個字段。 其中一些我感興趣:
customer_orders表包含 4000 萬個條目,並且僅包含 3 個字段:
當我運行這樣的查詢時,執行大約需要800秒並返回 4000 萬個條目:
SELECT o.*
FROM customer_orders o
LEFT JOIN customer c ON (c.Id = o.Customer_Id)
WHERE NOT (ISNULL(c.Location)) AND c.Registration_Date < '2018-01-01 00:00:00';
帶有 MySQL 服務器的機器有 32GB 的 RAM,28GB 分配給 MySQL。 MySQL 版本:5.6.39。
MySQL 在具有如此多記錄的表上執行如此長時間的此類查詢是否正常? 如何提高性能?
更新:
customer_orders 表不包含我們想要存儲的任何重要數據。 這是某種復制表,其中包含過去 10 天內下的訂單。 我們每天都運行一個存儲過程,它會刪除事務范圍內超過 10 天的訂單。
有一段時間,這個存儲過程因為沒有優化查詢而超時,訂單數量每天都在增長。 上一個查詢還包含 COUNT 方法,我想這超出了超時時間。
然而,令我驚訝的是,MySQL 可能需要長達 15 分鍾才能在附加條件下獲取 40m 的記錄。
我覺得很正常。 如果您分享該查詢的explain
返回內容,將會很有幫助。
為了優化查詢,從 customer_orders 開始可能不是一個好主意,因為無論如何您都沒有對其進行過濾(因此它正在執行超過 40M 記錄的全表掃描)。 此外,正如評論中所指出的,這里不需要LEFT JOIN
。 我會這樣寫你的查詢:
SELECT o.*
FROM customers c, customer_orders o
WHERE c.id = o.Customer_Id
AND c.Location IS NOT NULL
AND c.Registration_Date < '2018-01-01'
這將(取決於多條記錄如何滿足條款Registration_Date < '2018-01-01'
)篩選customers
第一個表,然后用加入customer_orders
其中有表和索引的customer_id
另外,可能不相關,但是查詢返回 40M 記錄對您來說是否正常? 我的意思是,這就像整個customer_orders
表。 如果我是對的,這意味着所有訂單都來自“2018-01-01”之前注冊的客戶
這是太渴望評論了...
關於您的查詢,首先要注意的是它實際上並未執行LEFT JOIN
,因為它在WHERE
子句中具有引用LEFT JOIN
ed 表的條件。
可以改寫為:
SELECT o.*
FROM customer_orders o
INNER JOIN customer c
ON c.Id = o.Customer_Id
AND c.Location is NOT NULL
AND c.Registration_Date < '2018-01-01 00:00:00';
明確連接類型更有利於可讀性,並且可能有助於 MySQL 為查詢找到更好的執行路徑。
在性能方面,基本建議是,對於此查詢,您需要在所有被搜索的三列上建立一個復合索引,其順序與查詢中使用的列相同(通常,您想放置更多開始時的限制條件,因此您可能需要對此進行調整):
ALTER TABLE mytable ADD INDEX (Id, Location, Registration_Date );
有關性能的更多建議,您可能希望使用CREATE TABLE
的CREATE TABLE
語句和查詢的執行計划來更新您的問題。
如果我的評論和 GMB 的回答最終對性能沒有太大幫助; 您可以隨時嘗試使用不同的方法編寫查詢。 我通常更喜歡連接到子查詢,但有時它們會成為處理數據的最佳選擇。
由於您已經說過與訂單表相比,客戶表相對較大,這可能是其中一種情況。
SELECT o.*
FROM customer_orders AS o
WHERE o.Customer_Id IN (
SELECT Id
FROM customer
WHERE Location IS NOT NULL
AND Registration_Date < '2018-01-01 00:00:00'
);
我想發表評論,但改變主意要回答。
因為主要問題是您的問題本身。
我不知道你的customer_orders
有多少列,但如果你得到
4000 萬個條目
背部。 我會說你做錯了什么。 可能這不是查詢本身很慢,而是數據獲取。
為了證明嘗試對您的查詢執行EXPLAIN
:
EXPLAIN SELECT ...your query here... ;
然后執行
EXPLAIN SELECT ...your query here... LIMIT 1;
嘗試將結果LIMIT
為 1000,例如:
SELECT ...your query here... LIMIT 1000;
當您有這些查詢的答案、輸出和統計數據時,我們可以討論您的以下步驟。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.