您好,登錄后才能下訂單哦!
運(yùn)營組的同事最近提出一個需求,希望可以統(tǒng)計(jì)出用系統(tǒng)用戶及訂單情況,于是乎我們很想當(dāng)然的寫出了一個統(tǒng)計(jì)SQL,用戶表user和行程表直接join,并且針對行程做了group,但SQL執(zhí)行速度出奇的慢。
explain select users.`mobile_num`, concat(users.`lastName` ,users.`firstName`) as userName, users.`company`,
(case `users`.`idPhotoCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `idPhotoCheckStatus`,
(case `users`.`driverLicenseCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `driverLicenseCheckStatus`,
(case `users`.`companyCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `companyCheckStatus`,
(case `users`.`unionCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' 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 != '本公司昵稱'
當(dāng)時的第一反應(yīng)是數(shù)據(jù)庫掛住了,因?yàn)橛脩舯淼臄?shù)據(jù)量10W左右,行程表的數(shù)據(jù)也是10W左右,不可能這么慢!通過explain查看分析計(jì)劃,并且查看過關(guān)聯(lián)字段的索引情況,發(fā)現(xiàn)這是一個最常見的關(guān)聯(lián)查詢,當(dāng)然是通過join實(shí)現(xiàn)。
轉(zhuǎn)而一想,10W*10W,經(jīng)過笛卡爾集之后,這不是百億級的數(shù)據(jù)篩選嗎?!于是換了一種寫法進(jìn)行嘗試。
explain select users.`mobile_num`, concat(users.`lastName` ,users.`firstName`) as userName, users.`company`,
(case `users`.`idPhotoCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `idPhotoCheckStatus`,
(case `users`.`driverLicenseCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `driverLicenseCheckStatus`,
(case `users`.`companyCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `companyCheckStatus`,
(case `users`.`unionCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' 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倍,執(zhí)行速度從未知到10秒內(nèi)返回,查看執(zhí)行計(jì)劃:
進(jìn)一步調(diào)整SQL進(jìn)行嘗試:
explain select users.`mobile_num`, concat(users.`lastName` ,users.`firstName`) as userName, users.`company`,
(case `users`.`idPhotoCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `idPhotoCheckStatus`,
(case `users`.`driverLicenseCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `driverLicenseCheckStatus`,
(case `users`.`companyCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' end) as `companyCheckStatus`,
(case `users`.`unionCheckStatus` when '2' then '已認(rèn)證' when '3' then '已駁回' else '待認(rèn)證' 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秒內(nèi)返回,這才是正常的預(yù)期,10W級的數(shù)據(jù)篩選,應(yīng)該是幾秒內(nèi)返回的!
出現(xiàn)這種差別的原因,其實(shí)很簡單,SQL語句執(zhí)行的時候是有一定順序的。
第一種寫法,直接join的結(jié)果,就是在100億條數(shù)據(jù)中進(jìn)行篩選;
后面兩種則是優(yōu)先執(zhí)行子查詢,完成10W級別的查詢,再進(jìn)行一次主表10W級的關(guān)聯(lián)查詢,所以數(shù)量級明顯少于第一種寫法。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。