MySQL 子查詢(四)子查詢的優化、將子查詢重寫為連接


  MySQL 5.7 ref ——13.2.10.10優化子查詢

十、子查詢的優化

  開發正在進行中,因此從長遠來看,沒有什么優化建議是可靠的。以下列表提供了一些您可能想要使用的有趣技巧。See also Section 8.2.2, “Optimizing Subqueries, Derived Tables, and View References”.

  10.1 優化子查詢中行的數量或順序

SELECT * FROM t1 WHERE t1.column1 IN
  (SELECT column1 FROM t2 ORDER BY column1);

SELECT * FROM t1 WHERE t1.column1 IN
  (SELECT DISTINCT column1 FROM t2);

SELECT * FROM t1 WHERE EXISTS
  (SELECT * FROM t2 LIMIT 1);

  10.2 用子查詢替換連接

SELECT DISTINCT column1 
FROM t1 WHERE t1.column1 IN (
    SELECT column1 FROM t2
);

  用上面的語句替換這下面的:

SELECT DISTINCT t1.column1 
FROM t1, t2
WHERE t1.column1 = t2.column1;

  10.3

  某些子查詢可以轉換為連接,以便與不支持子查詢的舊版MySQL兼容。但是,在某些情況下,將子查詢轉換為連接可能會提高性能。

  10.4 子句從外部移動到子查詢內部

  例如,用上面的查詢代替下面的:

SELECT * FROM t1
WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);

/*代替*/

SELECT * FROM t1
WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);

  另一個例子:

SELECT (SELECT column1 + 5 FROM t1) FROM t2;

/*代替*/

SELECT (SELECT column1 FROM t1) + 5 FROM t2;

 

  10.5 使用行子查詢而不是相關子查詢。

SELECT * FROM t1
  WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);

/*代替*/

SELECT * FROM t1
  WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1
                AND t2.column2=t1.column2);

  

  10.6

  使用 

NOT (a = ANY (...))

  而不是

a <> ALL (...)

 

  10.7

  使用 

x = ANY (table containing (1,2))

  而不是

x=1 OR x=2.

 

  10.8

  使用

=ANY

  而不是

EXISTS

 

  10.9

  對於始終返回一行的不相關子查詢,IN 總是慢於 =

SELECT * FROM t1
  WHERE t1.col_name = (SELECT a FROM t2 WHERE b = some_const);

/*代替*/

SELECT * FROM t1
  WHERE t1.col_name IN (SELECT a FROM t2 WHERE b = some_const);

 

  這些技巧可能會導致程序變得更快或更慢。使用像BENCHMARK() 函數這樣的MySQL工具,您可以了解在您自己的情況下有什么幫助。See Section 12.15, “Information Functions”.

  MySQL自己也會做出一些優化:

  • MySQL只執行一次不相關的子查詢。使用EXPLAIN確保給定的子查詢確實不相關。
  • MySQL會重寫IN,ALL,ANY和SOME子查詢,這樣是為了嘗試提高子查詢中的select-list列被索引的可能性。
  • MySQL使用索引查找函數替換以下形式的子查詢,EXPLAIN將其描述為特殊的連接類型(unique_subquery或index_subquery:
    ... IN (SELECT indexed_column FROM single_table ...)
  • MySQL使用包含MIN()或MAX()的表達式增強以下表單的表達式,除非涉及NULL值或空集:
    value {ALL|ANY|SOME} {> | < | >= | <=} (uncorrelated subquery)

    例如,對這個WHERE子句

    WHERE 5 > ALL (SELECT x FROM t)

    優化器可能會像這樣對待:

    WHERE 5 > (SELECT MAX(x) FROM t)

  

  See also MySQL Internals: How MySQL Transforms Subqueries.

 

十一、將子查詢重寫為連接

  有時,除了使用子查詢之外,還有其他方法可以測試一組值中的成員資格。

  同樣,在某些情況下,不僅可以將查詢重寫為沒有子查詢的語句,還可能比使用子查詢更加高效。IN()構造器就是如此。

  例如,這個查詢:

SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);

  可以被重寫為:

SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;

 

  查詢:

SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);
SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);

  可以被重寫為:

SELECT table1.*
  FROM table1 LEFT JOIN table2 ON table1.id=table2.id
  WHERE table2.id IS NULL;

 

  LEFT [OUTER] JOIN可以比等效子查詢更快,因為服務器可能能夠更好地優化它——這個事實並非僅針對MySQL Server。

  在SQL-92之前,外連接不存在,因此子查詢是執行某些操作的唯一方法。今天,MySQL Server和許多其他現代數據庫系統提供了廣泛的外連接類型。

 

  MySQL Server支持多表DELETE語句,可用於根據一個表甚至多個表中的信息同時有效地刪除行。還支持多表UPDATE語句。See Section 13.2.2, “DELETE Syntax”, and Section 13.2.11, “UPDATE Syntax”.

 

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM