運營組的同事最近提出一個需求,但願能夠統計出用系統用戶及訂單狀況,因而乎咱們很想固然的寫出了一個統計SQL,用戶表user和行程表直接join,而且針對行程作了group,但SQL執行速度出奇的慢。數據庫
explain select users.`mobile_num`, concat(users.`lastName` ,users.`firstName`) as userName, users.`company`, (case `users`.`idPhotoCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `idPhotoCheckStatus`, (case `users`.`driverLicenseCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `driverLicenseCheckStatus`, (case `users`.`companyCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `companyCheckStatus`, (case `users`.`unionCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `unionCheckStatus`, count(passenger_trip.id) as ptrip_num from users left join passenger_trip on passenger_trip.userId = users.id and passenger_trip.status != 'cancel' left join driver_trip on driver_trip.`userId`=users.`id` and driver_trip.`status` != 'cancel' where company != '本公司名' and company != '本公司暱稱'
當時的第一反應是數據庫掛住了,由於用戶表的數據量10W左右,行程表的數據也是10W左右,不可能這麼慢!經過explain查看分析計劃,而且查看過關聯字段的索引狀況,發現這是一個最多見的關聯查詢,固然是經過join實現。ide
轉而一想,10W*10W,通過笛卡爾集以後,這不是百億級的數據篩選嗎?!因而換了一種寫法進行嘗試。3d
explain select users.`mobile_num`, concat(users.`lastName` ,users.`firstName`) as userName, users.`company`, (case `users`.`idPhotoCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `idPhotoCheckStatus`, (case `users`.`driverLicenseCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `driverLicenseCheckStatus`, (case `users`.`companyCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `companyCheckStatus`, (case `users`.`unionCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `unionCheckStatus`, (select count(passenger_trip.id) from passenger_trip where passenger_trip.userId = users.id and passenger_trip.status != 'cancel') as ptrip_num, (select count(driver_trip.id) from driver_trip where driver_trip.userId = users.id and driver_trip.status != 'cancel') as dtrip_num from users where company != '本公司名' and company != '公司暱稱'
這樣的效果竟然比直接join快了N倍,執行速度從未知到10秒內返回,查看執行計劃:code
進一步調整SQL進行嘗試:blog
explain select users.`mobile_num`, concat(users.`lastName` ,users.`firstName`) as userName, users.`company`, (case `users`.`idPhotoCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `idPhotoCheckStatus`, (case `users`.`driverLicenseCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `driverLicenseCheckStatus`, (case `users`.`companyCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `companyCheckStatus`, (case `users`.`unionCheckStatus` when '2' then '已認證' when '3' then '已駁回' else '待認證' end) as `unionCheckStatus`, ptrip_num, dtrip_num from users left join (select count(passenger_trip.id) as ptrip_num, passenger_trip.`userId` from passenger_trip where passenger_trip.status != 'cancel' group by passenger_trip.`userId` ) as ptrip on ptrip.userId = users.id left join (select count(driver_trip.id) as dtrip_num, driver_trip.`userId` from driver_trip where driver_trip.status != 'cancel' group by driver_trip.`userId` ) as dtrip on dtrip.userId = users.id where company != '本公司名' and company != '公司暱稱'
竟然5秒內返回,這纔是正常的預期,10W級的數據篩選,應該是幾秒內返回的!排序
出現這種差異的緣由,其實很簡單,SQL語句執行的時候是有必定順序的。索引
第一種寫法,直接join的結果,就是在100億條數據中進行篩選;
後面兩種則是優先執行子查詢,完成10W級別的查詢,再進行一次主表10W級的關聯查詢,因此數量級明顯少於第一種寫法。ip