我有奇怪的 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
最佳答案
符合优先级 ID/状态标准的行比例是多少?
例如,如果 20% 的行匹配,则必须在 20% 的情况下访问该行才能获取额外的详细信息。如果它访问 20% 的行,那么它可能会访问 80-90% 的 block 。在这种情况下,忽略索引是正确的。
但是,如果它在没有连接的情况下使用索引进行查询,则更有可能是由于 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)
如果 T_LIST 上的 ID 不唯一,您的原始 SQL 将生成重复项。
关于Oracle:使用全扫描而不是复合索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4778546/