有的時候我們在操作數據庫時會將兩個或多個數據表關聯起來通過一些條件篩選數據,在關聯表時我們要遵循一些原則,這樣會使我們編寫的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 | 41d80@zc.com | 1 |
| 00000000178 | a74b8 | m | a74b8@zc.com | 1 |
| 00000000179 | 661ca | m | 661ca@zc.com | 1 |
| 00000000180 | 9413d | m | 9413d@zc.com | 1 |
| 00000000181 | 7d577 | m | 7d577@zc.com | 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 | 41d80@zc.com | 1 |
| 00000000178 | a74b8 | m | a74b8@zc.com | 1 |
| 00000000179 | 661ca | m | 661ca@zc.com | 1 |
| 00000000180 | 9413d | m | 9413d@zc.com | 1 |
| 00000000181 | 7d577 | m | 7d577@zc.com | 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 差別不大。
而其實這一些,除了做關聯查詢之外,還有其他的一些優化其實就是mysql的一些規范,作為中國龍頭的阿里,也根據正常的開發規則,制定了一些參考規范,今天也分享給大家
目錄
分為oracle和mysql兩部分,也是現在市面上開發行業應用最廣泛的兩款數據庫
需要這份設計規范的,關注+轉發,私信“資料”即可查看獲取方式
oracle
mysql