我有一个连接两个表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以更好的方式执行。 此外,表格的统计数据是最新的。
答案 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表的读取)