工作中,經常有運營需求用于統計線上數據,實際場景中兩個百萬級表聯合查詢,往往會大大消耗查詢時間。
針對此問題,解決思路可以將sql,拆分,可利用中間表方式,對數據進行統計。
例如:訂單表 t_order,訂單收貨表t_order_shipping,會員表 t_member;
數據需求:獲取會員表中大于二十歲的手機號,排除2017年已支付訂單的手機號。
根據此需求,我們可以寫出如下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 ='已支付';
);
當t_member 千萬級別,t_order和t_order_shipping百萬級別數據量時,以上查詢將需要非常多時間,大量的時間都用在了復制臨時表和發送查詢結果上。
經測試,mobile_phone加索引的請求下,該sql大概執行半小時。
優化方案:
1、可使用關聯查詢代替子查詢,避免臨時表復制
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,增加中間表;
統計需求,需要對兩組數據數進行去重過濾,我們可以分別單獨寫sql,將兩個數據將入中間表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 ='已支付'
給臨時表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
相同的電話號碼,剩下的就是需要統計的電話號碼;
DELETE tmp_member FROM tmp_member , tmp_order WHERE tmp_member .mobile_phone= tmp_order .mobile_phone;
此方案,將大的查詢結果,拆分成多個sql執行,大大提升執行時間;
親測,此sql執行不超過一分鐘。