我的子查询正在减慢这个过程。任何优化方法?

时间:2017-06-30 16:12:12

标签: sql sql-server performance subquery

我使用子查询编写代码,但速度太慢。我正在寻找一种可以优化此查询过程的解决方案。它旨在返回6列 - 采购订单编号,采购订单行编号,每个采购订单行的金额,每个采购订单编号的采购单行数,每个采购订单编号的行金额总和,每个采购订单编号按行数分类。下面是我写的示例表和实际查询。非常感谢您的帮助!

|PO NUMBER |PO LINE|LINE AMOUNT|TOTAL PO LINES|TOTAL PO AMOUNT|TOTAL PO GROUP|
|1721574   |   1   |   10.76   |      1       |     10.76     |   $0-100     |
|1722154   |   1   |   30.00   |      1       |     30.00     |   $0-100     |
|1723538   |   1   |   15.97   |      4       |     65.63     |   $0-100     |
|1723538   |   2   |   11.23   |      4       |     65.63     |   $0-100     |
|1723538   |   3   |   15.97   |      4       |     65.63     |   $0-100     |
|1723538   |   4   |   22.46   |      4       |     65.63     |   $0-100     |
|1723877   |   1   |   15.70   |      1       |     15.70     |   $0-100     |

查询

select ph.ponumber, 
       pl.poline, 
       pl.polinebasemerchamount, 
       (select count(pl2.poline) 
               from dbo.polineflat as pl2 
               inner join dbo.poheader as ph2 
               on ph2.pokey = pl2.pokey 
               where ph2.pokey = ph.pokey 
               group by ph2.ponumber), 
       (select sum(pl2.polinebasemerchamount) 
               from dbo.polineflat as pl2 
               inner join dbo.poheader as ph2 
               on ph2.pokey = pl2.pokey 
               where ph2.pokey = ph.pokey 
               group by ph2.ponumber), 
       (select case 
                   when sum(pl2.PoLineBaseMerchAmount) between 0 and 100 then '$0-100'
                   when sum(pl2.polinebasemerchamount) between 101 and 500 then '$101-500'
                   when sum(pl2.polinebasemerchamount) between 501 and 1000 then '$501-1000'
                   else '1000+' end
               from dbo.polineflat as pl2 
               inner join dbo.poheader as ph2 
               on ph2.pokey = pl2.pokey 
               where ph2.pokey = ph.pokey 
               group by ph2.ponumber) 
from dbo.poheader as ph
inner join dbo.polineflat as pl on ph.pokey = pl.pokey

5 个答案:

答案 0 :(得分:1)

可以使用def put(self, request, *args, **kwargs): serializer = self.serializer_class(self.get_object(), data=request.data, partial=True) if serializer.is_valid(): instance = serializer.save() # Generate a new token payload = jwt_payload_handler(instance) token = jwt.encode(payload, settings.SECRET_KEY) response = JsonResponse({'token': token.decode('unicode_escape')}) response.status = 200 return response else: response = JsonResponse({'errors': serializer.errors}) response.status = 500 return response 将三个sub-queries合并为一个查询。使用Cross Apply优于相关子查询的一个优点是它可以在Cross Apply列表中返回多个列

select

注意:我删除了子查询中的SELECT ph.ponumber, pl.poline, pl.polinebasemerchamount, oa.poline_count, oa.polinebasemerchamount_sum, CASE WHEN oa.polinebasemerchamount_sum BETWEEN 0 AND 100 THEN '$0-100' WHEN oa.polinebasemerchamount_sum BETWEEN 101 AND 500 THEN '$101-500' WHEN oa.polinebasemerchamount_sum BETWEEN 501 AND 1000 THEN '$501-1000' ELSE '1000+' END AS Range FROM dbo.poheader AS ph CROSS Apply (SELECT Count(pl2.poline) AS poline_count, Sum(pl2.polinebasemerchamount) AS polinebasemerchamount_sum FROM dbo.polineflat AS pl2 WHERE pl2.pokey = ph.pokey) oa ,因为它应该没用,否则会在原始查询中抛出错误

更新:要进一步改进查询,请创建以下Group By

Non clustered indexes

答案 1 :(得分:1)

我会计算一次总和,然后在父查询中进行处理:

SELECT ponumber, poline, polinebasemerchamount, polineCount, polineFlatSum,
    CASE 
        WHEN polineFlatSum between 0 and 100 then '$0-100'
        WHEN polineFlatSum between 101 and 500 then '$101-500'
        WHEN polineFlatSum  between 501 and 1000 then '$501-1000'
        ELSE '1000+' 
    END AS polineFlatSumString
from
(
    select ph.ponumber, 
           pl.poline, 
           pl.polinebasemerchamount, 
           (select count(pl2.poline) 
                   from dbo.polineflat as pl2 
                   inner join dbo.poheader as ph2 
                   on ph2.pokey = pl2.pokey 
                   where ph2.pokey = ph.pokey 
                   group by ph2.ponumber) AS polineCount, 
           (select sum(pl2.PoLineBaseMerchAmount) 
                   from dbo.polineflat as pl2 
                   inner join dbo.poheader as ph2 
                   on ph2.pokey = pl2.pokey 
                   where ph2.pokey = ph.pokey 
                   group by ph2.ponumber) AS polineFlatSum,        
    from dbo.poheader as ph
        inner join dbo.polineflat as pl on ph.pokey = pl.pokey
) T

答案 2 :(得分:0)

试试这个......

select ph2.ponumber, 
       pl2.poline, 
       pl2.polinebasemerchamount, 
       count(pl2.poline) ,
       sum(pl2.polinebasemerchamount) ,
case  when sum(pl2.PoLineBaseMerchAmount) between 0 and 100 then '$0-100'
      when sum(pl2.polinebasemerchamount) between 101 and 500 then '$101-500'
      when sum(pl2.polinebasemerchamount) between 501 and 1000 then '$501-1000'
           else '1000+' end

from dbo.poheader as ph2
inner join dbo.polineflat as pl2
on ph.pokey = pl.pokey
inner join dbo.polineflat as pl2 
on ph.pokey = pl2.pokey
group by  ph2.ponumber, 
       pl2.poline, 
       pl2.polinebasemerchamount

答案 3 :(得分:0)

看起来你正在通过使用选择

进行分组
select ph.ponumber, 
   pl.poline, 
   pl.polinebasemerchamount, 
   count(pl.poline) as total_count,
   sum(pl.polinebasemerchamount) as total_sum,
case  when sum(pl.PoLineBaseMerchAmount) between 0 and 100 then '$0-100'
  when sum(pl.polinebasemerchamount) between 101 and 500 then '$101-500'
  when sum(pl.polinebasemerchamount) between 501 and 1000 then '$501-1000'
       else '1000+' end as total_group

from dbo.poheader as ph
inner join dbo.polineflat as pl
on ph.pokey = pl.pokey
group by     ph.ponumber, pl.poline, pl.polinebasemerchamount 

答案 4 :(得分:0)

在这些情况下,我实际上使用#temp表。我发现它们在性能上要好得多,我可以更好地控制我想要的结果。它也更容易理解(至少对于我和其他阅读它们的人来说)。我回答这篇文章的目的是帮助您利用这种类型的编码。而不是直接给你答案,你可以复制和粘贴,然后点击F5。

注意:您可以随意命名对您有意义的临时表。您还可以使用LEFT JOIN / RIGHT JOIN来获取dbo.poheader中的所有值,并查看值与您的#temp表匹配。您可能需要切换ID&temp / temp表以适合您需要的结果。我希望这可以帮助你理解。

 --Insert Subquery 1 into a #temp1

 select count(pl2.poline) as Count1, ph2.ponumber 
 Into #temp1
 from dbo.polineflat as pl2 
           inner join dbo.poheader as ph2 
           on ph2.pokey = pl2.pokey 
           where ph2.pokey = ph.pokey 
           group by ph2.ponumber)

  --Insert Subquery 2 into #temp2

  select sum(pl2.polinebasemerchamount) as Sum1, ph2.ponumber
  into #temp2
           from dbo.polineflat as pl2 
           inner join dbo.poheader as ph2 
           on ph2.pokey = pl2.pokey 
           where ph2.pokey = ph.pokey 
           group by ph2.ponumber

  --Insert Subquery 3 into #temp3. Pull pl2.polinebasemerchant from #temp2

   select case 
    when sum(#temp2.PoLineBaseMerchAmount) between 0 and 100 then '$0-100'
    when sum(#temp2.polinebasemerchamount) between 101 and 500 then'$101-500'
    when sum(#temp2..polinebasemerchamount) between 501 and 1000 then '$501-1000'
    else '1000+' end 'DollarAmounts',ph2.ponumber
    into #temp3
    from dbo.polineflat as pl2 
    inner join dbo.poheader as ph2 
     on ph2.pokey = pl2.pokey 
     where ph2.pokey = ph.pokey 
     group by ph2.ponumber


 -- Select here with the temp table groups
  select ph.ponumber, 
         pl.poline, 
         pl.polinebasemerchamount,
         #temp1.Count1,
         #temp2.Sum1,
         #temp3.DollarAmounts

   from dbo.poheader as ph
   join dbo.polineflat as pl on ph.pokey = pl.pokey

   --join your temp tables here
   Join #temp1 on #temp1.ponumber = ph.ponumber
   join #temp2 on #temp2.ponumber = ph.ponumber
   join #temp3 on #temp3.ponumber = ph.ponumber


   TRUNCATE TABLE #temp1
   TRUNCATE TABLE #temp2
   TRUNCATE TABLE #temp3