为什么强制全表扫描后查询运行速度更快?

Pie*_*erk 3 performance oracle-11g-r2 query-performance

我有一个MERGE语句需要永远执行选择,因为它从 ( SUB_DATA)运行的表相当大(读取 1.4 Tb,7 亿行)。我的SELECT看起来像这样。

SELECT MIN(TRUNC(DATETIME,'DD'))    AS FIRST_ACTIVITY,
       MAX(TRUNC(DATETIME,'DD'))    AS LAST_ACTIVITY,
       NVL(PHONE_NUMBER, '-1')      AS PHONE_NUMBER,
       MAX(NVL(PHONE_ID, '-1')) KEEP (DENSE_RANK LAST ORDER BY DATETIME) AS LAST_PHONE_ID,
       MAX(TYPE_ID) KEEP (DENSE_RANK LAST ORDER BY DATETIME)             AS TYPE_ID
FROM SUB_DATA   AD,
     SUB_PROF   ICP
WHERE DATETIME BETWEEN minDate AND maxDate
AND   PROFILE_ID = ICP.ICP_SEQID
AND   REF_RT_ID in (13, 63) 
AND   DURATION > 3 
AND   PHONE_NUMBER like '123%' 
GROUP BY NVL(PHONE_NUMBER, '-1')
Run Code Online (Sandbox Code Playgroud)

INDEXES桌子上有两个PHONE_NUMBER,一个在另一列上,一个在此处未使用的列上。

我努力让查询运行得更快,工作中的一位资深人士建议我强制使用FULL TABLE SCAN. 我这样做了,它产生了奇迹。

即使它有效,它也违背了全表扫描不好的一般概念。

有人可以解释为什么会这样吗?

Mat*_*Mat 5

[...] 它违背了全表扫描不好的一般概念。

这有例外,就像所有一般概念一样。全表扫描可能比索引扫描然后按 rowid 访问表便宜 - 有时便宜得多。

请记住:

  • 除了表的块之外,还需要读取索引块。如果索引很大(占表大小的相当大的百分比),则 SGA(和关联锁存器)上的压力可能会很明显
  • 如果索引的排序顺序与数据在实际表中的存储方式不匹配,则完成查询所需的逻辑 I/O 数量可能(可能很多)多于完成完整查询所需的 LIO 数量表扫描。(索引的聚集因子是您可以用来估计这一点的指标之一。)

我发现这篇文章中的数字Oracle clustering_factor 提示很好地解释了这个问题。

从本质上讲,如果通过索引扫描使数据块 I/O 请求跳过整个表,则总体成本将高于执行大型顺序读取的成本。FTS 更有可能使用多块直接路径读取,完全绕过 SGA,这也有潜在的好处——没有“缓存颠簸”,锁存更少。

如果你有一个覆盖索引,很有可能它会一直击败全表扫描。如果不是,它将取决于需要处理的实际块(数据 + 索引)的百分比(该查询的索引选择性),以及它们相对于彼此的“物理排序”程度。

至于为什么优化器在这里为您选择了“错误”的路径:很难说。索引或表上的陈旧统计数据可能是一个问题,根据LIKE某些模式计算的估计值可能会关闭,实例参数可能有点偏爱索引,......如果这是唯一一个行为不端的查询,并且您的统计数据是最新的,使用/*+ full */提示听起来还不错。