溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL子查詢原理是什么

發(fā)布時(shí)間:2022-02-07 15:39:02 來源:億速云 閱讀:206 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“MySQL子查詢原理是什么”,在日常操作中,相信很多人在MySQL子查詢原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”MySQL子查詢原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

    01前言

    子查詢,通俗解釋就是查詢語句中嵌套著另一個(gè)查詢語句。相信日常工作中接觸到 MySQL 的同學(xué)都了解或使用過子查詢,但是具體它是怎樣實(shí)現(xiàn)的呢? 查詢效率如何? 這些恐怕好多人就不太清楚了,下面咱們就圍繞這兩個(gè)問題共同探索一下。

    02準(zhǔn)備內(nèi)容

    這里我們需要用到3個(gè)表,這3個(gè)表都有一個(gè)主鍵索引 id 和一個(gè)索引 a,字段 b 上無索引。存儲過程 idata() 往表 t1 里插入的是 100 行數(shù)據(jù),表 t2、t3 里插入了 1000 行數(shù)據(jù)。建表語句如下:

    CREATE TABLE `t1` (
        `id` INT ( 11 ) NOT NULL,
        `t1_a` INT ( 11 ) DEFAULT NULL,
        `t1_b` INT ( 11 ) DEFAULT NULL,
    PRIMARY KEY ( `id` ),
    KEY `idx_a` ( `t1_a` )) ENGINE = INNODB;
    
    CREATE TABLE `t2` (
        `id` INT ( 11 ) NOT NULL,
        `t2_a` INT ( 11 ) DEFAULT NULL,
        `t2_b` INT ( 11 ) DEFAULT NULL,
    PRIMARY KEY ( `id` ),
    KEY `idx_a` ( `t2_a` )) ENGINE = INNODB;
    
    CREATE TABLE `t3` (
        `id` INT ( 11 ) NOT NULL,
        `t3_a` INT ( 11 ) DEFAULT NULL,
        `t3_b` INT ( 11 ) DEFAULT NULL,
    PRIMARY KEY ( `id` ),
    KEY `idx_a` ( `t3_a` )) ENGINE = INNODB;
    
    -- 向t1添加100條數(shù)據(jù)
    -- drop procedure idata;
    delimiter ;;
    create procedure idata()
    begin
      declare i int;
      set i=1;
      while(i<=100)do
            insert into t1 values(i, i, i);
        set i=i+1;
      end while;
    end;;
    delimiter ;
    call idata();
    
    -- 向t2添加1000條數(shù)據(jù)
    drop procedure idata;
    delimiter ;;
    create procedure idata()
    begin
      declare i int;
      set i=101;
      while(i<=1100)do
            insert into t2 values(i, i, i);
        set i=i+1;
      end while;
    end;;
    delimiter ;
    call idata();
    
    -- 向t2添加1000條數(shù)據(jù),且t3_a列的值為倒敘
    drop procedure idata;
    delimiter ;;
    create procedure idata()
    begin
      declare i int;
      set i=101;
      while(i<=1100)do
            insert into t3 values(i, 1101-i, i);
        set i=i+1;
      end while;
    end;;
    delimiter ;
    call idata();

    03子查詢的語法形式和分類

    3.1 語法形式

    子查詢的語法規(guī)定,子查詢可以在一個(gè)外層查詢的各種位置出現(xiàn),這里我們只介紹常用的幾個(gè):

    3.1.1  FROM子句中

    SELECT m, n FROM (SELECT m2 + 1 AS m, n2 AS n FROM t2 WHERE m2 > 2) AS t;

    這個(gè)例子中的子查詢是:(SELECT m2 + 1 AS m, n2 AS n FROM t2 WHERE m2 > 2),這個(gè)放在FROM子句中的子查詢相當(dāng)于一個(gè)表,但又和我們平常使用的表有點(diǎn)兒不一樣,這種由子查詢結(jié)果集組成的表稱之為派生表。

    3.1.2 WHERE或IN子句中

    如:SELECT * FROM t1 WHERE m1 = (SELECT MIN(m2) FROM t2);

           SELECT * FROM t1 WHERE m1 IN (SELECT m2 FROM t2);

    其他的還有 SELECT 子句中,ORDER BY 子句中,GROUP BY 子句中,雖然語法支持,但沒啥意義,就不嘮叨這些情況了。

    3.2 分類

    3.2.1 按返回的結(jié)果集區(qū)分

    標(biāo)量子查詢,只返回一個(gè)單一值的子查詢稱之為標(biāo)量子查詢,比如:

    SELECT * FROM t1 WHERE m1 = (SELECT m1 FROM t1 LIMIT 1);

    行子查詢,就是只返回一條記錄的子查詢,不過這條記錄需要包含多個(gè)列(只包含一個(gè)列就成了標(biāo)量子查詢了)。比如:SELECT * FROM t1 WHERE (m1, n1) = (SELECT m2, n2 FROM t2 LIMIT 1);

    列子查詢,就是只返回一個(gè)列的數(shù)據(jù),不過這個(gè)列的數(shù)據(jù)需要包含多條記錄(只包含一條記錄就成了標(biāo)量子查詢了)。比如:SELECT * FROM t1 WHERE m1 IN (SELECT m2 FROM t2);

    表子查詢,就是子查詢的結(jié)果既包含很多條記錄,又包含很多個(gè)列,比如:

    SELECT * FROM t1 WHERE (m1, n1) IN (SELECT m2, n2 FROM t2);

    其中的 (SELECT m2, n2 FROM t2) 就是一個(gè)表子查詢,這里需要和行子查詢對比一下,行子查詢中我們用了 LIMIT 1 來保證子查詢的結(jié)果只有一條記錄。

    3.2.2 按與外層查詢關(guān)系來區(qū)分

    不相關(guān)子查詢,就是子查詢可以單獨(dú)運(yùn)行出結(jié)果,而不依賴于外層查詢的值,我們就可以把這個(gè)子查詢稱之為不相關(guān)子查詢。
    相關(guān)子查詢,就是需要依賴于外層查詢的值的子查詢稱之為相關(guān)子查詢。比如:SELECT * FROM t1 WHERE m1 IN (SELECT m2 FROM t2 WHERE n1 = n2);

    04子查詢在MySQL中是怎么執(zhí)行的

    4.1 標(biāo)量子查詢、行子查詢的執(zhí)行方式

    4.1.1 不相關(guān)子查詢

    如下邊這個(gè)查詢語句:

    mysql root@localhost:test> explain select * from t1 where t1_a = (select t2_a from t2 limit 1);
    +----+-------------+-------+-------+---------------+-------+---------+--------+------+-------------+
    | id | select_type | table | type  | possible_keys | key   | key_len | ref    | rows | Extra       |
    +----+-------------+-------+-------+---------------+-------+---------+--------+------+-------------+
    | 1  | PRIMARY     | t1    | ref   | idx_a         | idx_a | 5       | const  | 1    | Using where |
    | 2  | SUBQUERY    | t2    | index | <null>        | idx_a | 5       | <null> | 1000 | Using index |
    +----+-------------+-------+-------+---------------+-------+---------+--------+------+-------------+

    它的執(zhí)行方式:

    先單獨(dú)執(zhí)行 (select t2_a from t2 limit 1) 這個(gè)子查詢。

    然后在將上一步子查詢得到的結(jié)果當(dāng)作外層查詢的參數(shù)再執(zhí)行外層查詢 select * from t1 where t1_a = ...。

    也就是說,對于包含不相關(guān)的標(biāo)量子查詢或者行子查詢的查詢語句來說,MySQL 會分別獨(dú)立的執(zhí)行外層查詢和子查詢,就當(dāng)作兩個(gè)單表查詢就好了。

    4.1.2 相關(guān)的子查詢

    比如下邊這個(gè)查詢:

    mysql root@localhost:test> explain select * from t1 where t1_a = (select t2_a from t2 where t1.t1_b=t2.t2_b  limit 1);
    +----+--------------------+-------+------+---------------+--------+---------+--------+------+-------------+
    | id | select_type        | table | type | possible_keys | key    | key_len | ref    | rows | Extra       |
    +----+--------------------+-------+------+---------------+--------+---------+--------+------+-------------+
    | 1  | PRIMARY            | t1    | ALL  | <null>        | <null> | <null>  | <null> | 100  | Using where |
    | 2  | DEPENDENT SUBQUERY | t2    | ALL  | <null>        | <null> | <null>  | <null> | 1000 | Using where |
    +----+--------------------+-------+------+---------------+--------+---------+--------+------+-------------+

    它的執(zhí)行方式就是這樣的:

    先從外層查詢中獲取一條記錄,本例中也就是先從 t1 表中獲取一條記錄。

    然后從上一步驟中獲取的那條記錄中找出子查詢中涉及到的值,就是 t1 表中找出 t1.t1_b 列的值,然后執(zhí)行子查詢。

    最后根據(jù)子查詢的查詢結(jié)果來檢測外層查詢 WHERE 子句的條件是否成立,如果成立,就把外層查詢的那條記錄加入到結(jié)果集,否則就丟棄。

    然后重復(fù)以上步驟,直到 t1 中的記錄全部匹配完。

    4.2 IN子查詢

    4.2.1 物化

    如果子查詢的結(jié)果集中的記錄條數(shù)很少,那么把子查詢和外層查詢分別看成兩個(gè)單獨(dú)的單表查詢效率還是蠻高的,但是如果單獨(dú)執(zhí)行子查詢后的結(jié)果集太多的話,就會導(dǎo)致這些問題:

    結(jié)果集太多,可能內(nèi)存中都放不下~

    對于外層查詢來說,如果子查詢的結(jié)果集太多,那就意味著 IN 子句中的參數(shù)特別多,這就導(dǎo)致:

    1)無法有效的使用索引,只能對外層查詢進(jìn)行全表掃描。

    2)在對外層查詢執(zhí)行全表掃描時(shí),由于 IN 子句中的參數(shù)太多,這會導(dǎo)致檢測一條記錄是否符合和 IN 子句中的參數(shù)匹配花費(fèi)的時(shí)間太長。

    于是就有:不直接將不相關(guān)子查詢的結(jié)果集當(dāng)作外層查詢的參數(shù),而是將該結(jié)果集寫入一個(gè)臨時(shí)表里。寫入臨時(shí)表的過程是這樣的:

    該臨時(shí)表的列就是子查詢結(jié)果集中的列。

    寫入臨時(shí)表的記錄會被去重,讓臨時(shí)表變得更小,更省地方。

    一般情況下子查詢結(jié)果集不大時(shí),就會為它建立基于內(nèi)存的使用 Memory 存儲引擎的臨時(shí)表,而且會為該表建立哈希索引。

    如果子查詢的結(jié)果集非常大,超過了系統(tǒng)變量 tmp_table_size或者 max_heap_table_size,臨時(shí)表會轉(zhuǎn)而使用基于磁盤的存儲引擎來保存結(jié)果集中的記錄,索引類型也對應(yīng)轉(zhuǎn)變?yōu)?B+ 樹索引。

    這個(gè)將子查詢結(jié)果集中的記錄保存到臨時(shí)表的過程稱之為物化(Materialize)。為了方便起見,我們就把那個(gè)存儲子查詢結(jié)果集的臨時(shí)表稱之為物化表。正因?yàn)槲锘碇械挠涗浂冀⒘怂饕ɑ趦?nèi)存的物化表有哈希索引,基于磁盤的有 B+ 樹索引),通過索引執(zhí)行IN語句判斷某個(gè)操作數(shù)在不在子查詢結(jié)果集中變得非??欤瑥亩嵘俗硬樵冋Z句的性能。

    mysql root@localhost:test> explain select * from t3 where t3_a in (select t2_a from t2);
    +----+--------------+-------------+--------+---------------+------------+---------+--------------+------+-------------+
    | id | select_type  | table       | type   | possible_keys | key        | key_len | ref          | rows | Extra       |
    +----+--------------+-------------+--------+---------------+------------+---------+--------------+------+-------------+
    | 1  | SIMPLE       | t3          | ALL    | idx_a         | <null>     | <null>  | <null>       | 1000 | Using where |
    | 1  | SIMPLE       | <subquery2> | eq_ref | <auto_key>    | <auto_key> | 5       | test.t3.t3_a | 1    | <null>      |
    | 2  | MATERIALIZED | t2          | index  | idx_a         | idx_a      | 5       | <null>       | 1000 | Using index |
    +----+--------------+-------------+--------+---------------+------------+---------+--------------+------+-------------+

    其實(shí)上邊的查詢就相當(dāng)于表 t3 和子查詢物化表進(jìn)行內(nèi)連接:

    mysql root@localhost:test> explain select * from t3 left join t2 on t3.t3_a=t2.t2_a;
    +----+-------------+-------+------+---------------+--------+---------+--------------+------+--------+
    | id | select_type | table | type | possible_keys | key    | key_len | ref          | rows | Extra  |
    +----+-------------+-------+------+---------------+--------+---------+--------------+------+--------+
    | 1  | SIMPLE      | t3    | ALL  | <null>        | <null> | <null>  | <null>       | 1000 | <null> |
    | 1  | SIMPLE      | t2    | ref  | idx_a         | idx_a  | 5       | test.t3.t3_a | 1    | <null> |
    +----+-------------+-------+------+---------------+--------+---------+--------------+------+--------+

    此時(shí) MySQL 查詢優(yōu)化器會通過運(yùn)算來選擇成本更低的方案來執(zhí)行查詢。

    雖然,上面通過物化表的方式,將IN子查詢轉(zhuǎn)換成了聯(lián)接查詢,但還是會有建立臨時(shí)表的成本,能不能不進(jìn)行物化操作直接把子查詢轉(zhuǎn)換為連接呢?直接轉(zhuǎn)換肯定不行。
    -- 這里我們先構(gòu)造了3條記錄,其實(shí)也是構(gòu)造不唯一的普通索引

    +------+------+------+
    | id   | t2_a | t2_b |
    +------+------+------+
    | 1100 | 1000 | 1000 |
    | 1101 | 1000 | 1000 |
    | 1102 | 1000 | 1000 |
    +------+------+------+
    -- 加限制條件where t2.id>=1100是為了減少要顯示的數(shù)據(jù)
    mysql root@localhost:test> select * from t3 where t3_a in (select t2_a from t2 where t2.id>=1100);
    +-----+------+------+
    | id  | t3_a | t3_b |
    +-----+------+------+
    | 101 | 1000 | 101  |
    +-----+------+------+
    1 row in set
    Time: 0.016s
    mysql root@localhost:test> select * from t3 left join t2 on t3.t3_a=t2.t2_a where t2.id>=1100;
    +-----+------+------+------+------+------+
    | id  | t3_a | t3_b | id   | t2_a | t2_b |
    +-----+------+------+------+------+------+
    | 101 | 1000 | 101  | 1100 | 1000 | 1000 |
    | 101 | 1000 | 101  | 1101 | 1000 | 1000 |
    | 101 | 1000 | 101  | 1102 | 1000 | 1000 |
    +-----+------+------+------+------+------+
    3 rows in set
    Time: 0.018s

    所以說 IN 子查詢和表聯(lián)接之間并不完全等價(jià)。而我們需要的是另一種叫做半聯(lián)接 (semi-join) 的聯(lián)接方式 :對于 t3 表的某條記錄來說,我們只關(guān)心在 t2 表中是否存在與之匹配的記錄,而不關(guān)心具體有多少條記錄與之匹配,最終的結(jié)果集中也只保留 t3 表的記錄。

    注意:semi-join 只是在 MySQL 內(nèi)部采用的一種執(zhí)行子查詢的方式,MySQL 并沒有提供面向用戶的 semi-join 語法。

    4.2.2 半聯(lián)接的實(shí)現(xiàn):
    • Table pullout (子查詢中的表上拉)

    當(dāng)子查詢的查詢列表處只有主鍵或者唯一索引列時(shí),可以直接把子查詢中的表上拉到外層查詢的 FROM 子句中,并把子查詢中的搜索條件合并到外層查詢的搜索條件中,比如這個(gè):

    mysql root@localhost:test> select * from t3 where t3_a in (select t2_a from t2 where t2.id=999)
    +-----+------+------+
    | id  | t3_a | t3_b |
    +-----+------+------+
    | 102 | 999  | 102  |
    +-----+------+------+
    1 row in set
    Time: 0.024s
    mysql root@localhost:test> select * from t3 join t2 on t3.t3_a=t2.t2_a where t2.id=999;
    +-----+------+------+-----+------+------+
    | id  | t3_a | t3_b | id  | t2_a | t2_b |
    +-----+------+------+-----+------+------+
    | 102 | 999  | 102  | 999 | 999  | 999  |
    +-----+------+------+-----+------+------+
    1 row in set
    Time: 0.028s
    mysql root@localhost:test> explain select * from t3 where t3_a in (select t2_a from t2 where t2.id=999)
    +----+-------------+-------+-------+---------------+---------+---------+-------+------+--------+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra  |
    +----+-------------+-------+-------+---------------+---------+---------+-------+------+--------+
    | 1  | SIMPLE      | t2    | const | PRIMARY,idx_a | PRIMARY | 4       | const | 1    | <null> |
    | 1  | SIMPLE      | t3    | ref   | idx_a         | idx_a   | 5       | const | 1    | <null> |
    +----+-------------+-------+-------+---------------+---------+---------+-------+------+--------+
    • FirstMatch execution strategy (首次匹配)

    FirstMatch 是一種最原始的半連接執(zhí)行方式,跟相關(guān)子查詢的執(zhí)行方式是一樣的,就是說先取一條外層查詢的中的記錄,然后到子查詢的表中尋找符合匹配條件的記錄,如果能找到一條,則將該外層查詢的記錄放入最終的結(jié)果集并且停止查找更多匹配的記錄,如果找不到則把該外層查詢的記錄丟棄掉。然后再開始取下一條外層查詢中的記錄,重復(fù)上邊這個(gè)過程。

    mysql root@localhost:test> explain select * from t3 where t3_a in (select t2_a from t2 where t2.t2_a=1000)
    +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------+
    | id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra                       |
    +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------+
    | 1  | SIMPLE      | t3    | ref  | idx_a         | idx_a | 5       | const | 1    | <null>                      |
    | 1  | SIMPLE      | t2    | ref  | idx_a         | idx_a | 5       | const | 4    | Using index; FirstMatch(t3) |
    +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------+
    • DuplicateWeedout execution strategy (重復(fù)值消除)

    轉(zhuǎn)換為半連接查詢后,t3 表中的某條記錄可能在 t2 表中有多條匹配的記錄,所以該條記錄可能多次被添加到最后的結(jié)果集中,為了消除重復(fù),我們可以建立一個(gè)臨時(shí)表,并設(shè)置主鍵id,每當(dāng)某條 t3 表中的記錄要加入結(jié)果集時(shí),就首先把這條記錄的id值加入到這個(gè)臨時(shí)表里,如果添加成功,說明之前這條 t2 表中的記錄并沒有加入最終的結(jié)果集,是一條需要的結(jié)果;如果添加失敗,說明之前這條 s1 表中的記錄已經(jīng)加入過最終的結(jié)果集,直接把它丟棄。

    • LooseScan execution strategy (松散掃描)

    這種雖然是掃描索引,但只取值相同的記錄的第一條去做匹配操作的方式稱之為松散掃描。

    4.2.3 半聯(lián)接的適用條件

    當(dāng)然,并不是所有包含IN子查詢的查詢語句都可以轉(zhuǎn)換為 semi-join,只有形如這樣的查詢才可以被轉(zhuǎn)換為 semi-join:

    SELECT ... FROM outer_tables 
        WHERE expr IN (SELECT ... FROM inner_tables ...) AND ...
    
    -- 或者這樣的形式也可以:
    
    SELECT ... FROM outer_tables 
        WHERE (oe1, oe2, ...) IN (SELECT ie1, ie2, ... FROM inner_tables ...) AND ...

    用文字總結(jié)一下,只有符合下邊這些條件的子查詢才可以被轉(zhuǎn)換為 semi-join:

    1. 該子查詢必須是和IN語句組成的布爾表達(dá)式,并且在外層查詢的 WHERE 或者 ON 子句中出現(xiàn)

    2. 外層查詢也可以有其他的搜索條件,只不過和 IN 子查詢的搜索條件必須使用AND 連接起來

    3. 該子查詢必須是一個(gè)單一的查詢,不能是由若干查詢由 UNION 連接起來的形式

    4. 該子查詢不能包含 GROUP BY 或者 HAVING 語句或者聚集函數(shù)

    4.2.4 轉(zhuǎn)為 EXISTS 子查詢

    不管子查詢是相關(guān)的還是不相關(guān)的,都可以把 IN 子查詢嘗試轉(zhuǎn)為 EXISTS子查詢。其實(shí)對于任意一個(gè) IN 子查詢來說,都可以被轉(zhuǎn)為 EXISTS 子查詢,通用的例子如下:

    outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)
    -- 可以被轉(zhuǎn)換為:
    EXISTS (SELECT inner_expr FROM ... WHERE subquery_where AND outer_expr=inner_expr)

    當(dāng)然這個(gè)過程中有一些特殊情況,比如在 outer_expr 或者 inner_expr 值為 NULL 的情況下就比較特殊。因?yàn)橛?NULL 值作為操作數(shù)的表達(dá)式結(jié)果往往是 NULL,比方說:

    mysql root@localhost:test> SELECT NULL IN (1, 2, 3);
    +-------------------+
    | NULL IN (1, 2, 3) |
    +-------------------+
    | <null>            |
    +-------------------+
    1 row in set

    而 EXISTS 子查詢的結(jié)果肯定是 TRUE 或者 FASLE 。但是現(xiàn)實(shí)中我們大部分使用 IN 子查詢的場景是把它放在 WHERE 或者 ON 子句中,而 WHERE 或者 ON 子句是不區(qū)分 NULL 和 FALSE 的,比方說:

    mysql root@localhost:test> SELECT 1 FROM s1 WHERE NULL;
    +---+
    | 1 |
    +---+
    0 rows in set
    Time: 0.016s
    mysql root@localhost:test> SELECT 1 FROM s1 WHERE FALSE;
    +---+
    | 1 |
    +---+
    0 rows in set
    Time: 0.033s

    所以只要我們的IN子查詢是放在 WHERE 或者 ON 子句中的,那么 IN ->  EXISTS 的轉(zhuǎn)換就是沒問題的。說了這么多,為啥要轉(zhuǎn)換呢?這是因?yàn)椴晦D(zhuǎn)換的話可能用不到索引,比方說下邊這個(gè)查詢:

    mysql root@localhost:test> explain select * from t3 where t3_a in (select t2_a from t2 where t2.t2_a>=999) or t3_b > 1000;
    +----+-------------+-------+-------+---------------+--------+---------+--------+------+--------------------------+
    | id | select_type | table | type  | possible_keys | key    | key_len | ref    | rows | Extra                    |
    +----+-------------+-------+-------+---------------+--------+---------+--------+------+--------------------------+
    | 1  | PRIMARY     | t3    | ALL   | <null>        | <null> | <null>  | <null> | 1000 | Using where              |
    | 2  | SUBQUERY    | t2    | range | idx_a         | idx_a  | 5       | <null> | 107  | Using where; Using index |
    +----+-------------+-------+-------+---------------+--------+---------+--------+------+--------------------------+

    但是將它轉(zhuǎn)為 EXISTS 子查詢后卻可以使用到索引:

    mysql root@localhost:test> explain select * from t3 where exists (select 1 from t2 where t2.t2_a>=999 and t2.t2_a=t3.t3_a) or t3_b > 1000;
    +----+--------------------+-------+------+---------------+--------+---------+--------------+------+--------------------------+
    | id | select_type        | table | type | possible_keys | key    | key_len | ref          | rows | Extra                    |
    +----+--------------------+-------+------+---------------+--------+---------+--------------+------+--------------------------+
    | 1  | PRIMARY            | t3    | ALL  | <null>        | <null> | <null>  | <null>       | 1000 | Using where              |
    | 2  | DEPENDENT SUBQUERY | t2    | ref  | idx_a         | idx_a  | 5       | test.t3.t3_a | 1    | Using where; Using index |
    +----+--------------------+-------+------+---------------+--------+---------+--------------+------+--------------------------+

    需要注意的是,如果 IN 子查詢不滿足轉(zhuǎn)換為 semi-join 的條件,又不能轉(zhuǎn)換為物化表或者轉(zhuǎn)換為物化表的成本太大,那么它就會被轉(zhuǎn)換為 EXISTS 查詢?;蛘咿D(zhuǎn)換為物化表的成本太大,那么它就會被轉(zhuǎn)換為 EXISTS 查詢。

    到此,關(guān)于“MySQL子查詢原理是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI