動態

詳情 返回 返回

10個案例告訴你mysql不使用子查詢的原因 - 動態 詳情

大家好,我是 V 哥,上週跟一個哥們吃飯,技術人在一起,你知道的,沒聊上一會兒,就轉到技術問題探討上了,其中聊到數據庫子查詢的問題印象深刻,回來整理了以下10個案例説明不使用子查詢的問題,分享給大家。

首先,來説一下在MySQL中,不推薦使用子查詢和JOIN的原因,主要有以下幾點:

  1. 性能問題:子查詢在執行時,MySQL需要創建臨時表來存儲內層查詢的結果,查詢完畢後再刪除這些臨時表,這會增加CPU和IO資源的消耗,產生慢查詢。JOIN操作本身效率也是硬傷,特別是當數據量很大時,性能難以保證。
  2. 索引失效:子查詢可能導致索引失效,因為MySQL會將查詢強行轉換為聯接來執行,這使得子查詢不能首先被執行,如果外表很大,性能上會出問題。
  3. 查詢優化器的複雜度:子查詢會影響查詢優化器的判斷,導致不夠優化的執行計劃。相比之下,聯表查詢更容易被優化器理解和處理。
  4. 數據傳輸開銷:子查詢可能導致大量不必要的數據傳輸,因為每個子查詢都需要將結果返回給主查詢,而聯表查詢則可以通過一次查詢返回所需的所有數據,減少數據傳輸的開銷。
  5. 維護成本:使用JOIN寫的SQL語句在修改表的schema時比較複雜,成本較大,尤其是在系統較大時,不易維護。

針對這些原因,可以採取以下解決方案:

  1. 應用層關聯:在業務層單表查詢出數據後,作為條件給下一個單表查詢,減少數據庫層的負擔。
  2. 使用IN代替子查詢:如果子查詢結果集比較小,可以考慮使用“IN”操作符進行查詢,這在數據量較小的情況下,查詢效率更高。
  3. 使用WHERE EXISTS:WHERE EXISTS是一種比“IN”更好的方案,它會檢查子查詢是否返回結果集,查詢速度能夠明顯提高。
  4. 改寫為JOIN:使用JOIN查詢來替代子查詢,不需要建立臨時表,速度更快,如果查詢中使用索引,性能會更好。

接下來,V 哥通過10個案例來直觀的介紹一下。

案例1:查詢所有有庫存的商品信息。

  • 原始查詢(使用子查詢):查詢字段太多,就用*號替代了哈,不用在意,實際項目中肯定是不這樣使用的。
  SELECT * FROM products WHERE id IN (SELECT product_id FROM inventory WHERE stock > 0);

這個查詢會導致查詢速度慢,影響用户體驗。

  • 優化方案(使用EXISTS):

    SELECT * FROM products WHERE EXISTS (SELECT 1 FROM inventory WHERE inventory.product_id = products.id AND inventory.stock > 0);

    這個優化方案可以大幅提升查詢速度,改善用户體驗。

案例2:使用EXISTS優化子查詢

原始查詢

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');

優化方案

SELECT * FROM orders WHERE EXISTS (SELECT 1 FROM customers WHERE orders.customer_id = customers.customer_id AND customers.country = 'USA');

使用EXISTS代替IN子查詢可以減少回表查詢的次數,提高查詢效率。

案例3:使用JOIN代替子查詢

原始查詢

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');

優化方案

SELECT o.* FROM orders o JOIN customers c ON o.customer_id = c.customer_id WHERE c.country = 'USA';

使用JOIN代替子查詢可以減少子查詢的開銷,並且更容易利用索引。

案例4:優化子查詢以減少數據量

原始查詢

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers);

優化方案

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE active = 1);

限制子查詢返回的數據量,減少主查詢需要檢查的行數,提高查詢效率。

案例5:使用索引覆蓋

原始查詢

SELECT customer_id FROM customers WHERE country = 'USA';

優化方案

CREATE INDEX idx_country ON customers(country);
SELECT customer_id FROM customers WHERE country = 'USA';

country字段創建索引,使得子查詢可以直接在索引中找到數據,避免回表查詢。

案例6:使用臨時表優化複雜查詢

原始查詢

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE last_order_date > '2023-01-01');

優化方案

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);

對於複雜的子查詢,使用臨時表存儲中間結果,簡化查詢並提高性能。

案例7:使用窗口函數替代子查詢

原始查詢

SELECT employee_id, salary, (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id) AS avg_salary FROM employees e;

優化方案

SELECT employee_id, salary, AVG(salary) OVER (PARTITION BY department_id) AS avg_salary FROM employees;

使用窗口函數替代子查詢,提高查詢效率。

案例8:優化子查詢以避免全表掃描

原始查詢

SELECT * FROM users WHERE username IN (SELECT username FROM orders WHERE order_date = '2024-01-01');

優化方案

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字段創建索引,避免全表掃描,提高子查詢效率。

案例9:使用LIMIT子句限制子查詢返回數據量

原始查詢

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');

優化方案

SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA' LIMIT 100);

使用LIMIT子句限制子查詢返回的數據量,減少主查詢需要處理的數據量,提高查詢效率。

案例10:使用JOIN代替子查詢以利用索引

原始查詢

SELECT * FROM transactions WHERE product_id IN (SELECT product_id FROM products WHERE category = 'Equity');

優化方案

SELECT t.* FROM transactions t JOIN products p ON t.product_id = p.product_id WHERE p.category = 'Equity';

使用JOIN代替子查詢,並且可以更容易地利用products表上的category索引。

這些案例展示瞭如何通過不同的優化策略來提升MySQL查詢性能,特別是在處理子查詢時。

最後

通過上述分析和案例,我們可以看到,在實際業務場景中,替代子查詢和JOIN的高效編程方法能夠在不同場景下顯著提升MySQL數據庫的查詢性能。在實際應用中,應根據具體業務需求和數據特點,靈活選擇合適的優化方案。關注威哥愛編程,痴迷技術咱是認真滴。官人,都看到這了,高低點個贊再走唄,V 哥感謝你的支持。

user avatar front_yue 頭像 xiaolei_599661330c0cb 頭像 wric 頭像 huaweiclouddeveloper 頭像 jinyeyoudianerliang 頭像 dyzs 頭像 aipaobudehoutao 頭像 huankuaidehongjiu_c2eaor 頭像 beibiaobaidedigua_68fcd748dc136 頭像
點贊 9 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.