原SQL:
SELECT
p.id,
p.NAME,
p.idcard,
p.phone,
p.plate,
p.FAMILY_NO
FROM
t_person_info p
WHERE
p.id IN ( SELECT id FROM t_person_info WHERE FAMILY_NO = ( SELECT FAMILY_NO FROM t_person_info WHERE id = '1561155127086411776' ) )
OR p.id = '1561155127086411776'
執行計劃:
耗時:
2.4秒
優化思路:
將人員的直接查出來,只有1條數據作爲驅動表,再用戶口號去關聯原表。
優化後的SQL:
SELECT
p.id,
p.NAME,
p.idcard,
p.phone,
p.plate,
p.FAMILY_NO
FROM
t_person_info p
right JOIN (select * from t_person_info where id = '1561155127086411776') p2 on p.FAMILY_NO = p2.FAMILY_NO
執行計劃
耗時:
0.03秒
成功避免了兩個子查詢以及79萬表的全表掃描。
結論:
永遠不要輕易使用【in子查詢】,由於in子查詢總是以外層查詢的table作爲驅動表,所以如果想用in子查詢的話,一定要將外層查詢的結果集降下來,降低io次數,降低nested loop循環次數,即:永遠用小結果集驅動大的結果集。
之前的SQL就是以大表t_person_info作爲驅動表進行nested loop,該表數據越大,效率越慢。
如sql
SELECT
p.id,
p.NAME,
p.idcard,
p.phone,
p.plate,
p.FAMILY_NO
FROM
t_person_info p
WHERE
p.id IN ( SELECT id FROM t_person_info WHERE FAMILY_NO = '11697717')
and p.id = '1561155127086411776'
mysql優化器自動謂詞下推,等價於:
SELECT
p.id,
p.NAME,
p.idcard,
p.phone,
p.plate,
p.FAMILY_NO
FROM
(select * from t_person_info where id = '1561155127086411776') p
WHERE
p.id IN ( SELECT id FROM t_person_info WHERE FAMILY_NO = '11697717')
這樣驅動表結果集降到最低,效率也就提高了。這裏只是舉例,這條SQL並不符合業務場景。