我有一个巨大的查询,这些年来逐渐增长,所有的iv都是为了满足增长而添加子程序。我现在的问题是这个查询大约需要3分钟才能运行。有人可以帮我优化这个查询
SELECT ENTRY_1.REP_CODE,CONTACT_1.NAME,
(select sum((d2.total_goods-d2.total_cost)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where ((d2.detail_type = 'O' and d2.charged_qty<d2.qty
and d2.nocharge_qty=0)
or (d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF'))
or (( e2.entry_type = 'SJIN' ) and ( d2.total_goods = 0 )))
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_GP,
-- get the month to date sales
(select sum((d2.total_goods)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where ((d2.detail_type = 'O' and d2.charged_qty<d2.qty
and d2.nocharge_qty=0)
or (d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF'))
or (( e2.entry_type = 'SJIN' ) and ( d2.total_goods = 0 )))
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_SALES,
--
(select sum((d2.total_goods-d2.total_cost)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where (d2.detail_type = 'O' and d2.charged_qty<d2.qty and d2.nocharge_qty=0)
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) ORD_GP,
(select sum((d2.total_goods)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where (d2.detail_type = 'O' and d2.charged_qty<d2.qty and d2.nocharge_qty=0)
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) ORD_SALE,
(select sum((d2.total_goods-d2.total_cost)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF')
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) INV_GP,
(select sum((d2.total_goods)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF')
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) INV_SALE,
(select sum((d2.total_goods-d2.total_cost)*et2.sign)
from detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where ( e2.entry_type = 'SJIN' ) and ( d2.total_goods = 0 )
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) EXPEND,
(select count(distinct e2.trader_id)
from entry e2
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where e2.entry_type in('SORD','SINV','DREC')
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_PUR,
(select count(distinct e2.our_reference)
from entry e2
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where e2.entry_type in('SORD') and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_ORD,
(select sum((d1.total_goods-d1.total_cost)*et.sign)
from detail d1
join entry e1 on d1.entry_id=e1.entry_id
join entry_type et on et.entry_type=e1.entry_type
left outer join detail d2 on d2.detail_id=d1.link_detail_id
join rep r2 on e1.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where ((d1.detail_type = 'O' and d1.charged_qty<d1.qty and d1.nocharge_qty=0 and e1.entry_type in ('SORD','SRTN')
and e1.our_reference not like 'AUTO%')
or (d1.detail_type = 'N' and e1.entry_type in('SCRN','DREC','DSRF'))
or (( e1.entry_type = 'SJIN' ) and ( d1.total_goods = 0 ))
or(( d1.DETAIL_TYPE = 'N' ) and ( e1.ENTRY_TYPE = 'SINV' ) and ( e1.TAXPOINT_DATE = CURRENT_DATE ) and ( d2.DETAIL_TYPE = 'A' )))
and e1.taxpoint_date=current_date
and c2.contact_id=contact_1.contact_id) DAILY_GP,
(select count(*)
from entry e2
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where e2.entry_type='SORD'
and e2.taxpoint_date=current_date
and c2.contact_id=contact_1.contact_id) NUM_ORDS,
(select count(tn.note)
from trader_notes tn join trader t on tn.trader_id=t.trader_id
join rep r2 on t.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where tn.created between current_date
and (current_date+1)
and tn.note_type in ('N','S','G')
and tn.note is not null
and c2.contact_id=contact_1.contact_id) NOTES
FROM ENTRY ENTRY_1 INNER JOIN REP REP_1 ON
(REP_1.REP_CODE = ENTRY_1.REP_CODE)
INNER JOIN CONTACT CONTACT_1 ON
(CONTACT_1.CONTACT_ID = REP_1.CONTACT_ID)
WHERE ( ENTRY_1.ENTRY_TYPE = 'SJOB' )
AND ( ENTRY_1.AGE = 0 )
你可以看到这两个子程序是相同的,唯一的区别是select语句的总和。有没有办法我只能运行其中一个子程序来查找总和?
我显示了完整查询,有人可以帮助我吗?
答案 0 :(得分:5)
SELECT ENTRY_1.AGE, ENTRY_1.REP_CODE,CONTACT_1.NAME, ENTRY_1.GOODS,
sum((d2.total_goods-d2.total_cost)*et2.sign)
, sum((d2.total_goods)*et2.sign)
.
.
. CODE TAKEN OUT
.
.
FROM
detail d2
join entry e2 on d2.entry_id=e2.entry_id
join entry_type et2 on et2.entry_type=e2.entry_type
join rep r2 on e2.rep_code=r2.rep_code
join contact c2 on r2.contact_id=c2.contact_id
where ((d2.detail_type = 'O' and d2.charged_qty<d2.qty
and d2.nocharge_qty=0)
or (d2.detail_type = 'N' and e2.entry_type in('SINV','SCRN','DREC','DSRF'))
or (( e2.entry_type = 'SJIN' ) and ( d2.total_goods = 0 )))
and c2.contact_id=contact_1.contact_id
and (e2.year_num=entry_1.year_num and e2.period_num=entry_1.period_num)) MTD_GP
, ENTRY ENTRY_1 INNER JOIN REP REP_1 ON
(REP_1.REP_CODE = ENTRY_1.REP_CODE)
INNER JOIN CONTACT CONTACT_1 ON
(CONTACT_1.CONTACT_ID = REP_1.CONTACT_ID)
WHERE ( ENTRY_1.ENTRY_TYPE = 'SJOB' )
AND ( ENTRY_1.AGE = 0 )
当然,这个想法是你将连接移到下面 - 将它们从SELECT子句中取出并将它们(一次)放入FROM和WHERE子句中。 - 我做的剪切和粘贴是不对的,但是你明白了(你也没有提供完整的查询以实际用作基础)
答案 1 :(得分:1)
经过一番评论后,我觉得我有一些东西可供你试一试......你可能需要调整一些,但希望能为你带来很多困惑。查询的最大杀手是如何使COUNT(DISTINCT)值不基于合格条目的主要标准......
话虽如此,看着你所有的联接,你正在从入口表到一个rep表,从rep到一个联系表。如果代表ID总是指向联系人以获得相同的“ID”,那么看起来代码就像是销售人员联系表中实际“contact_id”的快捷方式。也就是说,无需加入Rep表或Contact表。销售标题具有“REP_CODE”,因此这可以消除所有连接和分组(除非您另行更正)。
下一步。我从内心开始有两个初步查询。您的原始OUTERMOST查询只有基于条目类型“SJOB”和Age = 0的条目ID。因此,我的“PQ1”(预查询1)将只获得符合该条件并获得代码的条目,联系人ID和姓名以及相应的年份/期间。这都是DISTINCT。
然后根据相同的rep,year和period将此结果连接到条目表(e2别名)(因此消除了一堆其他连接/其他位置)。然后将e2加入细节表以获取所有项目。这是“PQ2”(预查询2)的开始。
由于我收到了针对特定联系人代表,年份和期间的明确信息,看起来您正在为主要PQ1查询中的任何人获取整体活动,并在同一合格年份/期间内查看其总体销售活动。
您获得Gross,Sales和Invoiced金额的where子句有3个条件。这是PreQuery 2条件的主要“WHERE”子句。在字段列表中,由于它们基本上都具有相同的资格标准,所以我刚刚添加了
SUM(case When ......)为MTD_GP, 总和(情况......)作为MTD_Sales, order_GP和Order_Sales的sum()(基于FIRST Where部分) INVOICED_GP和INVOICED_Sales的sum()(基于SECOND Where部分) EXPEND的sum()(基于where部分的THIRD部分)
一旦我完成了所有内容,并按照给定的代表,期间,年份进行了汇总,我将结果作为完成所有其他计数distinct(),count(*)等条目的基础。同样,因为我知道我已经将它分解为给定的Rep,所以我可以以类似的方式再次查询条目2表。
希望这能够大大澄清我对您尝试完成的查询的看法,并启动您进入更好/最终的解决方案。
从您的联接中,您的“代表”似乎有一个联系人ID,其中多个代表都可以指向一个“联系人”。无需显式JOIN仅联系已存在于Rep表中的联系人ID ...因此,您可以简化联接到Rep表的条目表并获取联系人ID。
select
PQ2.Rep_Code,
PQ2.Contact_ID,
PQ2.Name,
PQ2.Year_Num,
PQ2.Period_Num,
PQ2.MTD_GP,
PQ2.MTD_SALES,
PQ2.ORD_GP,
PQ2.ORD_SALE,
PQ2.INV_GP,
PQ2.INV_SALE,
PQ2.EXPEND,
( select count(distinct e2.trader_id)
from entry e2
where e2.rep_code = PQ2.Rep_Code
and e2.Year_Num = PQ2.Year_Num
and e2.Period_Num = PQ2.Period_Num
and e2.entry_type in ('SORD','SINV','DREC') ) MTD_PUR,
( select count(distinct e2.trader_id)
from entry e2
where e2.rep_code = PQ2.Rep_Code
and e2.Year_Num = PQ2.Year_Num
and e2.Period_Num = PQ2.Period_Num
and e2.entry_type = 'SORD' ) MTD_ORD,
( select count(*)
from entry e2
where e2.rep_code = PQ2.Rep_Code
and e2.entry_type='SORD'
and e2.taxpoint_date = current_date ) NUM_ORDS,
( select count(tn.note)
from trader_notes tn
join trader t on tn.trader_id = t.trader_id
AND t.rep_code = PQ2.Rep_Code
where
tn.created between current_date and (current_date + 1)
and tn.note_type in ('N','S','G')
and tn.note is not null ) NOTES,
( select
sum( ( d3.total_goods - d3.total_cost) * et3.sign)
from
entry e3
join detail d3 on e3.entry_id = d3.entry_id
left join detail dLink on d3.link_detail_id = dLink.detail_id
join entry_type et3 on e3.entry_type = et3.entry_type
where
PQ2.Rep_Code = e3.Rep_Code
AND e3.taxpoint_date = current_date
AND ( ( d3.detail_type = 'O'
and d3.charged_qty < d3.qty
and d3.nocharge_qty = 0
and e3.entry_type in ('SORD','SRTN')
and e3.our_reference not like 'AUTO%'
)
or ( d3.detail_type = 'N'
and e3.entry_type in ('SCRN','DREC','DSRF')
)
or ( e3.entry_type = 'SJIN'
and d3.total_goods = 0
)
or ( d3.DETAIL_TYPE = 'N'
and e3.ENTRY_TYPE = 'SINV'
and e3.TAXPOINT_DATE = CURRENT_DATE
and dLink.DETAIL_TYPE = 'A'
)
)
) DAILY_GP
FROM
( select
PQ1.Rep_Code,
PQ1.Contact_ID,
PQ1.Name,
PQ1.Year_Num,
PQ1.Period_Num,
sum( (d2.Total_Goods - d2.Total_Cost ) * et2.Sign ) as MTD_GP,
sum( d2.Total_Goods * et2.Sign ) as MTD_SALES,
sum( case when d2.detail_type = 'O'
and d2.charged_qty < d2.qty
and d2.nocharge_qty = 0
then (d2.total_goods - d2.total_cost) * et2.sign
else 0 end ) ORD_GP,
sum( case when d2.detail_type = 'O'
and d2.charged_qty < d2.qty
and d2.nocharge_qty = 0
then (d2.total_goods * et2.sign )
else 0 end ) ORD_SALE,
sum( case when d2.detail_type = 'N'
and e2.entry_type in('SINV','SCRN','DREC','DSRF')
then (d2.total_goods - d2.total_cost) * et2.sign
else 0 end ) INV_GP,
sum( case when d2.detail_type = 'N'
and e2.entry_type in('SINV','SCRN','DREC','DSRF')
then (d2.total_goods * et2.sign )
else 0 end ) INV_SALE,
sum( case when e2.entry_type = 'SJIN'
and d2.total_goods = 0
then (d2.total_goods - d2.total_cost) * et2.sign
else 0 end ) EXPEND
FROM
( select distinct
r1.rep_code,
r1.contact_id,
c1.Name,
e1.year_num,
e1.period_num
from
entry e1
join rep r1 ON e1.rep_code = r1.rep_code
join contact c1 on r1.contact_id = c1.contact_id
where
e1.entry_type = 'SJOB'
and e1.age = 0 ) PQ1
JOIN entry e2 on PQ1.rep_code = e2.rep_code
AND PQ1.Year_Num = e2.Year_Num
AND PQ1.Period_Num = e2.Period_Num
JOIN Detail d2 on e2.Entry_ID = d2.Entry_ID
JOIN Entry_Type et2 on e2.entry_type = et2.entry_type
WHERE
( d2.detail_type = 'O'
and d2.charged_qty < d2.qty
and d2.nocharge_qty = 0 )
or ( d2.detail_type = 'N'
and e2.entry_type in('SINV','SCRN','DREC','DSRF') )
or ( e2.entry_type = 'SJIN'
and d2.total_goods = 0 )
GROUP BY
PQ1.Rep_Code,
PQ1.Contact_ID,
PQ1.Name,
PQ1.Year_Num,
PQ1.Period_Num ) as PQ2
答案 2 :(得分:0)
作为一般规则,您不应将相关子查询用于数据集最终会很大的任何查询,因为它们的行为类似于游标并逐行运行。您应该使用连接到表或派生表。
对于SQl服务器我是这么认识的,它可能在其他数据库中有所不同。