【发布时间】:2020-06-22 13:12:59
【问题描述】:
所以我已经超过 5 年没有使用 Oracle 并且我已经没有实践了。我一直在使用 SQL Server。
我正在查看一些现有的查询并尝试改进它们,但它们的反应非常奇怪。根据解释计划,他们并没有加快速度,而是进行全表扫描而不使用索引。
在原始查询中,在 where 语句中完成了两个表之间的等值连接。我们将它们称为表 A 和 B。我使用了一个解释计划,然后是 SELECT * FROM table(DBMS_XPLAN.DISPLAY (FORMAT=>'ALL +OUTLINE'));它告诉我表 A 是由本地索引查询的。
按本地索引 ROWID 访问表
SELECT A.*
FROM TableA A, TableB B
WHERE A.SecondaryID = B.ID;
我尝试更改查询并将 TableA 与新表(表 C)连接起来。表 C 是表 B 的子集,有 700 条记录,而不是 100K。然而,解释计划告诉我,现在通过完整查找查询表 A。
CREATE TableC
AS<br>
SELECT * FROM TableB WHERE Active='Y';
SELECT A.*
FROM TableA A, TableC C
WHERE A.SecondaryID = C.ID;
下一步,我保留了表 A 和 C 之间的连接,但使用了一个提示来告诉它使用表 A 上的索引。但是它仍然会进行完整的查找。
SELECT /*+ INDEX (A_NDX01) */ A.*
FROM TableA A, TableC C
WHERE A.SecondaryID = C.ID;
所以我尝试将连接更改为表 A 的简单选择,并使用 IN 语句与表 C 进行比较。仍然是全表扫描。
SELECT A.*
FROM TableA A
WHERE A.SecondaryID in (SELECT ID FROM TableC);
最后,我把前面的语句改成 subselect 来拉取前 1000 条记录,它使用了索引。奇怪的是,表 C 中只有 700 条记录。
SELECT A.*
FROM TableA A
WHERE A.SecondaryID in (SELECT ID FROM TableC WHERE rownum <1000
)
我想知道是否有人可以帮我弄清楚发生了什么?
我最好的猜测是,由于 TableC 是一个新表,也许优化器不知道其中有多少条记录,这就是为什么它只在知道少于 1000 条记录时才使用索引的原因?
我尝试在我的模式上运行 dbms_stats.gather_schema_stats 但它没有帮助。
感谢您的帮助。
【问题讨论】:
-
确保所有相关表的统计信息都是最新的 (
SELECT TABLE_NAME, LAST_ANALYZED FROM DBA_TABLES WHERE TABLE_NAME IN ('TABLE1', 'TABLE2', 'TABLE3')),如果需要,请使用DBMS_STATS.GATHER_TABLE STATS收集统计信息。然后再次检查您的查询计划。 -
所以 last_analyzed 已经很老了。但是 DBA_TAB_STATS_HISTORY 中每个分区的统计信息是最近的。我不确定为什么会有差异。