How to simplify a select query that contains many internal selections and improve performance in PostgreSQL

Below is my select query

  SELECT 
   gtab04.Productid,
   gtab04.Product,
   gtab04.SaleUnit ,
   gtab04.Packing,
   gtab04.ConvFact,
   gtab04.PTR,
   gtab04.MRP, 
   gtab04.PRate,
   gtab04.PTR1,
   gtab04.PTR2,
   gtab04.Location,
   0 As ManufId,
   gtab07.PatentId,
   gtab07.Patent,
   gtab07.PatentCd,
   gtab15.TaxId,
   gtab15.TaxName, 
   gtab15.TaxType,
   gtab15.TaxRate, 
   gtab15.TxOMRP,
   ''::text As Manufacture,
CASE WHEN EXISTS(
      SELECT gtab10.Productid FROM gtab10 INNER JOIN gtab09 ON gtab09.TranId = 
      gtab10.TranId WHERE  gtab10.Productid = gtab04.Productid AND      
      gtab10.BatchId = gtab05.BatchId AND gtab09.acyrid = 7 limit 1) THEN 1 ELSE 0 END   
      AS 
   StkEntered,
      (SELECT SUM(gtab10.qty) FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId =  
      gtab09.TranId WHERE gtab10.Productid = gtab04.Productid AND    
      gtab10.BatchId = gtab05.BatchId AND gtab09.vrid = 6 AND gtab09.acyrid = 7) 
      +
      (SELECT SUM(gtab10.qty) FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId =  
      gtab09.TranId  WHERE gtab10.Productid = gtab04.Productid AND   
      gtab10.BatchId = gtab05.BatchId AND gtab09.vrid in (10,11,23,42,35) AND      
      gtab09.trdate < Cast('2014-06-01' AS timestamp) AND gtab09.acyrid = 7) 
   AS 
   OpeningInQty
      (SELECT SUM(gtab10.qty)FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId =    
      gtab09.TranId  WHERE gtab04.Productid = gtab10.Productid AND     
      gtab10.BatchId = gtab05.BatchId AND gtab09.vrid in( 12,32,33,44 ,45 ,46, 47 ,48 ,     
      49,18 , 34 ,25,27 ,15,26,24 , 43 ,36) AND gtab09.trdate < Cast('2014-06-01'   AS    
      timestamp) AND gtab09.acyrid = 7) AS 
   OpeningOutQty,
   0 AS PurchQty, 
   0 AS SRetQty, 
   0 AS PerInQty, 
   0 AS SaleQty, 
   0 AS StockInQty,
   0 AS StockOutQty, 
   0 AS SaleAmt, 
   0 AS DamageQty, 
   0 AS PRetQty, 
   0 AS PerOutQty,
      (SELECT SUM(gtab10.qty) FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId =     
      gtab09.TranId WHERE gtab04.Productid = gtab10.Productid AND     
      gtab10.BatchId = gtab05.BatchId AND gtab09.vrid in (12 ,32 ,33 ,44 ,45 ,46 ,47,48    
      ,49) AND (gtab09.trdate BETWEEN '2014-05-01' AND '2014-05-31')
      ) AS 
   PrMthSaleQty, 
      (SELECT (SUM(gtab10.qty * gtab10.ptr) ) FROM gtab10 INNER JOIN gtab09 ON   
      gtab10.TranId = gtab09.TranId WHERE gtab04.Productid = gtab10.Productid   AND    
      gtab10.BatchId = gtab05.BatchId AND gtab09.vrid in( 12, 32 , 33 , 44 ,45 ,46 , 47    
      ,48 , 49) AND (FreeOrRpl = 0 OR FreeOrRpl = 2) AND (gtab09.trdate BETWEEN  '2014-   
      05-01' AND '2014-05-31')
      ) AS 
   PrMthSaleAmt, 
   gtab04.LandCost,
   gtab05.PTR AS BatchPTR,
      (case when (
      gtab05.Fqty -  gtab05.FIQty)>0 then (gtab05.Fqty -  gtab05.FIQty) else 0 end) as 
   IssdFreeQty, 
   gtab05.MRP AS BatchMRP, 
   gtab05.PRate AS BatchPRate, 
   gtab04.StdPack,  
      (date_part('day',  (Select Min(Expiry) From gtab05 WHERE  gtab05.Productid =    
      gtab04.Productid And gtab05.Qty > gtab05.IQty)-Cast('2014-06-20' AS    
      timestamp))) AS 
   ExpDys, 
      (SELECT  gtab09.TrDate FROM gtab09 INNER JOIN gtab10 ON gtab09.TranId  
      =gtab10.TranId   
      where gtab09.VrId in (12,32,33,44,45,46, 47,48,49) And   
      gtab10.ProductId =gtab04.ProductId order by TrDate desc limit 1) As 
   LastSaleDate ,
   GTAB05.BatchId, 
   0 AS FreeSaleQty, 
   0 AS ReplSaleQty 
FROM
   gtab04 INNER JOIN  gtab15 ON gtab04.TaxId = gtab15.TaxId  LEFT JOIN gtab05 ON  
   gtab04.Productid = gtab05.Productid   INNER JOIN gtab07 ON gtab07.Patentid =      
   gtab04.Patentid  WHERE (gtab04.Masked = False AND gtab04.Banned = false)  AND  
   gtab04.patentid in  (321, 313 , 267 , 431) ORDER BY Patent, gtab04.Product


DEVELOP ANALYSIS As you can see in the above selection, I used a lot of internal selections, adding these internal selections to the main selection, the overall performance will slow down, and it will take a lot of time. I think (not sure) that my select query plan is bad.
Please help improve this one Query.

EDIT


Sample data (.backup) and query plan

+2
source share
2 answers

optimization:

  • Get all aggregated calculations in one selection group upon request.
  • .

:

with gtab4_5 as (
    select 
        gtab04.Productid, gtab05.BatchId
    FROM
       gtab04 
    LEFT JOIN gtab05 
        ON gtab04.Productid = gtab05.Productid  
    WHERE (gtab04.Masked = False AND gtab04.Banned = false)  
        AND  gtab04.patentid in  (321, 313 , 267 , 431) 
)
  SELECT 
   gtab04.Productid,
   gtab04.Product,
   gtab04.SaleUnit ,
   gtab04.Packing,
   gtab04.ConvFact,
   gtab04.PTR,
   gtab04.MRP, 
   gtab04.PRate,
   gtab04.PTR1,
   gtab04.PTR2,
   gtab04.Location,
   0 As ManufId,
   gtab07.PatentId,
   gtab07.Patent,
   gtab07.PatentCd,
   gtab15.TaxId,
   gtab15.TaxName, 
   gtab15.TaxType,
   gtab15.TaxRate, 
   gtab15.TxOMRP,
   ''::text As Manufacture,
   stats_ags.StkEntered AS StkEntered,
   stats_ags.OpeningInQty as OpeningInQty,
   stats_ags.OpeningOutQty as OpeningOutQty,
   0 AS PurchQty, 
   0 AS SRetQty, 
   0 AS PerInQty, 
   0 AS SaleQty, 
   0 AS StockInQty,
   0 AS StockOutQty, 
   0 AS SaleAmt, 
   0 AS DamageQty, 
   0 AS PRetQty, 
   0 AS PerOutQty,
   stats_ags.PrMthSaleQty as PrMthSaleQty,
   stats_ags.PrMthSaleAmt as PrMthSaleAmt,
   gtab04.LandCost,
   gtab05.PTR AS BatchPTR,
      (case when (
      gtab05.Fqty -  gtab05.FIQty)>0 then (gtab05.Fqty -  gtab05.FIQty) else 0 end) as 
   IssdFreeQty, 
   gtab05.MRP AS BatchMRP, 
   gtab05.PRate AS BatchPRate, 
   gtab04.StdPack,  
      (date_part('day',  (Select Min(Expiry) From gtab05 WHERE  gtab05.Productid =    
      gtab04.Productid And gtab05.Qty > gtab05.IQty)-Cast('2014-06-20' AS    
      timestamp))) AS 
   ExpDys, 
   stats_ags.LastSaleDate as LastSaleDate ,
   GTAB05.BatchId, 
   0 AS FreeSaleQty, 
   0 AS ReplSaleQty 
FROM
   gtab04 
INNER JOIN  gtab15 
    ON gtab04.TaxId = gtab15.TaxId  
LEFT JOIN gtab05 
    ON gtab04.Productid = gtab05.Productid   
INNER JOIN gtab07 
    ON gtab07.Patentid = gtab04.Patentid  
left join (
        SELECT gtab10_9.Productid, gtab10_9.BatchId, 
            max( case 
                when gtab10_9.acyrid = 7 
                then gtab10_9.Productid else null 
            end) as StkEntered,
            SUM( case 
                when gtab10_9.acyrid = 7 and ( 
                    gtab10_9.vrid = 6 
                or (
                    gtab10_9.vrid in (10,11,23,42,35) 
                    AND gtab10_9.trdate < Cast('2014-06-01' AS timestamp) 
                ) ) 
                then gtab10_9.qty else 0 
            end) as OpeningInQty,
            SUM( case 
                when gtab10_9.acyrid = 7 
                    and gtab10_9.vrid in( 12,32,33,44 ,45 ,46, 47 ,48 , 49,18 , 34 ,25,27 ,15,26,24 , 43 ,36) 
                    AND gtab10_9.trdate < Cast('2014-06-01'   AS timestamp)                 
                then gtab10_9.qty else 0 
            end) as OpeningOutQty,
            SUM( case 
                when gtab10_9.acyrid = 7 
                    and gtab10_9.vrid in(12 ,32 ,33 ,44 ,45 ,46 ,47,48,49) 
                    AND gtab10_9.trdate BETWEEN '2014-05-01' AND '2014-05-31'               
                then gtab10_9.qty else 0 
            end) as PrMthSaleQty,
            SUM( case 
                when gtab10_9.acyrid = 7 
                    and gtab10_9.vrid in( 12, 32 , 33 , 44 ,45 ,46 , 47,48 , 49) 
                    and (gtab10_9.FreeOrRpl = 0 OR gtab10_9.FreeOrRpl = 2) 
                    AND gtab10_9.trdate BETWEEN '2014-05-01' AND '2014-05-31'               
                then gtab10_9.qty * gtab10_9.ptr else 0 
            end) as PrMthSaleAmt,
            MAX( case 
                when gtab10_9.acyrid = 7 
                    and gtab10_9.VrId in (12,32,33,44,45,46, 47,48,49)
                    and (gtab10_9.FreeOrRpl = 0 OR gtab10_9.FreeOrRpl = 2) 
                then gtab10_9.TrDate else null 
            end) as LastSaleDate
        FROM (
            SELECT gtab10.*, gtab09.*
            FROM gtab10 
            INNER JOIN gtab09 ON gtab09.TranId = gtab10.TranId 
            inner join gtab4_5 on   gtab4_5.Productid = gtab10.Productid and gtab4_5.BatchId = gtab10.BatchId
        ) gtab10_9 
        group by gtab10_9.Productid, gtab10_9.BatchId
    ) stats_ags
    on stats_ags.Productid = gtab04.Productid 
    and stats_ags.BatchId = gtab05.BatchId
WHERE (gtab04.Masked = False AND gtab04.Banned = false)  
    AND  gtab04.patentid in  (321, 313 , 267 , 431) 
ORDER BY Patent, gtab04.Product

:

Sort  (cost=82928.96..82931.84 rows=1152 width=306) (actual time=447.433..450.191 rows=2421 loops=1)
  Sort Key: gtab07.patent, gtab04.product
  Sort Method: external merge  Disk: 680kB

:

Sort  (cost=2796544.62..2796547.50 rows=1152 width=278) (actual time=47865.883..47868.570 rows=2421 loops=1)
  Sort Key: gtab07.patent, gtab04.product
  Sort Method: external merge  Disk: 680kB

, ...

, PG 9.3

+2

, .

  • InQty , 1
  • LastSaleDate MAX,
  • ,
  • , gtab10 INNER JOIN gtab09 vrid. . FreeOrRpl .

SQL, , QUERY PLAN .

SELECT * FROM (
SELECT 
    gtab04.Productid,
    gtab04.Product,
    gtab04.SaleUnit ,
    gtab04.Packing,
    gtab04.ConvFact,
    gtab04.PTR,
    gtab04.MRP, 
    gtab04.PRate,
    gtab04.PTR1,
    gtab04.PTR2,
    gtab04.Location,
    0 As ManufId,
    gtab07.PatentId,
    gtab07.Patent,
    gtab07.PatentCd,
    gtab15.TaxId,
    gtab15.TaxName, 
    gtab15.TaxType,
    gtab15.TaxRate, 
    gtab15.TxOMRP,
    ''::text As Manufacture,
    CASE WHEN EXISTS(
      SELECT gtab10.Productid 
        FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId = gtab09.TranId
        WHERE  gtab10.Productid = gtab04.Productid AND gtab10.BatchId = gtab05.BatchId 
            AND gtab09.acyrid = 7 limit 1) THEN 1 ELSE 0 END   
  AS 
    StkEntered,
      (SELECT SUM(gtab10.qty) 
        FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId = gtab09.TranId 
        WHERE gtab10.Productid = gtab04.Productid AND gtab10.BatchId = gtab05.BatchId 
            AND (gtab09.vrid = 6 
                OR (gtab09.vrid in (10, 11, 23, 42, 35) AND gtab09.trdate < Cast('2014-06-01' AS timestamp))
            AND gtab09.acyrid = 7)  
  AS 
  OpeningInQty
      (SELECT SUM(gtab10.qty)
        FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId = gtab09.TranId  
        WHERE gtab10.Productid = gtab04.Productid AND gtab10.BatchId = gtab05.BatchId 
            AND gtab09.vrid in ( 12, 32, 33, 44, 45, 46, 47, 48, 49, 18, 34, 25, 27, 15, 26, 24, 43, 36) 
                AND gtab09.trdate < Cast('2014-06-01' AS timestamp) AND gtab09.acyrid = 7) 
    AS 
    OpeningOutQty,
    0 AS PurchQty, 
    0 AS SRetQty, 
    0 AS PerInQty, 
    0 AS SaleQty, 
    0 AS StockInQty,
    0 AS StockOutQty, 
    0 AS SaleAmt, 
    0 AS DamageQty, 
    0 AS PRetQty, 
    0 AS PerOutQty,
      (SELECT SUM(gtab10.qty) 
        FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId = gtab09.TranId 
        WHERE gtab10.Productid = gtab04.Productid AND gtab10.BatchId = gtab05.BatchId 
                AND gtab09.vrid in (12, 32, 33, 44, 45, 46, 47, 48, 49) 
                AND (gtab09.trdate BETWEEN '2014-05-01' AND '2014-05-31')
      ) 
    AS 
    PrMthSaleQty, 
      (SELECT SUM(gtab10.qty * gtab10.ptr) 
        FROM gtab10 INNER JOIN gtab09 ON gtab10.TranId = gtab09.TranId 
        WHERE gtab10.Productid = gtab04.Productid  
            AND gtab10.BatchId = gtab05.BatchId 
            AND gtab09.vrid in (12, 32, 33, 44, 45, 46, 47, 48, 49) 
            AND (gtab09.trdate BETWEEN  '2014-05-01' AND '2014-05-31') 
            AND (FreeOrRpl IN (0, 2))
      ) 
    AS 
    PrMthSaleAmt, 
    gtab04.LandCost,
    gtab05.PTR AS BatchPTR,
        (case when (
        gtab05.Fqty - gtab05.FIQty)>0 then (gtab05.Fqty -  gtab05.FIQty) else 0 end) as 
    IssdFreeQty, 
    gtab05.MRP AS BatchMRP, 
    gtab05.PRate AS BatchPRate, 
    gtab04.StdPack,  
    (date_part('day', (Select Min(Expiry) From gtab05 
    WHERE  gtab05.Productid = gtab04.Productid And gtab05.Qty > gtab05.IQty)-Cast('2014-06-20' AS    
        timestamp))) 
    AS 
    ExpDys, 
        (SELECT  MAX(gtab09.TrDate) FROM gtab09 INNER JOIN gtab10 ON gtab09.TranId  = gtab10.TranId   
        where gtab09.VrId in (12,32,33,44,45,46, 47,48,49) And gtab10.ProductId = gtab04.ProductId) 
  AS 
    LastSaleDate ,
    GTAB05.BatchId, 
    0 AS FreeSaleQty, 
    0 AS ReplSaleQty 
FROM gtab04 
    LEFT JOIN gtab05 ON gtab04.Productid = gtab05.Productid AND gtab04.patentid in (321, 313, 267, 431)
    INNER JOIN  gtab15 ON gtab04.TaxId = gtab15.TaxId      
    INNER JOIN gtab07 ON gtab04.Patentid = gtab07.Patentid   
WHERE (gtab04.Masked = False AND gtab04.Banned = false)  
) v
ORDER BY v.Patent, v.Product
+1

All Articles