【问题标题】:Index is not being used on a partitioned table分区表上没有使用索引
【发布时间】:2018-12-23 08:25:08
【问题描述】:

我有tableA,它(列表)几乎均匀地划分为 5 个值。 tableA 包含 1 亿行,并且在 customFunc(x) 上有一个本地(分区)索引。以下查询使用提到的索引执行RANGE SCAN,执行大约需要 5-10 秒并返回 500 万。

select count(*) from tableA where customFunc(x)='abc';

不幸的是,当我尝试在特定分区上执行相同的查询时,它会进行全表扫描并且需要很长时间。..

select count(*) from tableA where customFunc(x)='abc' and partitioning_key='DT';

我完全不明白为什么它会这样工作。它不应该在第二种情况下利用分区修剪吗?

编辑:添加提示/*+ index(tableA mentionedIndex) */ 解决了问题,但我还是不明白为什么默认不使用它

编辑:XPLAN 1

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(带分区键)

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')

【问题讨论】:

  • 谢谢斯图尔特。优化器的决策涉及多个因素,包括统计信息、可用资源、索引等。查看这两个查询的优化器计划将很有用。您能否将 xplans 添加到问题中?
  • 10053 trace是你的朋友是这样的情况...
  • @alexgibbs 请看上面的计划,谢谢!
  • 谢谢斯图尔特,这有帮助。看起来它正在使用分区,而不是使用索引 - 我还没有足够的信心来回答并且会对此进行一些实验,但是从这些计划中的基数来看,我想知道优化器是否看到索引因为在该分区中没有足够的选择性,而是选择了完整的。看看不同谓词的行为是否相同——customFunc(x)='VOLTRON' 或其他什么而不是'abc',以及直方图是什么样的,将会很有趣。
  • Stuart 只是一个后续。我想知道您是否可以检查目标分区中“abc”谓词的相对基数。此查询是否获取大量目标分区?假设是最新的统计数据、历史数据等(没有什么是陈旧的?),看看这里是否可能涉及数据倾斜会很好。 customFunc(x) 上的零匹配谓词是否也进行全扫描?谢谢

标签: database oracle performance indexing partitioning


【解决方案1】:

不应该在第二种情况下利用分区修剪吗?

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

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

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

现在你感到困惑是对的。将分区键作为谓词,优化器应该对指定的分区执行INDEX RANGE SCAN。要弄清楚为什么它不这样做需要您付出更多的努力。可能是您的统计数据过时,或者您需要收集直方图。也许它是基于函数的索引这一事实使优化器感到困惑。如果您有访问权限或合作的 DBA,则可以使用 10053 事件来查看幕后情况。 Find out more.

【讨论】:

  • 索引是使用“create index indexname on tableA (customFunc(x)) local”构建的,为什么当我搜索每个分区而不是搜索特定分区时,oracle 使用此索引?使用分区键创建本地索引有什么意义?
  • 顺便说一句:当我强制 cob 使用索引时,它就像一个魅力
  • 该函数是否对分区键做任何明确的事情?我猜不是。
  • @Stuart 感谢 APC。我印象深刻,相信我已经观察到,使用本地非前缀索引,分区键上的单独谓词可以独立使用,也可以与其他列上的本地索引结合使用。虽然在没有给出分区键的情况下可以探测所有分区,但我相信优化器可以选择同时使用分区修剪和索引访问,当两个谓词都存在时。谢谢docs.oracle.com/database/121/VLDBG/…
  • @alexgibbs - 相关的一点是“优化器有选项”。有时,当给定选项时,优化器会做出错误的选择。这似乎就是这里发生的事情。通常我们会期望优化器选择分区消除和索引范围扫描。所以在这种情况下没有明显的原因。
猜你喜欢
  • 2011-06-07
  • 2017-05-29
  • 1970-01-01
  • 2014-11-24
  • 2017-02-21
  • 2023-03-10
  • 2010-09-20
  • 2015-03-09
  • 1970-01-01
相关资源
最近更新 更多