这似乎需要花费很长时间才能处理大型数据集。将第一个和最后三个查询合并为1会使它更快吗?有没有人对什么可能使它更快有任何意见?我很感激。
update "detail" set bal = (units * amount) where code_type = 'AB';
update "detail" set bal = (units * amount) where code_type = 'CD';
update "detail" set bal = (units * amount) where code_type = 'EF';
update "detail" set bal = (units * amount * -1) where code_type = 'GH';
update "detail" set bal = (units * amount * -1) where code_type = 'IK';
update "detail" set bal = (units * amount * -1) where code_type = 'LM';
update "detail" set bal = 0 where code_type = 'NO';
另外 -
update bill set pay =
(select round(sum(bd1.bal),2) from "detail" bd1 where
bd1.inv = bill.inv and
(bd1.code_type = 'AB' or bd1.code_type = 'CD'));
update bill set pay = 0 where pay is null;
update bill set cost =
(select round(sum(bd2.bal),2) from "detail" bd2 where
bd2.inv = bill.inv and
(not (bd2.code_type = 'AB' or bd2.code_type = 'CD')));
update bill set cost = 0 where cost is null;
update bill set balance = round(cost + pay,2);
由于
答案 0 :(得分:3)
性能可能很糟糕,因为您正在更新整个表,并且您要更新它十二次。如果表格非常大,那就可以了 时间。此外,这两个嵌入式子查询将每行运行一次。哎哟。
以下frankenquery将所有内容都汇总到一个语句中。它仍然必须击中整个表,但至少它只执行一次。我无法检查语法 或者根据数据对其进行测试,但是这个或类似它的东西应该可以工作。
EDITED,将其拆分为两个更新(因此,需要两个表扫描)
UPDATE Detail
set
bal = case
when code_type in ('AB','CD','EF') then bi.units * bi.amount
when code_type in ('gh','ik','lm') then -bi.units * bi.amount
when code_type = 'NO' then 0
else bal -- If none of the above, change nothing
end
和
UPDATE Bill
set
payments = isnull(bd1.amount, payments) -- This changes nothing if nothing was calculated
,pay = case
when pay is null then 0
else pay
end
-- Ok, problem with cost: what if calculated amount is 0 and current value is non-zero?
-- I've insufficient data here to correctly resolve all the possible permutations
,cost = case
when bd2.amount is not null then cost
when cost is null then 0
else cost
end
,balance = round(charges + isnull(bd1.amount, bi.payments), 2)
from Bill bi
-- These subqueries could be combined into one using similar CASE logic,
-- and it would probably perform better (one table scan vs. two). I'm
-- leaving it this way for demonstration, and to keep the overall query
-- a bit simpler.
left outer join (select
inv
,round(sum(bd1.bal), 2) amount
from detail
where code_type = 'AB'
or code_type = 'CD'
group by inv) bd1
on bd1.inv = bi.inv -- ADDED in second edit
left outer join (select
inv -- RENAMED in second edit
,round(sum(bd2.bal), 2) amount
from detail
where code_type <> 'AB'
and code_type <> 'CD'
group by inv) bd2 -- RENAMED in second edit
on bd2.invoive = bi.inv -- ADDED in second edit
道德:CASE
语句可以是SQL开发人员最好的朋友。
答案 1 :(得分:1)
第一个查询可以这样写:
UPDATE "detail"
SET bal =
CASE
WHEN code_type = 'NO'
THEN 0
ELSE
CASE
WHEN code_type IN ('AB',
'CD',
'EF')THEN 1
ELSE -1
END
END * (units * amount)
WHERE code_type IN ('AB','CD','EF','GH','IK','KL','NO');
拥有code_type索引会快速过滤掉您需要更新的符合条件的行。根据表结构的其余部分,您的速度可能会有所不同,但我认为这将是最快的版本。因为这里唯一重要的是基于代码类型的0,1或-1,这是你检查的,然后乘以单位*金额。
更新: 您的第二批更新也可以一批编写:
UPDATE b
SET payments = COALESCE(x.bal,0),
cost = COALESCE(y.bal,0),
balance = ROUND(charges + COALESCE(x.bal,0),2)
FROM bill b
LEFT OUTER JOIN
( SELECT ROUND(SUM(bd1.bal),2) AS bal,
inv
FROM "detail" bd1
WHERE bd1.code_type IN ('AB',
'CD')
GROUP BY bd1.inv
)
x
ON x.inv = b.inv
LEFT OUTER JOIN
( SELECT ROUND(SUM(bd2.bal),2) AS bal,
invoice
FROM "detail" bd2
WHERE bd2.code_type NOT IN ('AB',
'CD')
GROUP BY bd2.invoice
)
y
ON y.invoice = b.invoice
提高速度的提示:
答案 2 :(得分:0)
我认为前3个陈述你可以在单个陈述中这样做:
update detail set bal = (units * amount) where code_type in( 'AB','CD' )
您也可以为接下来的3个陈述做同样的事。
答案 3 :(得分:0)
目前,您正在为每个查询重新计算units * amount
和units * amount * -1
。计算units * amount
一次并结合前几个查询可以提高性能,但我不知道多少:
declare @total int
set @total = units * amount
update "detail" set bal = @total where code_type in ('AB', 'CD', 'EF');
update "detail" set bal = (@total * -1) where code_type in ('GH', 'IK','LM');
update "detail" set bal = 0 where code_type = 'NO';