MySQL不使用子查詢(xún)的原因及優(yōu)化案例
不推薦使用子查詢(xún)和JOIN的原因
在MySQL中,不推薦使用子查詢(xún)和JOIN主要有以下原因:
- 性能問(wèn)題:子查詢(xún)執(zhí)行時(shí),MySQL需創(chuàng)建臨時(shí)表存儲(chǔ)內(nèi)層查詢(xún)結(jié)果,查詢(xún)完再刪除,增加CPU和IO資源消耗,易產(chǎn)生慢查詢(xún)。JOIN操作效率也較低,尤其數(shù)據(jù)量大時(shí),性能難保證。
- 索引失效:子查詢(xún)可能使索引失效,MySQL會(huì)將查詢(xún)轉(zhuǎn)為聯(lián)接執(zhí)行,子查詢(xún)不能先執(zhí)行,若外表大,性能受影響。
- 查詢(xún)優(yōu)化器復(fù)雜度:子查詢(xún)影響查詢(xún)優(yōu)化器判斷,致執(zhí)行計(jì)劃不夠優(yōu)化。相比之下,聯(lián)表查詢(xún)更易被優(yōu)化器理解和處理。
- 數(shù)據(jù)傳輸開(kāi)銷(xiāo):子查詢(xún)可能致大量不必要數(shù)據(jù)傳輸,每個(gè)子查詢(xún)都需將結(jié)果返回給主查詢(xún)。而聯(lián)表查詢(xún)可通過(guò)一次查詢(xún)返回所有所需數(shù)據(jù),減少數(shù)據(jù)傳輸開(kāi)銷(xiāo)。
- 維護(hù)成本:使用JOIN寫(xiě)的SQL語(yǔ)句,在修改表schema時(shí)較復(fù)雜,成本大,尤其系統(tǒng)大時(shí),不易維護(hù)。
解決方案
針對(duì)這些問(wèn)題,可采取以下解決方案:
- 應(yīng)用層關(guān)聯(lián):在業(yè)務(wù)層單表查詢(xún)出數(shù)據(jù)后,作為條件給下一個(gè)單表查詢(xún),減少數(shù)據(jù)庫(kù)層負(fù)擔(dān)。
- 使用IN代替子查詢(xún):若子查詢(xún)結(jié)果集小,可用“IN”操作符查詢(xún),數(shù)據(jù)量小時(shí),查詢(xún)效率更高。
- 使用WHERE EXISTS:WHERE EXISTS比“IN”更好,它檢查子查詢(xún)是否返回結(jié)果集,能明顯提高查詢(xún)速度。
- 改寫(xiě)為JOIN:用JOIN查詢(xún)替代子查詢(xún),無(wú)需建立臨時(shí)表,速度快,若查詢(xún)中用索引,性能更好。
優(yōu)化案例
案例1:查詢(xún)所有有庫(kù)存的商品信息
原始查詢(xún)(使用子查詢(xún)):
SELECT * FROM products WHERE id IN (SELECT product_id FROM inventory WHERE stock > 0);
此查詢(xún)會(huì)導(dǎo)致查詢(xún)速度慢,影響用戶(hù)體驗(yàn)。
優(yōu)化方案(使用EXISTS):
SELECT * FROM products WHERE EXISTS (SELECT 1 FROM inventory WHERE inventory.product_id = products.id AND inventory.stock > 0);
該優(yōu)化方案可大幅提升查詢(xún)速度,改善用戶(hù)體驗(yàn)。
案例2:使用EXISTS優(yōu)化子查詢(xún)
原始查詢(xún):
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
使用EXISTS代替IN子查詢(xún)可減少回表查詢(xún)次數(shù),提高查詢(xún)效率。
案例3:使用JOIN代替子查詢(xún)
原始查詢(xún):
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
使用JOIN代替子查詢(xún)可減少子查詢(xún)開(kāi)銷(xiāo),且更容易利用索引。
案例4:優(yōu)化子查詢(xún)以減少數(shù)據(jù)量
原始查詢(xún):
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers);
優(yōu)化方案:
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE active = 1);
限制子查詢(xún)返回?cái)?shù)據(jù)量,減少主查詢(xún)需檢查的行數(shù),提高查詢(xún)效率。
案例5:使用索引覆蓋
原始查詢(xún):
SELECT customer_id FROM customers WHERE country = 'USA';
優(yōu)化方案:
CREATE INDEX idx_country ON customers(country); SELECT customer_id FROM customers WHERE country = 'USA';
為country字段創(chuàng)建索引,使子查詢(xún)可直接在索引中找到數(shù)據(jù),避免回表查詢(xún)。
案例6:使用臨時(shí)表優(yōu)化復(fù)雜查詢(xún)
原始查詢(xún):
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE last_order_date > '2023-01-01');
優(yōu)化方案:
CREATE TEMPORARY TABLE temp_customers AS SELECT customer_id FROM customers WHERE last_order_date > '2023-01-01'; SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM temp_customers);
對(duì)于復(fù)雜子查詢(xún),用臨時(shí)表存儲(chǔ)中間結(jié)果,簡(jiǎn)化查詢(xún)并提高性能。
案例7:使用窗口函數(shù)替代子查詢(xún)
原始查詢(xún):
SELECT employee_id, salary, (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id) AS avg_salary FROM employees e;
優(yōu)化方案:
SELECT employee_id, salary, AVG(salary) OVER (PARTITION BY department_id) AS avg_salary FROM employees;
用窗口函數(shù)替代子查詢(xún),提高查詢(xún)效率。
案例8:優(yōu)化子查詢(xún)以避免全表掃描
原始查詢(xún):
SELECT * FROM users WHERE username IN (SELECT username FROM orders WHERE order_date = '2024-01-01');
優(yōu)化方案:
CREATE INDEX idx_order_date ON orders(order_date); SELECT * FROM users WHERE username IN (SELECT username FROM orders WHERE order_date = '2024-01-01');
為order_date字段創(chuàng)建索引,避免全表掃描,提高子查詢(xún)效率。
案例9:使用LIMIT子句限制子查詢(xún)返回?cái)?shù)據(jù)量
原始查詢(xún):
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
優(yōu)化方案:
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA' LIMIT 100);
用LIMIT子句限制子查詢(xún)返回?cái)?shù)據(jù)量,減少主查詢(xún)需處理數(shù)據(jù)量,提高查詢(xún)效率。
案例10:使用JOIN代替子查詢(xún)以利用索引
原始查詢(xún):
SELECT * FROM transactions WHERE product_id IN (SELECT product_id FROM products WHERE category = 'Equity');
優(yōu)化方案:
SELECT t.* FROM transactions t JOIN products p ON t.product_id = p.product_id WHERE p.category = 'Equity';
用JOIN代替子查詢(xún),并可更容易利用products表上category索引。
總結(jié)
這些案例展示了如何通過(guò)不同優(yōu)化策略提升MySQL查詢(xún)性能,特別是在處理子查詢(xún)時(shí)。以下是一些額外的優(yōu)化建議:
- 創(chuàng)建合適的索引:經(jīng)常用于
WHERE和JOIN的字段應(yīng)建立索引,避免在低選擇性的字段上建立索引(如性別字段)。 - 避免索引失效的情況:使用函數(shù)計(jì)算的字段不會(huì)使用索引,如
SELECT * FROM orders WHERE YEAR(order_date) = 2023;應(yīng)優(yōu)化為SELECT * FROM orders WHERE order_date >= '2023-01-01';。 - 組合索引的最左前綴法則:確保查詢(xún)條件從組合索引的最左列開(kāi)始。
- 使用EXPLAIN分析查詢(xún)執(zhí)行計(jì)劃:通過(guò)
EXPLAIN關(guān)鍵字可以幫助我們了解查詢(xún)的執(zhí)行計(jì)劃,從而發(fā)現(xiàn)性能瓶頸。 - 優(yōu)化查詢(xún)語(yǔ)句:避免使用
SELECT *,使用LIMIT限制返回行數(shù),重寫(xiě)子查詢(xún)?yōu)镴OIN。 - 合理調(diào)整Join Buffer:在無(wú)索引或索引不可用的情況下,Join Buffer是優(yōu)化Block Nested-Loop Join的關(guān)鍵,其大小直接影響外層表加載的行數(shù)和內(nèi)層表的掃描效率。
通過(guò)這些優(yōu)化策略,可以顯著提升MySQL查詢(xún)性能,改善用戶(hù)體驗(yàn)。
以上就是MySQL不使用子查詢(xún)的原因及優(yōu)化案例的詳細(xì)內(nèi)容,更多關(guān)于MySQL不使用子查詢(xún)?cè)虻馁Y料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MySQL 中處理 BLOB 和 CLOB 數(shù)據(jù)類(lèi)型小結(jié)
在MySQL中,BLOB和CLOB 數(shù)據(jù)類(lèi)型用于存儲(chǔ)大量的二進(jìn)制數(shù)據(jù)和字符數(shù)據(jù),可以使用SQL 語(yǔ)句或編程語(yǔ)言將二進(jìn)制數(shù)據(jù)和字符數(shù)據(jù)插入到BLOB 和CLOB列中,這篇文章主要介紹了MySQL 中處理 BLOB 和 CLOB 數(shù)據(jù)類(lèi)型,需要的朋友可以參考下2025-03-03
mysql5.7.18.zip免安裝版本配置教程(windows)
這篇文章主要為大家詳細(xì)介紹了mysql5.7.18.zip安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
MySQL無(wú)法讀表錯(cuò)誤的解決方法(MySQL 1018 error)
這篇文章主要為大家詳細(xì)介紹了MySQL無(wú)法讀表錯(cuò)誤的解決方法,MySQL 1018 error如何解決?具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
MySQL千萬(wàn)級(jí)數(shù)據(jù)從190秒優(yōu)化到1秒的全過(guò)程
優(yōu)化MySQL千萬(wàn)級(jí)數(shù)據(jù)策略還是比較多的,分表分庫(kù),創(chuàng)建中間表,匯總表以及修改為多個(gè)子查詢(xún),這里討論的情況是在MySQL一張表的數(shù)據(jù)達(dá)到千萬(wàn)級(jí)別,在這樣的情況下,開(kāi)發(fā)者可以嘗試通過(guò)優(yōu)化SQL來(lái)達(dá)到查詢(xún)的目的,所以本文給大家介紹了MySQL千萬(wàn)級(jí)數(shù)據(jù)從190秒優(yōu)化到1秒的全過(guò)程2024-04-04
MySQL大表數(shù)據(jù)的分區(qū)與分庫(kù)分表的實(shí)現(xiàn)
數(shù)據(jù)庫(kù)的分區(qū)和分庫(kù)分表是兩種常用的技術(shù)方案,本文主要介紹了MySQL大表數(shù)據(jù)的分區(qū)與分庫(kù)分表的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-03-03
深入解析MySQL的事務(wù)隔離及其對(duì)性能產(chǎn)生的影響
這篇文章主要介紹了MySQL的事務(wù)隔離及其對(duì)性能產(chǎn)生的影響,在MySQL的優(yōu)化方面具有一定的借鑒意義,需要的朋友可以參考下2015-12-12

