1. 程式人生 > >【MySQL系列--優化1】——巢狀join優化

【MySQL系列--優化1】——巢狀join優化

表達連線的語法允許巢狀連線。以下討論參見第13.2.9.2節“join語法”中描述的連線語法。

與SQL標準相比,table_factor的語法被擴充套件。後者僅接受table_reference,而不是一對括號內的列表。如果我們將table_reference專案的列表中的每個逗號都視為與內部連線相同,那麼這是一個保守的擴充套件。例如:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

相當於:

SELECT * FROM t1 LEFT
JOIN (t2 CROSS JOIN t3 CROSS JOIN t4) ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

在MySQL中,CROSS JOIN在語法上等同於INNER JOIN;他們可以互相替代。在標準SQL中,它們不是等效的。 INNER JOIN與ON子句一起使用;否則使用CROSS JOIN。

通常,只能包含內部連線操作的連線表示式中,括號可以被忽略。考慮這個連線表示式:

t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL
) ON t1.a=t2.a

刪除左側的括號和分組操作後,該連線表示式將轉換為此表示式:

(t1 LEFT JOIN t2 ON t1.a=t2.a) LEFT JOIN t3
    ON t2.b=t3.b OR t2.b IS NULL

然而,這兩個表示式是不相等的。為了看到這一點,假設表t1,t2和t3具有以下狀態:

  1. Table t1 contains rows (1), (2)
  2. Table t2 contains row (1,101)
  3. Table t3 contains row (101)

在這種情況下,第一個表示式返回包含行(1,1,101,101),(2,NULL,NULL,NULL)的結果集,而第二個表示式返回行(1,1,101,101),(2,NULL,NULL, 101):

mysql> SELECT *
       FROM t1
            LEFT JOIN
            (t2 LEFT JOIN t3 ON t2.b=t3.b OR t2.b IS NULL)
            ON t1.a=t2.a;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL | NULL |
+------+------+------+------+

mysql> SELECT *
       FROM (t1 LEFT JOIN t2 ON t1.a=t2.a)
            LEFT JOIN t3
            ON t2.b=t3.b OR t2.b IS NULL;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL |  101 |
+------+------+------+------+

在以下示例中,外連線操作與內連線操作一起使用:

t1 LEFT JOIN (t2, t3) ON t1.a=t2.a

這個表示式不能被轉換為下面的表示式:

t1 LEFT JOIN t2 ON t1.a=t2.a, t3

對於給定的表狀態,兩個表示式返回不同的行集合:

mysql> SELECT *
       FROM t1 LEFT JOIN (t2, t3) ON t1.a=t2.a;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL | NULL |
+------+------+------+------+

mysql> SELECT *
       FROM t1 LEFT JOIN t2 ON t1.a=t2.a, t3;
+------+------+------+------+
| a    | a    | b    | b    |
+------+------+------+------+
|    1 |    1 |  101 |  101 |
|    2 | NULL | NULL |  101 |
+------+------+------+------+

因此,如果我們使用外部連線運算子在連線表示式中省略括號,我們可能會更改原始表示式的結果集。
更準確地說,我們不能忽略左外連線操作的右運算元和右連線操作的左運算元中的括號。換句話說,我們不能忽略外連線操作的內表表達式的括號。可以忽略其他運算元的圓括號(外部表的運算元)。

下面的表示式:

(t1,t2) LEFT JOIN t3 ON P(t2.b,t3.b)

對於任何表t1,t2,t3和屬性t2.b和t3.b上的任何條件P,等效於此表示式:

t1, t2 LEFT JOIN t3 ON P(t2.b,t3.b)

每當在連線表示式(join_table)中執行連線操作的順序不是從左到右,我們討論巢狀連線。考慮以下查詢:

SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b=t3.b) ON t1.a=t2.a
  WHERE t1.a > 1

SELECT * FROM t1 LEFT JOIN (t2, t3) ON t1.a=t2.a
  WHERE (t2.b=t3.b OR t2.b IS NULL) AND t1.a > 1

這些查詢被認為包含這些巢狀連線:

t2 LEFT JOIN t3 ON t2.b=t3.b
t2, t3