我正在研究Oracle查询,我非常需要让它更快。我非常感谢任何建议。
我有两张桌子。
1)交易:在商店购买 - TransactionID
2)TransactionItems:每次购买都有1..many项目 - TransactionID,ItemID
在每个表中,有两个标志:
查询需要:
我将查询分为4个步骤。
查询运行顺利。然而,这是一个问题。有数十亿的交易记录,每个交易有大约7个交易项目。
现在速度有多快:
我跟踪了每个步骤的处理时间:
为TransactionItem设置标志A的值
为TransactionItem设置标志B的值
设置交易的标志A的值
设置交易的标志B的值
以下是我的完整查询。以下是使用的其他表格
产品
FlagAproductCodes
FlagBproductCodes
TransactionPayment
Payment_Dim
我有这些索引:
交易 1. TransactionID
TransactionItems 1. TransactionID 2. ProductID
产品 1.产品ID 2. ProductCode
FlagAproductCodes 1. ProductCode
FlagBproductCodes 1. ProductCode
付款 1. PaymentID 2. PaymentCode 3. Payment_Name
我真的很感谢帮助,谢谢
-- 1. Set value of FlagA for TransactionItem
Update
TransactionItems Item
Set FlagA =
(
Select
Case
When
Item.FlagA_Qty = 0 Then 'N' -- this is the quantity of items purchased that fall into the FlagA category
When
FlagA.ProductCode Is Null Then 'N'
Else
'Y'
End
From
Product Prod
Left Join
FlagAproductCodes FlagA
On Product.ProductCode = FlagA.ProductCode
Where
Product.Prod_Id = Item.Prod_Id
)
;
-- 2. Set value of FlagB for TransactionItem
Update TransactionItems
Set FlagB = 'Y'
Where ItemID In
(
Select
Trans_Items.ItemID
From
TransactionItems Trans_Items
Inner Join Product Prod
On Trans_Items.Prod_Id = Product.Prod_Id
Inner Join FlagBproductCodes FlagB
On Product.ProductCode = FlagB.ProductCode
Where
(
Trans_Items.Gov_FlagA_Qty < Trans_Items.Item_Qty
)
AND
(
Exists
(Select Transaction_Payment_Fid
From TransactionPayment Trans_Pay
Inner Join Warehouse.Payment_Dim Pay_Dim
On Trans_Pay.Payment_Id = Pay_Dim.Payment_Id
Where
Transaction_Fid = Trans_Items.Transaction_Fid
And Upper(Pay_Dim.Payment_Name) Like '%ABC%'
)
)
)
;
Update TransactionItems
Set FlagB = 'N'
Where FlagB Is Null;
-- 3: Set FlagA for Transactions
Update
Transactions
Set
Gov_FlagA_Flag =
Case When Exists
(Select ItemID
From TransactionItems Item
Where Item.Transaction_Fid = Transactions.Transaction_Fid
and gov_FlagA_flag = 'Y')
Then 'Y'
Else 'N'
End
;
-- 4: Set FlagB for Transactions
Update
Transactions
Set
FlagB =
Case When Exists
(Select ItemID
From TransactionItems Item
Where Item.Transaction_Fid = Transactions.Transaction_Fid
And FlagB = 'Y')
Then 'Y'
Else 'N'
End
;
答案 0 :(得分:0)
你需要研究并行执行,这可能是一个太广泛的主题,无法在这里充分探讨。 (而且我没有资格对此说多少)。
与此同时,您可以通过仅更新每个表一次,并减少偶然查找的数量来获得一些好处。这是未经测试的,但我认为与您对TransactionItems的三次更新具有相同的逻辑,例如:
merge into TransactionItems TI
using (
select P.Prod_ID,
case when FAPC.ProductCode is null then 'N' else 'Y' end as FlagA,
case when FBPC.ProductCode is null then 'N' else 'Y' end as FlagB
from Product P
left join FlagAproductCodes FAPC on FAPC.ProductCode = P.ProductCode
left join FlagAproductCodes FBPC on FBPC.ProductCode = P.ProductCode
) temp
on (temp.Prod_id = TI.Prod_ID)
when matched then
update set TI.FlagA = case when temp.FlagA = 'Y' and TI.FlagA_Qty != 0
then 'Y' else 'N' end,
TI.FlagB = case when TI.FlagA_Qty < TI.Item_Qty
and exists (
select Transaction_Payment_Fid
from TransactionPayment TP
join Payment_Dim PD on TP.Payment_Id = PD.Payment_Id
where TP.Transaction_Fid = TI.Transaction_Fid
and upper(PD.Payment_Name) Like '%ABC%'
) then 'Y' else 'N' end
/
您可能更喜欢创建可更新视图。但是在这个数据量上,它仍然需要很长时间。
答案 1 :(得分:0)
有趣的挑战。我的直接反应是分裂&amp;征服 - 编写PLSQL以对扇区/ id范围进行操作,并经常提交。然后触发并行作业以在不同范围上操作,然后调谐以找到最佳设置。如果幸运的话,表格被分区,那就更好了。
此外,虽然我来自一个基于集合的一切时代,在PLSQL甚至梦想成熟之前,你可能想考虑在事务基础上重新设计它,而不是你当前的基于集合的方法,从而获取更新主行作为批量收集,然后使用批量收集来驱动详细信息表更新。我发现这可以更快,它肯定会让你在批量操作时有更多的控制权。如果失败,这也可以让你重新启动,例如快照太旧,存档日志已填满等等。如果爆炸,你不会想重新开始。
答案 2 :(得分:0)
我非常感谢指导 - 真的很有帮助!
启用并行产生了巨大的差异!
ALTER SESSION ENABLE PARALLEL DML;
再次感谢所有帮助