使用數據庫為mysql的官方示例數據庫employees,可以從這下載:https://github.com/datacharmer/test_db
介紹:
使用到了employees的兩個表,分別是員工表(employees, 30w24數據),部門經理表(dept_manager 24數據),兩張表都有emp_no,員工編號字段,並且設置了主鍵索引。
要求查詢所有非經理的員工數據:
左連接
select e.* from employees e LEFT JOIN dept_manager d on e.emp_no = d.emp_no where d.emp_no is null
執行結果:0.651s
執行計划:
子查詢
select * from employees e where e.emp_no not in (select emp_no from dept_manager )
執行結果:0.260s
執行計划:
===============================================
不像一般討論的那樣,這個場景子查詢性能更好,但是具體原因只是看執行計划體現不出,只感覺Extra列可能是重要原因。
實際分析涉及到了Mysql內部實現原理了,咱目前的水平不足,無法解釋。
先放一波猜測記錄,若未來能力夠了再回來驗證。
「
子查詢的子部分非常快,查詢的結果作為外層where條件,使得外層可以走索引,實際並沒有遍歷30W數據,即:
1. 查詢子表所有數據(24條)(非常快,單獨執行0.032s,在子查詢中應該會增加耗時)
2. 返回子表的主鍵(24條)(非常快)
3. 用子表返回的主鍵 索引查找外層數據( < 0.23s )
而
左連接SQL 由於必須連接后才能過濾右側為空的數據,導致遍歷了1遍的左表,左表每行數據索引1次右表,相當於至少遍歷了2次左表
1. 遍歷左表所有數據 ( < 0.2s )
2. 所有左表數據關聯右表( 這部耗時最多,總 < 0.6s,兩倍於步驟1)
3. 遍歷左表過濾非空 ( 非常快)
」
在貼吧看到某個貼后有感而發,測了下。