MySQL IN、Exist關聯查詢時,我們爲什麼建議小表驅動大表?

有的時候我們在操作數據庫時會將兩個或多個數據表關聯起來通過一些條件篩選數據,在關聯表時我們要遵循一些原則,這樣會使我們編寫的SQL 語句在效率上快很多。

一、優化原則

小表驅動大表,即小的數據集驅動大得數據集。在知道什麼是小表驅動達大表之前,我們先來了解兩個查詢關鍵字,IN 與 EXISTS。我們通過兩段查詢語句先來了解一下它們的作用。我建立了兩張表,一張員工表,一張部門表,員工表中有部門id 這個屬性,將這兩張表關聯起來。

我們先使用IN 來查詢數據:

SELECT * 
FROM t_emp 
WHERE dept_id IN (SELECT dept_id FROM t_dept) 
LIMIT 5;

查詢結果:由於有很多的員工信息,在這裏我就只查詢5 條數據。

+-------------+----------+------------+--------------+---------+
| emp_id      | emp_name | emp_gender | emp_email    | dept_id |
+-------------+----------+------------+--------------+---------+
| 00000000177 | 41d80    | m          | [email protected] |       1 |
| 00000000178 | a74b8    | m          | [email protected] |       1 |
| 00000000179 | 661ca    | m          | [email protected] |       1 |
| 00000000180 | 9413d    | m          | [email protected] |       1 |
| 00000000181 | 7d577    | m          | [email protected] |       1 |
+-------------+----------+------------+--------------+---------+

接下里使用EXISTS 來查詢數據:

 SELECT * 
 FROM t_emp 
 WHERE EXISTS 
     (SELECT 1 
     FROM t_dept 
     WHERE t_dept.dept_id = t_emp.dept_id) 
 LIMIT 5;

查詢結果:與上面的結果一樣。

+-------------+----------+------------+--------------+---------+
| emp_id      | emp_name | emp_gender | emp_email    | dept_id |
+-------------+----------+------------+--------------+---------+
| 00000000177 | 41d80    | m          | [email protected] |       1 |
| 00000000178 | a74b8    | m          | [email protected] |       1 |
| 00000000179 | 661ca    | m          | [email protected] |       1 |
| 00000000180 | 9413d    | m          | [email protected] |       1 |
| 00000000181 | 7d577    | m          | [email protected] |       1 |
+-------------+----------+------------+--------------+---------+

既然IN 和 EXISTS 都可以用來查詢數據,那它們兩個有什麼區別呢?

SELECT * 
FROM t_emp 
WHERE dept_id IN 
    (SELECT dept_id 
    FROM t_dept);

// 這條SQL 語句相當於:
for SELECT dept_id FROM t_dept
    for SELECT * FROM t_emp WHERE t_emp.dept_id = t_dept.dept_id

這裏雖然我們編寫的SQL 語句是主查詢員工信息,子查詢部門id ,但是MySql 的執行順序會先執行子查詢,再執行主查詢,然後獲得我們要查詢的數據。

 SELECT * 
 FROM t_emp 
 WHERE EXISTS 
     (SELECT 1 
     FROM t_dept 
     WHERE t_dept.dept_id = t_emp.dept_id);

// 這條SQL 語句相當於:     
for SELECT * FROM t_emp 
    for SELECT * FROM t_dept  WHERE t_dept.dept_id = t_emp.dept_id          

我們可以將EXISTS 語法理解爲:將主查詢的數據放在子查詢中做條件驗證,根據結果TRUE 和 FALSE 來決定主查詢中的數據是否需要保留。EXISTS 子查詢只返回TRUE 或 FALSE ,因此子查詢中的SELECT * 可以是SELECT 1 或者其他,MySql 的官方說在實際執行時會忽略SELECT 清單,因此是沒有 什麼區別的。EXISTS 子查詢其實在執行時,MySql 已經對它做了一些優化並不是對每條數據進行對比。

二、總結

在實際操作過程中我們要對兩張表的dept_id 都設置索引。在一開始我們就講了一個優化原則即:小表驅動大表,在我們使用IN 進行關聯查詢時,通過上面IN 操作的執行順序,我們是先查詢部門表再根據部門表查出來的id 信息查詢員工信息。我們都知道員工表肯定會有很多的員工信息,但是部門表一般只會有很少的數據信息,我們事先通過查詢部門表信息查詢員工信息,以小表(t_dept)的查詢結果,去驅動大表(t_emp),這種查詢方式是效率很高的,也是值得提倡的。

但是我們使用EXISTS 查詢時,首先查詢員工表,然後根據部門表的查詢條件返回的TRUE 或者 FALSE ,再決定員工表中的信息是否需要保留。這不就是用大的數據表(t_emp) 去驅動小的數據表小的數據表(t_dept)了嗎?雖然這種方式也可以查出我們想要的數據,但是這種查詢方式是不值得提倡的。

當t_emp(外層大表) 表中數據多於 t_dept(子表小表) 表中的數據時,這時我們使用IN 優於 EXISTS。當t_dept(子表小表) 表中數據多於 t_emp(外層大表) 表中的數據時(我們這裏只是假設),這時我們使用EXISTS 優於 IN。因此是使用IN 還是使用EXISTS 就需要根據我們的需求決定了。但是如果兩張表中的數據量差不多時那麼是使用IN 還是使用 EXISTS 差別不大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章