2015-09-02 46 views
0

在我的項目中,有幾個很長的SQL語句。他們超過100行和多個選擇,連接和嵌套聯合。這很難閱讀,有必要進行優化。 我應該注意哪個方面?表結構,SQL語句本身還是別的什麼東西?如何優化這些長SQL語句?歡迎任何建議。如何優化長SQL語句?

以下是一段代碼。

select p.id,p.from_zone fromzone,p.to_zone tozone,p.action,p.status,saw.srcaddr,daw.dstaddr,aw2.protocol,case when aw2.port=';' then ' ' else aw2.port end port        
from policy p join (select sa.id,sa.device,concat(replace(group_concat(sa.nameshow),',',';<br />'),';') srcaddr from           
           (select sai.id,sai.device,sai.nameshow,max(sai.flag) flagw from 
             (select psa1.id,psa1.device,a1.network nameshow,case when a1.from_network<=#{srcAddr} and a1.to_network>=#{srcAddr} then 1 else 0 end flag from policy_source_destination_addr psa1 join address a1 on psa1.address=a1.name and psa1.device=a1.device and psa1.zone=a1.zone where psa1.device=#{deviceName} and psa1.direction='source' 
             union 
             select psa2.id,psa2.device,psa2.address nameshow,case when a2.from_network<=#{srcAddr} and a2.to_network>=#{srcAddr} then 1 else 0 end flag from policy_source_destination_addr psa2 join address_set as1 on psa2.address=as1.name and psa2.device=as1.device and psa2.zone=as1.zone 
                       join address a2 on as1.device=a2.device and as1.zone=a2.zone and as1.address=a2.name 
                       where psa2.device=#{deviceName} and psa2.direction='source' 
             union 
             select psa3.id,psa3.device,psa3.address nameshow,case when a5.from_network<=#{srcAddr} and a5.to_network>=#{srcAddr} then 1 else 0 end flag from policy_source_destination_addr psa3 join address_set as3 on psa3.address=as3.name and psa3.device=as3.device and psa3.zone=as3.zone 
                       join address_set as4 on as3.device=as4.device and as3.zone=as4.zone and as3.address=as4.name 
                       join address a5 on as4.device=a5.device and as4.zone=a5.zone and as4.address=a5.name 
                       where psa3.device=#{deviceName} and psa3.direction='source' 
             union 
             select psa3.id,psa3.device,psa3.address nameshow,1 flag from policy_source_destination_addr psa3 where psa3.device=#{deviceName} and psa3.direction='source' and upper(psa3.address)='ANY' 
             ) sai 
           group by sai.id,sai.device,sai.nameshow 
           ) sa 
        group by sa.id,sa.device having max(sa.flagw)=1) saw on p.id=saw.id and p.device=saw.device 
       join (select da.id,da.device,concat(replace(group_concat(da.nameshow),',',';<br />'),';') dstaddr from 
           (select dai.id,dai.device,dai.nameshow,max(dai.flag) flagw from 
             (select pda1.id,pda1.device,a3.network nameshow,case when a3.from_network<=#{dstAddr} and a3.to_network>=#{dstAddr} then 1 else 0 end flag from policy_source_destination_addr pda1 join address a3 on pda1.address=a3.name and pda1.device=a3.device and pda1.zone=a3.zone where pda1.device=#{deviceName} and pda1.direction='destination' 
             union 
             select pda2.id,pda2.device,pda2.address nameshow,case when a4.from_network<=#{dstAddr} and a4.to_network>=#{dstAddr} then 1 else 0 end flag from policy_source_destination_addr pda2 join address_set as2 on pda2.address=as2.name and pda2.device=as2.device and pda2.zone=as2.zone 
                       join address a4 on as2.device=a4.device and as2.zone=a4.zone and as2.address=a4.name 
                       where pda2.device=#{deviceName} and pda2.direction='destination' 
             union 
             select pda3.id,pda3.device,pda3.address nameshow,case when a6.from_network<=#{dstAddr} and a6.to_network>=#{dstAddr} then 1 else 0 end flag from policy_source_destination_addr pda3 join address_set as5 on pda3.address=as5.name and pda3.device=as5.device and pda3.zone=as5.zone 
                       join address_set as6 on as5.device=as6.device and as5.zone=as6.zone and as5.address=as6.name 
                       join address a6 on as6.device=a6.device and as6.zone=a6.zone and as6.address=a6.name 
                       where pda3.device=#{deviceName} and pda3.direction='destination' 
             union 
             select pda3.id,pda3.device,pda3.address nameshow,1 flag from policy_source_destination_addr pda3 where pda3.device=#{deviceName} and pda3.direction='destination' and upper(pda3.address)='ANY' 
             ) dai 
           group by dai.id,dai.device,dai.nameshow 
           ) da 
        group by da.id,da.device having max(da.flagw)=1) daw on p.id=daw.id and p.device=daw.device 
       join (select distinct ai.id,ai.device from           
          (select pa1.id,pa1.device 
           from policy_application pa1 join application ap1 on pa1.device=ap1.device and pa1.application=ap1.name 
           where pa1.device=#{deviceName} and upper(ap1.protocol)=#{protocol} and if(instr(ap1.destination_port,'-')=0,ap1.destination_port=#{port},substr(ap1.destination_port,1,instr(ap1.destination_port,'-')-1)+0<=#{port} and substr(ap1.destination_port,instr(ap1.destination_port,'-')+1)+0>=#{port}) 
           union 
           select pa2.id,pa2.device 
           from policy_application pa2 join application_set aps1 on pa2.application=aps1.name and pa2.device=aps1.device 
                   join application ap2 on aps1.application=ap2.name and aps1.device=ap2.device 
                   where pa2.device=#{deviceName} and upper(ap2.protocol)=#{protocol} and if(instr(ap2.destination_port,'-')=0,ap2.destination_port=#{port},substr(ap2.destination_port,1,instr(ap2.destination_port,'-')-1)+0<=#{port} and substr(ap2.destination_port,instr(ap2.destination_port,'-')+1)+0>=#{port}) 
           union 
           select pa3.id,pa3.device 
           from policy_application pa3 join application_set aps2 on pa3.application=aps2.name and pa3.device=aps2.device 
                   join application_term apt1 on aps2.application=apt1.name and aps2.device=apt1.device 
                   where pa3.device=#{deviceName} and upper(apt1.protocol)=#{protocol} and if(instr(apt1.destination_port,'-')=0,apt1.destination_port=#{port},substr(apt1.destination_port,1,instr(apt1.destination_port,'-')-1)+0<=#{port} and substr(apt1.destination_port,instr(apt1.destination_port,'-')+1)+0>=#{port}) 
           union 
           select pa4.id,pa4.device 
           from policy_application pa4 join application_map am4 on pa4.application=am4.name 
           where pa4.device=#{deviceName} and upper(am4.protocol)=#{protocol} and (if(am4.portvalue is null,1=1,if(length(am4.portvalue)-length(replace(am4.portvalue,'#',''))=2,SUBSTRING_INDEX(am4.portvalue, '#', 1)+0<=#{port} and SUBSTRING_INDEX(SUBSTRING_INDEX(am4.portvalue, '#', -2), '#', 1)+0>=#{port},SUBSTRING_INDEX(am4.portvalue, '#', 1)+0=#{port} or SUBSTRING_INDEX(SUBSTRING_INDEX(am4.portvalue, '#', -2), '#', 1)+0=#{port}))) 
          ) ai 
        ) aw on p.id=aw.id and p.device=aw.device 
       join (select a.id,a.device,a.protocol,concat(replace(group_concat(a.portshow),',',';<br />'),';') port from 
           (select pa5.id,pa5.device,ap3.protocol,case when substr(ap3.destination_port,1,instr(ap3.destination_port,'-')-1)=substr(ap3.destination_port,instr(ap3.destination_port,'-')+1) then substr(ap3.destination_port,1,instr(ap3.destination_port,'-')-1) else ap3.destination_port end portshow 
            from policy_application pa5 join application ap3 on pa5.device=ap3.device and pa5.application=ap3.name 
            where pa5.device=#{deviceName} 
            union 
            select pa6.id,pa6.device,ap4.protocol,case when substr(ap4.destination_port,1,instr(ap4.destination_port,'-')-1)=substr(ap4.destination_port,instr(ap4.destination_port,'-')+1) then substr(ap4.destination_port,1,instr(ap4.destination_port,'-')-1) else ap4.destination_port end portshow 
            from policy_application pa6 join application_set aps3 on pa6.application=aps3.name and pa6.device=aps3.device 
                    join application ap4 on aps3.application=ap4.name and aps3.device=ap4.device 
                    where pa6.device=#{deviceName} 
            union 
            select pa7.id,pa7.device,apt2.protocol,case when substr(apt2.destination_port,1,instr(apt2.destination_port,'-')-1)=substr(apt2.destination_port,instr(apt2.destination_port,'-')+1) then substr(apt2.destination_port,1,instr(apt2.destination_port,'-')-1) else apt2.destination_port end portshow 
            from policy_application pa7 join application_set aps4 on pa7.application=aps4.name and pa7.device=aps4.device 
                    join application_term apt2 on aps4.application=apt2.name and aps4.device=apt2.device 
                    where pa7.device=#{deviceName}           
            union 
            select pa8.id,pa8.device,am8.protocol,case when am8.portvalue is null then '' else concat('#',am8.portvalue) end portshow 
            from policy_application pa8 join application_map am8 on pa8.application=am8.name 
            where pa8.device=#{deviceName} 
           ) a 
        group by a.id,a.device,a.protocol) aw2 on p.id=aw2.id and p.device=aw2.device 
       where p.device=#{deviceName} and p.status=#{status} and p.action=#{action} 
       order by p.id+0 
       limit ${start},${rows} 
+1

其中一個陳述的例子將有助於回答或數據庫結構。 –

+2

您使用的是MySQL還是SQLServer ?,因爲標籤令人困惑 –

+0

我正在使用mysql。 – Wendy

回答

0

如果你在MySQL,首先,我想了解什麼an execution plan is的參考文檔。

你應該明白,當它運行您的查詢服務器執行計劃。例如,您可以看到服務器是否正在使用您擁有的索引,或者是否需要添加新索引。

有幾件事情可以做,以優化查詢。它可能是,例如,使結構非規範化或規範化它(這取決於查詢)。添加更多的索引,如果更新不是關鍵,partitionate表等

所以首先是TU使用EXPLAIN 一個查詢之前EXPLAIN EXTENDED命令:

EXPLAIN SELECT ... 
EXPLAIN EXTENDED SELECT ... 

形式存在你可以看到你的查詢背後發生了什麼,並做出你認爲會改善性能的改變。

0

第一步:儘量使用視圖或存儲過程,以使其更具可讀性。

下一步:檢查哪個查詢是通過使用查詢計劃或運行的每個視圖/查詢/存儲本身過程和檢查運行時間

0

發言的瓶頸哇,這是一些片SQL的,作爲一個〜40表加入。

鑑於其複雜性,我掙扎着看到任何明顯的方式來增加一個大的方式表現。

使用EXPLAIN可能會有所幫助,但是使用它的子查詢的數量可能只是抱怨大多數這些(因爲它不會使用索引來加入子查詢 - 同樣適用於查看哪些可能會使它更易讀,但可能無助於表現並可能妨礙它)。

有一些小的調整。對於子查詢aw你有一個額外的查詢圍繞正在做DISTINCT的主子查詢。由於主要的子查詢是4個聯合查詢,UNION語句將已經消除了重複。因此,執行DISTINCT的外部查詢是多餘的。

另外一點。您的主查詢正在檢查政策表。我認爲這會大量減少要處理的記錄數量,但是每個子查詢都會返回大量不符合此條件的行。根據每個子查詢中的策略執行額外連接可能會更快,從而減少每個子查詢返回的記錄(並在可以使用索引的級別執行)。

因此,像這樣: -

SELECT p.id,p.from_zone fromzone,p.to_zone tozone,p.action,p.status,saw.srcaddr,daw.dstaddr,aw2.protocol,CASE WHEN aw2.port=';' then ' ' else aw2.port end port        
FROM policy p 
JOIN 
(
    SELECT sa.id,sa.device,CONCAT(REPLACE(GROUP_CONCAT(sa.nameshow),',',';<br />'),';') srcaddr 
    FROM           
    (
     SELECT sai.id,sai.device,sai.nameshow,max(sai.flag) flagw 
     FROM 
     (
      SELECT psa1.id,psa1.device,a1.network nameshow,CASE WHEN a1.from_network<=#{srcAddr} AND a1.to_network>=#{srcAddr} then 1 else 0 end flag 
      FROM policy p 
      JOIN policy_source_destination_addr psa1 ON p.id=psa1.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      JOIN address a1 ON psa1.address=a1.name AND psa1.device=a1.device AND psa1.zone=a1.zone 
      WHERE psa1.device=#{deviceName} AND psa1.direction='source' 
      UNION 
      SELECT psa2.id,psa2.device,psa2.address nameshow,CASE WHEN a2.from_network<=#{srcAddr} AND a2.to_network>=#{srcAddr} then 1 else 0 end flag 
      FROM policy p 
      JOIN policy_source_destination_addr psa2 ON p.id=psa2.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      JOIN address_set as1 ON psa2.address=as1.name AND psa2.device=as1.device AND psa2.zone=as1.zone 
      JOIN address a2 ON as1.device=a2.device AND as1.zone=a2.zone AND as1.address=a2.name 
      WHERE psa2.device=#{deviceName} AND psa2.direction='source' 
      UNION 
      SELECT psa3.id,psa3.device,psa3.address nameshow,CASE WHEN a5.from_network<=#{srcAddr} AND a5.to_network>=#{srcAddr} then 1 else 0 end flag 
      FROM policy p 
      JOIN policy_source_destination_addr psa3 ON p.id=psa3.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      JOIN address_set as3 ON psa3.address=as3.name AND psa3.device=as3.device AND psa3.zone=as3.zone 
      JOIN address_set as4 ON as3.device=as4.device AND as3.zone=as4.zone AND as3.address=as4.name 
      JOIN address a5 ON as4.device=a5.device AND as4.zone=a5.zone AND as4.address=a5.name 
      WHERE psa3.device=#{deviceName} AND psa3.direction='source' 
      UNION 
      SELECT psa3.id,psa3.device,psa3.address nameshow,1 flag 
      FROM policy p 
      JOIN policy_source_destination_addr psa3 ON p.id=psa3.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      WHERE psa3.device=#{deviceName} AND psa3.direction='source' AND upper(psa3.address)='ANY' 
     ) sai 
     GROUP BY sai.id,sai.device,sai.nameshow 
    ) sa 
    GROUP BY sa.id,sa.device 
    HAVING MAX(sa.flagw)=1 
) saw 
ON p.id=saw.id AND p.device=saw.device 
JOIN 
(
    SELECT da.id,da.device,CONCAT(REPLACE(GROUP_CONCAT(da.nameshow),',',';<br />'),';') dstaddr 
    FROM 
    (
     SELECT dai.id,dai.device,dai.nameshow,max(dai.flag) flagw 
     FROM 
     (
      SELECT pda1.id,pda1.device,a3.network nameshow,CASE WHEN a3.from_network<=#{dstAddr} AND a3.to_network>=#{dstAddr} then 1 else 0 end flag 
      FROM policy p 
      JOIN policy_source_destination_addr pda1 ON p.id=pda1.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      JOIN address a3 ON pda1.address=a3.name AND pda1.device=a3.device AND pda1.zone=a3.zone where pda1.device=#{deviceName} AND pda1.direction='destination' 
      union 
      SELECT pda2.id,pda2.device,pda2.address nameshow,CASE WHEN a4.from_network<=#{dstAddr} AND a4.to_network>=#{dstAddr} then 1 else 0 end flag 
      FROM policy p 
      JOIN policy_source_destination_addr pda2 ON p.id=pda2.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      JOIN address_set as2 ON pda2.address=as2.name AND pda2.device=as2.device AND pda2.zone=as2.zone 
      JOIN address a4 ON as2.device=a4.device AND as2.zone=a4.zone AND as2.address=a4.name 
      WHERE pda2.device=#{deviceName} AND pda2.direction='destination' 
      UNION 
      SELECT pda3.id,pda3.device,pda3.address nameshow,CASE WHEN a6.from_network<=#{dstAddr} AND a6.to_network>=#{dstAddr} then 1 else 0 end flag 
      FROM policy p 
      JOIN policy_source_destination_addr pda3 ON p.id=pda3.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      JOIN address_set as5 ON pda3.address=as5.name AND pda3.device=as5.device AND pda3.zone=as5.zone 
      JOIN address_set as6 ON as5.device=as6.device AND as5.zone=as6.zone AND as5.address=as6.name 
      JOIN address a6 ON as6.device=a6.device AND as6.zone=a6.zone AND as6.address=a6.name 
      WHERE pda3.device=#{deviceName} AND pda3.direction='destination' 
      UNION 
      SELECT pda3.id,pda3.device,pda3.address nameshow,1 flag 
      FROM policy p 
      JOIN policy_source_destination_addr pda3 ON p.id=pda3.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
      WHERE pda3.device=#{deviceName} AND pda3.direction='destination' AND upper(pda3.address)='ANY' 
     ) dai 
     GROUP BY dai.id,dai.device,dai.nameshow 
    ) da 
    GROUP BY da.id,da.device 
    HAVING MAX(da.flagw)=1 
) daw 
ON p.id=daw.id AND p.device=daw.device 
join 
(
    SELECT pa1.id,pa1.device 
    FROM policy p 
    JOIN policy_application pa1 ON p.id=pa1.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
    JOIN application ap1 ON pa1.device=ap1.device AND pa1.application=ap1.name 
    WHERE pa1.device=#{deviceName} AND upper(ap1.protocol)=#{protocol} AND if(INSTR(ap1.destination_port,'-')=0,ap1.destination_port=#{port},SUBSTR(ap1.destination_port,1,INSTR(ap1.destination_port,'-')-1)+0<=#{port} AND SUBSTR(ap1.destination_port,INSTR(ap1.destination_port,'-')+1)+0>=#{port}) 
    UNION 
    SELECT pa2.id,pa2.device 
    FROM policy p 
    JOIN policy_application pa2 ON p.id=pa2.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
    JOIN application_set aps1 ON pa2.application=aps1.name AND pa2.device=aps1.device 
    JOIN application ap2 ON aps1.application=ap2.name AND aps1.device=ap2.device 
    WHERE pa2.device=#{deviceName} AND upper(ap2.protocol)=#{protocol} AND if(INSTR(ap2.destination_port,'-')=0,ap2.destination_port=#{port},SUBSTR(ap2.destination_port,1,INSTR(ap2.destination_port,'-')-1)+0<=#{port} AND SUBSTR(ap2.destination_port,INSTR(ap2.destination_port,'-')+1)+0>=#{port}) 
    UNION 
    SELECT pa3.id,pa3.device 
    FROM policy p 
    JOIN policy_application pa3 ON p.id=pa3.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
    JOIN application_set aps2 ON pa3.application=aps2.name AND pa3.device=aps2.device 
    JOIN application_term apt1 ON aps2.application=apt1.name AND aps2.device=apt1.device 
    WHERE pa3.device=#{deviceName} AND upper(apt1.protocol)=#{protocol} AND if(INSTR(apt1.destination_port,'-')=0,apt1.destination_port=#{port},SUBSTR(apt1.destination_port,1,INSTR(apt1.destination_port,'-')-1)+0<=#{port} AND SUBSTR(apt1.destination_port,INSTR(apt1.destination_port,'-')+1)+0>=#{port}) 
    UNION 
    SELECT pa4.id,pa4.device 
    FROM policy p 
    JOIN policy_application pa4 ON p.id=pa4.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
    JOIN application_map am4 ON pa4.application=am4.name 
    WHERE pa4.device=#{deviceName} AND upper(am4.protocol)=#{protocol} AND (if(am4.portvalue is null,1=1,if(length(am4.portvalue)-length(replace(am4.portvalue,'#',''))=2,SUBSTRING_INDEX(am4.portvalue, '#', 1)+0<=#{port} AND SUBSTRING_INDEX(SUBSTRING_INDEX(am4.portvalue, '#', -2), '#', 1)+0>=#{port},SUBSTRING_INDEX(am4.portvalue, '#', 1)+0=#{port} or SUBSTRING_INDEX(SUBSTRING_INDEX(am4.portvalue, '#', -2), '#', 1)+0=#{port}))) 
) aw 
ON p.id=aw.id AND p.device=aw.device 
JOIN 
(
    SELECT a.id,a.device,a.protocol,CONCAT(REPLACE(GROUP_CONCAT(a.portshow),',',';<br />'),';') port 
    FROM 
    (
     SELECT pa5.id,pa5.device,ap3.protocol,CASE WHEN SUBSTR(ap3.destination_port,1,INSTR(ap3.destination_port,'-')-1)=SUBSTR(ap3.destination_port,INSTR(ap3.destination_port,'-')+1) then SUBSTR(ap3.destination_port,1,INSTR(ap3.destination_port,'-')-1) else ap3.destination_port end portshow 
     FROM policy p 
     JOIN policy_application pa5 ON p.id=pa5.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
     JOIN application ap3 ON pa5.device=ap3.device AND pa5.application=ap3.name 
     WHERE pa5.device=#{deviceName} 
     UNION 
     SELECT pa6.id,pa6.device,ap4.protocol,CASE WHEN SUBSTR(ap4.destination_port,1,INSTR(ap4.destination_port,'-')-1)=SUBSTR(ap4.destination_port,INSTR(ap4.destination_port,'-')+1) then SUBSTR(ap4.destination_port,1,INSTR(ap4.destination_port,'-')-1) else ap4.destination_port end portshow 
     FROM policy p 
     JOIN policy_application pa6 ON p.id=pa6.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
     JOIN application_set aps3 ON pa6.application=aps3.name AND pa6.device=aps3.device 
     JOIN application ap4 ON aps3.application=ap4.name AND aps3.device=ap4.device 
     WHERE pa6.device=#{deviceName} 
     UNION 
     SELECT pa7.id,pa7.device,apt2.protocol,CASE WHEN SUBSTR(apt2.destination_port,1,INSTR(apt2.destination_port,'-')-1)=SUBSTR(apt2.destination_port,INSTR(apt2.destination_port,'-')+1) then SUBSTR(apt2.destination_port,1,INSTR(apt2.destination_port,'-')-1) else apt2.destination_port end portshow 
     FROM policy p 
     JOIN policy_application pa7 ON p.id=pa7.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
     JOIN application_set aps4 ON pa7.application=aps4.name AND pa7.device=aps4.device 
     JOIN application_term apt2 ON aps4.application=apt2.name AND aps4.device=apt2.device 
     WHERE pa7.device=#{deviceName}           
     UNION 
     SELECT pa8.id,pa8.device,am8.protocol,CASE WHEN am8.portvalue is null then '' else concat('#',am8.portvalue) END portshow 
     FROM policy p 
     JOIN policy_application pa8 ON p.id=pa8.id AND p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
     JOIN application_map am8 ON pa8.application=am8.name 
     WHERE pa8.device=#{deviceName} 
    ) a 
    GROUP BY a.id,a.device,a.protocol 
) aw2 
ON p.id=aw2.id AND p.device=aw2.device 
WHERE p.device=#{deviceName} AND p.status=#{status} AND p.action=#{action} 
ORDER BY p.id+0 
LIMIT ${start},${rows} 
0
  • order by p.id+0 - 是id一個VARCHAR控股多家。這很痛。

  • JOIN (SELECT ...) JOIN (SELECT ...)優化很差很差,因爲這些子查詢沒有索引。重新構造整個查詢,或使用添加索引的tmp表。

  • where pa7.device=#{deviceName} - policy_application需要INDEX(device)。那麼,提供SHOW CREATE TABLE怎麼樣,所以我們知道你已經有了什麼索引。

  • where psa1.device=#{deviceName} and psa1.direction='source' - policy_source_destination_addr需要INDEX(device, direction)(以任一順序)。

0

很難閱讀,不是因爲它很長,而是因爲缺乏格式化,使得它看起來很複雜,很難理解。

如果有的話,它應該被分解成多個行...

select 
    p.id    , 
    p.from_zone fromzone, 
    p.to_zone tozone , 
    p.action   , 
    p.status   , 
    saw.srcaddr 

目標,使其可讀通過減少阻止你的大腦從理解意義的視覺複雜...

select psa3.id    , 
     psa3.device   , 
     psa3.address nameshow, 
     case when a5.from_network <=#{srcAddr} and 
       a5.to_network <=#{srcAddr} 
      then 1 
      else 0 
     end flag 
from policy       p 
join policy_source_destination_addr psa3 on p.id   = psa3.id  and 
               p.device  = #{deviceName} and 
               p.status  = #{status}  and 
               p.action  = #{action} 
join address_set     as3 on psa3.address = as3.name  and 
               psa3.device = as3.device and 
               psa3.zone = as3.zone 
join address_s ... 

下的視覺複雜程度,更好的大腦會在代碼中識別有意義的複雜性,對四列如連接,列和表的別名功能和case語句,存在和價值存在等。

從我自己的代碼庫添加內部註釋,他們將是有益的...爲例...

with 
    cte_book_list as (
    -- retrieves a list of book_id's and the batch id 
    -- we do this to provide a list of book_id's that can be used in a number of 
    -- other CTE's below. The batch ID is included so this table doesn't have to be 
    -- referenced again. 
    select 
     rb.id        batch_id, 
     rb.client_id      client_id, 

線的數量無關。我有超過500行的陳述很容易閱讀,理解和維護。

0

我假設你已經知道如何優化正常大小的查詢,並且你只是想要一些關於如何馴服巨大查詢的複雜性的建議。

最近我不得不分析和優化一些大視圖(> 30連接)。 我已經創建了自己的一些工具(仍然是草稿,在這個階段我不願意分享),這些工具幫助我獲得了良好的結果。

可視化

我已經經歷過了一個,同時用FoundationDB Java parser叉,這樣我可以解析視圖和創建視圖結構的一個的MindMap(FreeMind具有簡單的基於XML格式)。這真的很有幫助,因爲有些模式在這裏和那裏重複出現,在圖表上很容易識別它們。

即使你沒有一個工具,它可以是一個好主意,提請查詢的結構圖 表中的條款和子查詢

(下面的例子繪製在Freemind中,具有「list」圖標的節點是實際的表格)。

enter image description here

分而治之

嘗試分解查詢:看自己的每一個子查詢,一個聯盟的每一個部分。嘗試獲取它們的內容並做一些實驗來簡化它們或對其進行優化。

A「局部優化」可能並不能確保你很大的進步,但是這種 階段重要的是要獲得在其所有 部分大型查詢熟悉。

測試,測試,測試

本地方法(「分而治之」)也有,你可以測試自己的每一個子查詢(如果總查詢是很慢的好處,測試總查詢的任何迴歸都需要時間)。如果查詢的所有部分都回到同一行,您可以集中精力使它們更有效地一起工作。

測試小型管理的塊

您的重新設計,在一個更高的水平

還在爲管理查詢「分而治之」我認爲有必要建立我的手工製作工具:在這種情況下,一個「查詢編譯器」。

基本上我複製了它自己的一個文件中的每一個子查詢,給了它我找到的最有意義的名稱,並且使用一個庫能夠在主要查詢中導入子查詢的源代碼(我使用了Freemarker )。

的目標是讓更多的「manegeable」 SQL,這樣,有 優化子查詢後,你可以分析和優化如何 子查詢中一起工作。

或者,您可以通過爲子查詢創建視圖來實現相同的結果,以便簡化高級查詢(我沒有這種可能性)。