業務過程中碰到多個join引起慢SQL問題,數據量不大,但查詢很慢,搜到一片BLog,參考解決。
業務過程不記錄,以blog內容重現:
原SQL:
select distinct abc.pro_col1, abc.col3 from t0 p INNER JOIN t1 abc on p.id=abc.par_col2 inner join t2 s on s.col3=abc.col3 inner join t3 po on po.id=s.col4 where p.state=2 and po.state=3 order by abc.pro_col1, abc.col3;
以上SQL同:
select select distinct abc.pro_col1, abc.col3 from t0 p, t1 abc, t2 s, t3 po where p.id=abc.par_col2 and s.col3=abc.col3 and po.id=s.col4 and p.state=2 and po.state=3 order by abc.pro_col1, abc.col3;
分析優化:
從語義來看,這條SQL是在經過幾個JOIN后取其中一個表的兩個字段的唯一值。
但是每一次關聯,都可能產生冗余的值,所以導致了結果集越來越龐大。
修改建議,每一次JOIN都輸出唯一值,減少冗余。即多次JOIN導致查詢結果集越來越大(笛卡兒積),可以把過濾條件放在前面。
select distinct pro_col1, col3 from ( select distinct t1.pro_col1, t1.col3, s.col4 from ( select distinct abc.pro_col1, abc.col3 from t1 abc INNER JOIN t0 p on (p.id = abc.par_col2 and p.state=2) ) t1 inner join t2 s on (s.col3 = t1.col3) ) t2 inner join t3 po on (po.id = t2.col4 and po.state=3) order by t2.pro_col1, t2.col3 ;
以下實例:
postgres=# create table rt1(id int, info text); CREATE TABLE postgres=# create table rt2(id int, info text); CREATE TABLE postgres=# create table rt3(id int, info text); CREATE TABLE postgres=# create table rt4(id int, info text); CREATE TABLE postgres=# insert into rt1 select generate_series(1,1000),'test'; INSERT 0 1000 postgres=# insert into rt2 select 1,'test' from generate_series(1,1000); INSERT 0 1000 postgres=# insert into rt3 select 1,'test' from generate_series(1,1000); INSERT 0 1000 postgres=# insert into rt4 select 1,'test' from generate_series(1,1000); INSERT 0 1000
對比:
優化后查詢:
從執行時間可以看到,優化后的速度何止是快。