我有奇怪的oracle优化器行为:
SELECT a.id,
a.date_insert,
a.message#cnt
FROM T_MESSAGE_TRANSMIT A,
T_LIST l
WHERE a.priority_id = 0
AND a.status = 'Q'
and l.id = a.list_id
此查询会生成超过T_MESSAGE_TRANSMIT
的完整扫描,无论它是涵盖priority_id
和status
字段的索引:
CREATE BITMAP INDEX INFORMER.IX$MESSAGE_TRANSMIT$6 ON INFORMER.T_MESSAGE_TRANSMIT (STATUS, PRIORITY_ID)
表格大小约为28M行,并且已在7天前进行过分析(从那天起仅添加了数千行)。
如果我使用提示/*+index(a IX$MESSAGE_TRANSMIT$6) */
,那么一切都会变好,如果我删除了连接,并将查询重写为:
SELECT a.id,
a.date_insert,
a.message#cnt
FROM T_MESSAGE_TRANSMIT A,
WHERE a.priority_id = 0
AND a.status = 'Q'
我哪里可以搞错?
UPD :
问题出在此优化程序设置中:
optimizer_mode first_rows_10
答案 0 :(得分:3)
哪些行符合优先级ID /状态标准?
例如,如果20%的行匹配,则必须在20%的情况下访问该行以获取额外的详细信息。如果它访问20%的行,它可能会访问80-90%的块。在这种情况下,忽略索引是正确的。
但是,如果它在没有连接的情况下使用查询的索引,则更可能是由于a.list_id值。如果它使用BITMAP索引,则对于它在那里找到的每一行,它必须通过id访问T_LIST表。如果T_LIST很大并且id没有编入索引,那么这可能意味着重复完全扫描T_LIST是一个坏主意。
在这种情况下,它可能从T_MESSAGE_TRANSMIT获取所有匹配的行,按ID对它们进行排序,然后从T_LIST获取匹配的行。对T_LIST的散列连接也可能是合适的。
另外,你确定你不想做一个简单的
SELECT a.id,
a.date_insert,
a.message#cnt
FROM T_MESSAGE_TRANSMIT A
WHERE a.priority_id = 0
AND a.status = 'Q'
AND a.list_id in (select l.id from T_LIST l)
如果ID在T_LIST上不唯一,则原始SQL将生成重复项。