Oracle正在执行完全表扫描

Oracle正在执行完全表扫描,oracle,performance,Oracle,Performance,我有一个连接两个表ISITEMFULL和Transaction的查询(它实际上搜索ISITEMFULL表中发票日期不为空的所有交易,而发票日期仅在事务表中定义) 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.TRANSAC

我有一个连接两个表ISITEMFULL和Transaction的查询(它实际上搜索ISITEMFULL表中发票日期不为空的所有交易,而发票日期仅在事务表中定义)

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万条记录),事务表有数十亿条记录。但是如果我查找plan,它会对事务表进行完全扫描。因此,查询需要花费大量时间。该计划如下所示:

 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 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以更好的方式执行。
此外,表格上的统计数据是最新的。

您是否尝试过这种变体:

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;

但无论如何,事务表中的129万个索引探测将需要一段时间。
(因此优化器选择完全扫描可能是正确的)。

您也可以尝试并行执行:

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;
但探测事务表2.01亿次也需要大量时间。

如果对这些查询进行SQL*跟踪,您将获得关于每个步骤执行时间的更多信息。
例如,您的SQL可能会花费大量时间,这不仅是因为完全扫描,还因为哈希工作区内存不足(在这种情况下,Oracle会将数据写入临时表空间,从而显著降低执行速度)。这也可以在V$SQL\u workarea\u ACTIVE view中进行检查(如果NUMBER_PASSES=0,则一切正常,1-缓慢,但或多或少可以接受,如果超过1,则构建哈希表可能需要太多时间)
(以防万一,如果您使用Exadata,由于卸载和存储索引,完全扫描将比大索引范围扫描更有效)


我还建议在
事务上创建函数索引(nvl2(发票数据,事务,空))
它将比组合索引更紧凑,因为它只存储
事务
列,只存储不为空的
发票数据
行,所以扫描速度更快。
您需要修改查询以使用它:

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;

(在这种情况下,应省略对事务表的读取)

创建多列索引:
在事务上创建索引somename(发票数据,事务)
Hi,谢谢你的评论。但是我不能创建索引,因为这是一个遗留的生产数据库,我只能使用可用的索引。有没有什么方法可以在使用索引后对两个表进行哈希连接(据我所知,索引是由嵌套循环使用的,而不是哈希)