提高在ExaData上运行的Oracle查询的速度

时间:2014-08-22 13:43:36

标签: sql database oracle bigdata exadata

我正在研究Oracle查询,我非常需要让它更快。我非常感谢任何建议。

  • 数据库是Oracle,在ExaData集群上运行。
  • Oracle版:Oracle Database 11g企业版11.2.0.3.0版 - 64位生产

我有两张桌子。

1)交易:在商店购买 - TransactionID

2)TransactionItems:每次购买都有1..many项目 - TransactionID,ItemID

在每个表中,有两个标志:

  • FlagA:Y / N
  • FlagB:是/否

查询需要:

  1. 为TransactionItem中的每条记录设置FlagA和FlagB的值。
  2. 根据TransactionItem中Flags的值设置Transaction中每行的FlagA和FlagB值
  3. 我将查询分为4个步骤。

    1. 为TransactionItem设置标志A的值
    2. 为TransactionItem设置标志B的值
    3. 设置交易的标志A的值
    4. 设置交易的标志B的值
    5. 查询运行顺利。然而,这是一个问题。有数十亿的交易记录,每个交易有大约7个交易项目。

      现在速度有多快:

      • 总时间:616秒/ 10.27分钟
      • 每秒处理1,218笔交易/每分钟73,000笔交易

      我跟踪了每个步骤的处理时间:

      1. 为TransactionItem设置标志A的值

        • 4分52秒
      2. 为TransactionItem设置标志B的值

        • 3分26秒
      3. 设置交易的标志A的值

        • 1分6秒
      4. 设置交易的标志B的值

        • 0分51秒
      5. 以下是我的完整查询。以下是使用的其他表格

        产品

        • 每个TransactionItem都有一个ProductId每个产品都有一个ProductCode。
        • 一个产品代码有很多产品

        FlagAproductCodes

        1. 包含归类为的ProductCodes列表的单个列 FLAGA
        2. FlagBproductCodes

          1. 包含归类为的ProductCodes列表的单个列 FLAGB
          2. TransactionPayment

            1. 这是一个包含每笔交易的付款明细的事实表
            2. Payment_Dim

              1. 在PaymentID上链接到TransactionPayment
              2. 这是必需的,因为FlagB是基于Payment_Dim.PaymentName
              3. 设置的

                我有这些索引:

                交易 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
                ;
                

3 个答案:

答案 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
/

您可能更喜欢创建可更新视图。但是在这个数据量上,它仍然需要很长时间。

This might also be useful

答案 1 :(得分:0)

有趣的挑战。我的直接反应是分裂&amp;征服 - 编写PLSQL以对扇区/ id范围进行操作,并经常提交。然后触发并行作业以在不同范围上操作,然后调谐以找到最佳设置。如果幸运的话,表格被分区,那就更好了。

此外,虽然我来自一个基于集合的一切时代,在PLSQL甚至梦想成熟之前,你可能想考虑在事务基础上重新设计它,而不是你当前的基于集合的方法,从而获取更新主行作为批量收集,然后使用批量收集来驱动详细信息表更新。我发现这可以更快,它肯定会让你在批量操作时有更多的控制权。如果失败,这也可以让你重新启动,例如快照太旧,存档日志已填满等等。如果爆炸,你不会想重新开始。

答案 2 :(得分:0)

我非常感谢指导 - 真的很有帮助!

启用并行产生了巨大的差异!

ALTER SESSION ENABLE PARALLEL DML;

再次感谢所有帮助