工作中,經(jīng)常有運(yùn)營(yíng)需求用于統(tǒng)計(jì)線(xiàn)上數(shù)據(jù),實(shí)際場(chǎng)景中兩個(gè)百萬(wàn)級(jí)表聯(lián)合查詢(xún),往往會(huì)大大消耗查詢(xún)時(shí)間。
針對(duì)此問(wèn)題,解決思路可以將sql,拆分,可利用中間表方式,對(duì)數(shù)據(jù)進(jìn)行統(tǒng)計(jì)。
例如:訂單表 t_order,訂單收貨表t_order_shipping,會(huì)員表 t_member;
數(shù)據(jù)需求:獲取會(huì)員表中大于二十歲的手機(jī)號(hào),排除2017年已支付訂單的手機(jī)號(hào)。
根據(jù)此需求,我們可以寫(xiě)出如下sql:
select distinct m.mobile_phone
from t_member m
where m.age >20
and m.mobile_phone not in (
select distinct s.mobile_phone
from t_order o, t_order_shipping
where o.order_id = s.order_id
and 0.status ='已支付';
);
當(dāng)t_member 千萬(wàn)級(jí)別,t_order和t_order_shipping百萬(wàn)級(jí)別數(shù)據(jù)量時(shí),以上查詢(xún)將需要非常多時(shí)間,大量的時(shí)間都用在了復(fù)制臨時(shí)表和發(fā)送查詢(xún)結(jié)果上。
經(jīng)測(cè)試,mobile_phone加索引的請(qǐng)求下,該sql大概執(zhí)行半小時(shí)。
優(yōu)化方案:
1、可使用關(guān)聯(lián)查詢(xún)代替子查詢(xún),避免臨時(shí)表復(fù)制
select distinct m.mobile_phone
from t_member m
left join (
select distinct s.mobile_phone
from t_order o, t_order_shipping
where o.order_id = s.order_id
and 0.status ='已支付'
) t
on m.mobile_phone = t.mobile_phone
where t.mobile_phone is null;
2、拆分sql,增加中間表;
統(tǒng)計(jì)需求,需要對(duì)兩組數(shù)據(jù)數(shù)進(jìn)行去重過(guò)濾,我們可以分別單獨(dú)寫(xiě)sql,將兩個(gè)數(shù)據(jù)將入中間表tmp_member和tmp_order中:
CREATE TABLE tmp_member SELECT
mobile_phone
FROM
t_member
WHERE
age >20;
CREATE TABLE tmp_order
select distinct s.mobile_phone
from t_order o, t_order_shipping
where o.order_id = s.order_id
and 0.status ='已支付'
給臨時(shí)表tmp_member和tmp_order的mobile_phone字段添加索引;
ALTER TABLE tmp_member ADD INDEX idx_mobile_phone (mobile_phone);
ALTER TABLE tmp_order ADD INDEX idx_mobile_phone (mobile_phone);
從tmp_member表中排除和tmp_order相同的電話(huà)號(hào)碼,剩下的就是需要統(tǒng)計(jì)的電話(huà)號(hào)碼;
DELETE tmp_member FROM tmp_member , tmp_order WHERE tmp_member .mobile_phone= tmp_order .mobile_phone;
此方案,將大的查詢(xún)結(jié)果,拆分成多個(gè)sql執(zhí)行,大大提升執(zhí)行時(shí)間;
親測(cè),此sql執(zhí)行不超過(guò)一分鐘。