大家好舟误,我是 V 哥葡秒,上周跟一個哥們吃飯,技術(shù)人在一起嵌溢,你知道的眯牧,沒聊上一會兒,就轉(zhuǎn)到技術(shù)問題探討上了赖草,其中聊到數(shù)據(jù)庫子查詢的問題印象深刻学少,回來整理了以下10個案例說明不使用子查詢的問題,分享給大家秧骑。
首先版确,來說一下在MySQL中扣囊,不推薦使用子查詢和JOIN的原因,主要有以下幾點:
性能問題:子查詢在執(zhí)行時绒疗,MySQL需要創(chuàng)建臨時表來存儲內(nèi)層查詢的結(jié)果侵歇,查詢完畢后再刪除這些臨時表,這會增加CPU和IO資源的消耗吓蘑,產(chǎn)生慢查詢惕虑。JOIN操作本身效率也是硬傷,特別是當數(shù)據(jù)量很大時士修,性能難以保證枷遂。
索引失效:子查詢可能導(dǎo)致索引失效,因為MySQL會將查詢強行轉(zhuǎn)換為聯(lián)接來執(zhí)行棋嘲,這使得子查詢不能首先被執(zhí)行酒唉,如果外表很大,性能上會出問題沸移。
查詢優(yōu)化器的復(fù)雜度:子查詢會影響查詢優(yōu)化器的判斷痪伦,導(dǎo)致不夠優(yōu)化的執(zhí)行計劃。相比之下雹锣,聯(lián)表查詢更容易被優(yōu)化器理解和處理网沾。
數(shù)據(jù)傳輸開銷:子查詢可能導(dǎo)致大量不必要的數(shù)據(jù)傳輸,因為每個子查詢都需要將結(jié)果返回給主查詢蕊爵,而聯(lián)表查詢則可以通過一次查詢返回所需的所有數(shù)據(jù)辉哥,減少數(shù)據(jù)傳輸?shù)拈_銷。
維護成本:使用JOIN寫的SQL語句在修改表的schema時比較復(fù)雜攒射,成本較大醋旦,尤其是在系統(tǒng)較大時,不易維護会放。
針對這些原因饲齐,可以采取以下解決方案:
應(yīng)用層關(guān)聯(lián):在業(yè)務(wù)層單表查詢出數(shù)據(jù)后,作為條件給下一個單表查詢咧最,減少數(shù)據(jù)庫層的負擔捂人。
使用IN代替子查詢:如果子查詢結(jié)果集比較小,可以考慮使用“IN”操作符進行查詢矢沿,這在數(shù)據(jù)量較小的情況下滥搭,查詢效率更高。
使用WHERE EXISTS:WHERE EXISTS是一種比“IN”更好的方案咨察,它會檢查子查詢是否返回結(jié)果集论熙,查詢速度能夠明顯提高。
改寫為JOIN:使用JOIN查詢來替代子查詢摄狱,不需要建立臨時表脓诡,速度更快无午,如果查詢中使用索引,性能會更好祝谚。
接下來宪迟,V 哥通過10個案例來直觀的介紹一下。
案例1:查詢所有有庫存的商品信息交惯。
- 原始查詢(使用子查詢):查詢字段太多次泽,就用*號替代了哈,不用在意席爽,實際項目中肯定是不這樣使用的意荤。
SELECT * FROM products WHERE id IN (SELECT product_id FROM inventory WHERE stock > 0);
這個查詢會導(dǎo)致查詢速度慢,影響用戶體驗只锻。
- 優(yōu)化方案(使用EXISTS):
SELECT * FROM products WHERE EXISTS (SELECT 1 FROM inventory WHERE inventory.product_id = products.id AND inventory.stock > 0);
這個優(yōu)化方案可以大幅提升查詢速度玖像,改善用戶體驗。
案例2:使用EXISTS優(yōu)化子查詢
原始查詢:
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
優(yōu)化方案:
SELECT * FROM orders WHERE EXISTS (SELECT 1 FROM customers WHERE orders.customer_id = customers.customer_id AND customers.country = 'USA');
使用EXISTS
代替IN
子查詢可以減少回表查詢的次數(shù)齐饮,提高查詢效率捐寥。
案例3:使用JOIN代替子查詢
原始查詢:
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
優(yōu)化方案:
SELECT o.* FROM orders o JOIN customers c ON o.customer_id = c.customer_id WHERE c.country = 'USA';
使用JOIN代替子查詢可以減少子查詢的開銷,并且更容易利用索引祖驱。
案例4:優(yōu)化子查詢以減少數(shù)據(jù)量
原始查詢:
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);
限制子查詢返回的數(shù)據(jù)量握恳,減少主查詢需要檢查的行數(shù),提高查詢效率捺僻。
案例5:使用索引覆蓋
原始查詢:
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)建索引乡洼,使得子查詢可以直接在索引中找到數(shù)據(jù),避免回表查詢匕坯。
案例6:使用臨時表優(yōu)化復(fù)雜查詢
原始查詢:
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);
對于復(fù)雜的子查詢就珠,使用臨時表存儲中間結(jié)果,簡化查詢并提高性能醒颖。
案例7:使用窗口函數(shù)替代子查詢
原始查詢:
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ù)替代子查詢,提高查詢效率壳炎。
案例8:優(yōu)化子查詢以避免全表掃描
原始查詢:
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)建索引泞歉,避免全表掃描,提高子查詢效率匿辩。
案例9:使用LIMIT子句限制子查詢返回數(shù)據(jù)量
原始查詢:
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
子句限制子查詢返回的數(shù)據(jù)量腰耙,減少主查詢需要處理的數(shù)據(jù)量,提高查詢效率铲球。
案例10:使用JOIN代替子查詢以利用索引
原始查詢:
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代替子查詢挺庞,并且可以更容易地利用products
表上的category
索引。
這些案例展示了如何通過不同的優(yōu)化策略來提升MySQL查詢性能稼病,特別是在處理子查詢時选侨。
最后
通過上述分析和案例掖鱼,我們可以看到,在實際業(yè)務(wù)場景中援制,替代子查詢和JOIN的高效編程方法能夠在不同場景下顯著提升MySQL數(shù)據(jù)庫的查詢性能戏挡。在實際應(yīng)用中,應(yīng)根據(jù)具體業(yè)務(wù)需求和數(shù)據(jù)特點晨仑,靈活選擇合適的優(yōu)化方案褐墅。關(guān)注威哥愛編程,癡迷技術(shù)咱是認真滴洪己。官人妥凳,都看到這了,高低點個贊再走唄答捕,V 哥感謝你的支持逝钥。