Oracle执行全表扫描

时间:2015-09-26 13:04:25

标签: oracle performance

我有一个连接两个表ISITEMFULL和Transaction的查询(它实际上搜索ISITEMFULL表中invoice_date不为null的所有事务,而invoice_date仅在事务表中定义。

SELECT MIN(T.TRANSACTION) TRANSACTION ,
ISIL.ITEMID ITEM_NUMBER,
ISIL.ITEMCOVER POLICY_NUMBER 
FROM TRANSACTION T,ISITEMFULL ISIL 
WHERE ISIL.SENT_FLG='T' 
AND T.TRANSACTION=ISIL.TRANSACTION
AND T.INVOICE_DAT IS NOT NULL 
GROUP BY ISIL.ITEMID,ISIL.ITEMCOVER;

现在,ISITEMFULL的大小相对较小(300万条记录),而TRANSACTION表有数十亿条记录。但如果我寻找计划,它会执行TRANSACTION表的完整扫描。因此,查询花费了大量时间。该计划如下:

 SELECT STATEMENT, GOAL = CHOOSE            Cost=2653711    Cardinality=1293564 Bytes=47861868
   HASH GROUP BY            Cost=2653711    Cardinality=1293564 Bytes=47861868
     HASH JOIN          Cost=2632362    Cardinality=1293564 Bytes=47861868
       TABLE ACCESS FULL    Object owner=PIE    Object name=ISITEMFULL  Cost=26845 Cardinality=1293564  Bytes=28458408
       TABLE ACCESS FULL    Object owner=PIE    Object name=TRANSACTION Cost=2312319 Cardinality=201443101  Bytes=3021646515

即使所有列都有相应的索引,但使用了这些索引,而是以完整模式扫描事务表。 各栏目定义的索引如下:

    --ISILMFULFILI4 - Transaction (in ISITEMFULL table)
    --ISILMFULFILI7 - ITEMID (in ISITEMFULL table)
    --ISILMFULFILI2 - ITEMCOVER (in ISITEMFULL table)
    --TRANSACTIONP1-    TRANSACTION (in TRANSACTION table)
    --TRANSACTIONI10 - INVOICE_DAT (in TRANSACTION table).

我曾尝试使用这些索引的提示,但它几乎没有帮助。有没有其他方法可以在事务表上停止全面扫描。甚至是查询

    Select  transaction from transaction TR where transaction in
    (
    Select  transaction from isclmfulfil IC WHERE sent_FLG='T') and invoice_dat is not null;

花了很多时间。

有没有办法可以告诉Oracle以更好的方式执行。 此外,表格的统计数据是最新的。

1 个答案:

答案 0 :(得分:1)

您是否尝试过这样的变体:

SELECT MIN(ISIL.TRANSACTION),
       ISIL.ITEMID ITEM_NUMBER,
       ISIL.ITEMCOVER POLICY_NUMBER 
  FROM ISITEMFULL ISIL 
 WHERE ISIL.SENT_FLG='T' 
   AND EXISTS(SELECT /*+ index(t TRANSACTIONP1) */ * 
                FROM TRANSACTION T 
               WHERE T.TRANSACTION=ISIL.TRANSACTION
                 AND T.INVOICE_DAT IS NOT NULL)
 GROUP BY ISIL.ITEMID,ISIL.ITEMCOVER;


但无论如何,事务表中的1.29M索引探测需要一些时间 (所以Optimizer选择全扫描可能是正确的。)

您也可以尝试并行执行:

SELECT /*+ parallel(T, 4) */ 
MIN(T.TRANSACTION) TRANSACTION ,
ISIL.ITEMID ITEM_NUMBER,
ISIL.ITEMCOVER POLICY_NUMBER 
FROM TRANSACTION T,ISITEMFULL ISIL 
WHERE ISIL.SENT_FLG='T' 
AND T.TRANSACTION=ISIL.TRANSACTION
AND T.INVOICE_DAT IS NOT NULL 
GROUP BY ISIL.ITEMID,ISIL.ITEMCOVER;

您可以尝试不同程度的并列性来检查哪种表现更快
您可以尝试使用此类提示在散列连接之前扫描TRANSACTIONI10

SELECT /*+ first_rows ordered use_hash(ISIL T) index(T TRANSACTIONI10) */
MIN(T.TRANSACTION) TRANSACTION ,
ISIL.ITEMID ITEM_NUMBER,
ISIL.ITEMCOVER POLICY_NUMBER 
FROM ISITEMFULL ISIL, TRANSACTION T
WHERE ISIL.SENT_FLG='T' 
AND T.TRANSACTION=ISIL.TRANSACTION
AND T.INVOICE_DAT IS NOT NULL 
GROUP BY ISIL.ITEMID,ISIL.ITEMCOVER;

但是,对20100次TRANSACTION表进行探测也需要相当长的时间
如果您对这些查询进行SQL *跟踪,您将获得有关每一步执行时间的更多信息 例如,您的SQL可能需要花费大量时间,不仅因为完全扫描,还因为缺少哈希工作区的内存(在这种情况下,Oracle会将数据写入临时表空间,这会显着降低执行速度)。这也可以在V $ SQL_WORKAREA_ACTIVE视图中检查(如果NUMBER_PASSES = 0那么一切OK,1 - 慢但是或多或少可接受,如果多于1,构建哈希表可能需要花费太多时间)
(以防万一,如果您使用Exadata,由于卸载和存储索引,全扫描将比大索引范围扫描更有效)


我还建议在TRANSACTION(nvl2(INVOICE_DAT,TRANSACTION, NULL))上创建函数索引,它比组合索引更紧凑,因为它只存储TRANSACTION列,而且只存储非空INVOICE_DAT的行,所以它将是扫描得更快 您需要修改查询才能使用它:

SELECT MIN(ISIL.TRANSACTION) TRANSACTION ,
ISIL.ITEMID ITEM_NUMBER,
ISIL.ITEMCOVER POLICY_NUMBER 
FROM TRANSACTION T,ISITEMFULL ISIL 
WHERE ISIL.SENT_FLG='T' 
AND ISIL.TRANSACTION = nvl2(INVOICE_DAT,TRANSACTION, NULL)
GROUP BY ISIL.ITEMID,ISIL.ITEMCOVER;

(在这种情况下应省略TRANSACTION表的读取)