Database 未在分区表上使用索引

Database 未在分区表上使用索引,database,oracle,performance,indexing,partitioning,Database,Oracle,Performance,Indexing,Partitioning,我有表a,它(列表)几乎由5个值平均划分tableA包含1亿行,在customFunc(x)上有一个本地(分区)索引。下面的查询使用所提到的索引进行范围扫描,执行大约需要5-10秒,并返回500万 select count(*) from tableA where customFunc(x)='abc'; 不幸的是,当我试图在一个特定的分区上执行相同的查询时,它会进行完整的表扫描,而且会花费很长时间 select count(*) from tableA where customFunc(x)

我有
表a
,它(列表)几乎由5个值平均划分
tableA
包含1亿行,在
customFunc(x)
上有一个本地(分区)索引。下面的查询使用所提到的索引进行范围扫描,执行大约需要5-10秒,并返回500万

select count(*) from tableA where customFunc(x)='abc';
不幸的是,当我试图在一个特定的分区上执行相同的查询时,它会进行完整的表扫描,而且会花费很长时间

select count(*) from tableA where customFunc(x)='abc' and partitioning_key='DT';
我完全不明白为什么会这样。。在第二种情况下,它不应该利用分区修剪的优势吗

编辑:添加一个提示
/*+索引(tableA-ReferencedIndex)*/
解决了这个问题,但我仍然不明白为什么默认情况下不使用它

编辑:xplan1

Plan hash value: xxx

---------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name                          | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                               |     1 |    17 | 29335   (1)| 00:00:02 |       |       |
|   1 |  SORT AGGREGATE     |                               |     1 |    17 |            |          |       |       |
|   2 |   PARTITION LIST ALL|                               |  5227K|    84M| 29335   (1)| 00:00:02 |     1 |     5 |
|*  3 |    INDEX RANGE SCAN | CUSTOM_FUNC_INDEX             |  5227K|    84M| 29335   (1)| 00:00:02 |     1 |     5 |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access(customFunc(x)='abc')
XPLAN 2(带分区密钥)

在第二种情况下,它不应该利用分区修剪的优势吗

第二个查询确实应用了分区修剪:这就是这个步骤的意思:
partitionlist SINGLE
。问题是分区修剪意味着读取整个分区:在第二个计划中,步骤
TABLE ACCESS FULL
意味着读取分区中的所有行,而不使用索引。因此,第二个查询为分区中的每一行计算
customFunc(x)='abc'

使用分区键创建本地索引有什么意义

不同之处在于,以分区键为前缀的本地索引将始终使用分区修剪,而当本地索引没有分区键时,优化者可以选择是否应用分区修剪。但是如果您想运行不使用分区键的查询,那么显然您需要非前缀版本


现在你感到困惑是对的。给定分区键作为谓词,优化器应该对指定的分区执行
索引范围扫描。要想弄清楚为什么不这样做,你需要付出更多的努力。可能是您的统计数据过时了,或者您需要收集直方图。也许它是一个基于函数的索引这一事实让优化器感到困惑。如果您有访问权限或合作DBA,您可以使用10053事件查看引擎盖下

谢谢你,斯图尔特。优化器的决策涉及多个因素,包括统计数据、可用资源、索引等。查看这两个查询的优化器计划将非常有用。你能把XPlan添加到问题中吗?在这种情况下你的朋友是谁…@alexgibbs请看上面的计划,谢谢!谢谢斯图尔特,这很有帮助。看起来它正在使用分区,只是没有使用索引--我还没有足够的信心回答这个问题,并将对此进行一些试验,但从这些计划中的基数来看,我想知道优化器是否认为该分区中的索引没有足够的选择性,而选择完全索引。很有意思的是,看看不同谓词的行为是否相同--
customFunc(x)='VOLTRON'
或其他什么,而不是
'abc'
,以及直方图是什么样的。Stuart只是这里的后续内容。我想知道您是否可以检查目标分区中'abc'谓词的相对基数。这个查询获取了很多目标分区吗?假设是最新的统计数据、历史数据等(没有什么过时的吗?),最好看看这里是否涉及数据倾斜。customFunc(x)上的零匹配谓词是否也执行完全扫描?Thanksindex是使用“在tableA(customFunc(x))local上创建索引indexname”构建的。为什么oracle在搜索每个分区时使用此索引,而不是在搜索特定分区时使用此索引?用分区键创建本地索引有什么意义?顺便说一句:当我强制cob使用索引时,它就像一个字符一样工作。该函数是否对分区键执行任何显式操作?“我想不是。”斯图尔特谢谢APC。我的印象是,我相信我已经观察到,对于本地非前缀索引,分区键上的独立谓词可以单独使用,也可以与其他col上的本地索引结合使用。虽然在没有给出分区键的情况下可以探测所有分区,但我相信优化器可以选择在两个谓词都存在的情况下同时使用分区修剪和索引访问。谢谢@alexgibbs-相关的一点是“优化器有选择权”。有时,当给定选项时,优化器会做出错误的选择。这就是这里发生的事情。通常我们希望优化器选择分区消除和索引范围扫描。所以在这种情况下没有明显的原因。
Plan hash value: yyy

----------------------------------------------------------------------------------------------------
| Id  | Operation              | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |           |     1 |    30 |   679K  (2)| 00:00:27 |       |       |
|   1 |  SORT AGGREGATE        |           |     1 |    30 |            |          |       |       |
|   2 |   PARTITION LIST SINGLE|           |  4014K|   114M|   679K  (2)| 00:00:27 |   KEY |   KEY |
|*  3 |    TABLE ACCESS FULL   | tableA    |  4014K|   114M|   679K  (2)| 00:00:27 |     1 |     1 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter(customFunc(x)='abc')