【问题标题】:Index on partitioned table not used未使用分区表上的索引
【发布时间】:2011-06-07 18:22:43
【问题描述】:

我必须查询一个相当大的表(450M 行),该表是分区和索引的。

假设这个结构:

  • load_num(int)
  • cust_id(int)
  • ...更多列...

该表在 load_num 上进行了分区,大约 3 个负载进入一个分区。 (所以 load_num 在分区内不是唯一的)

共有三个索引,其中两个以load_num,cust_id为前两列(int that order)

当我发出这个查询时:

select *
from   fact
where  load_num = 100
       and cust_id = 12345

返回需要很长时间,所以我点击了解释计划,它得到了正确的分区,然后对其进行了全表扫描。

为什么 oracle 不使用两个索引之一对分区进行 ROWID 扫描以获取行?

cust_id 应该是唯一的,并且表上的统计信息是最新的。我们正在使用 10g 企业版。

来自 MS SQL,所以我还没有跟上 Oracle 的步伐。

提前致谢,

格特-简

** 编辑:一些匿名的 DDL:

CREATE TABLE FACT
(
  LOAD_NUM NUMBER 
... columns ..
, CUSTOMER_ID VARCHAR2(20 BYTE) 
.. columns 
) 
TABLESPACE "TS_A" 
PCTFREE 0 
INITRANS 1 
STORAGE 
( 
  BUFFER_POOL DEFAULT 
) 
PARALLEL 12 
PARTITION BY LIST (LOAD_NUM) 
(
  PARTITION FACT_46 VALUES (46) TABLESPACE FACT_PART_DATA_46 
    COMPRESS  
, PARTITION FACT_52 VALUES (52) TABLESPACE FACT_PART_DATA_52 
    COMPRESS  
, PARTITION FACT_56 VALUES (56) TABLESPACE FACT_PART_DATA_56 
    COMPRESS  
  ... more partitions ...
)CREATE INDEX SOMESCHEMA.FACT_IDX2 ON SOMESCHEMA.FACT (LOAD_NUM ASC, CUSTOMER_ID ASC, OUTSTANDING_ID ASC) 
LOCAL 
(
  PARTITION FACT_DATA_46 
  LOGGING 
  TABLESPACE "FACT_DATA_46" 
  PCTFREE 10 
  INITRANS 2 
  STORAGE 
  ( 
    INITIAL 65536 
    MINEXTENTS 1 
    MAXEXTENTS 2147483645 
    BUFFER_POOL DEFAULT 
  ) 
  NOCOMPRESS 
, PARTITION FACT_DATA_52
  LOGGING 
  TABLESPACE "FACT_DATA_52" 
  PCTFREE 10 
  INITRANS 2 
  STORAGE 
  ( 
    INITIAL 65536 
    MINEXTENTS 1 
    MAXEXTENTS 2147483645 
    BUFFER_POOL DEFAULT 
  ) 
  NOCOMPRESS 
, 
... etc etc ..
)

【问题讨论】:

  • 索引是LOCAL 还是GLOBAL?您能否发布准确的表和索引定义(带有分区子句)?
  • 嗨,Quassnoi,我在那里编辑了一些 DDL。太好了!

标签: oracle optimization indexing partitioning


【解决方案1】:

为什么 oracle 不使用两个索引之一对分区进行 ROWID 扫描以获取行?

很难确切说明为什么Oracle 不使用索引,因为您的设置中没有任何东西可以阻止它这样做。

很可能,cust_id 分布存在偏差,因此 Oracle 认为 PARTITION SCAN 更有效。

您能否尝试明确添加提示:

SELECT  /*+ INDEX (f FACT_IDX2) */
        *
FROM    fact f
WHERE   load_num = 100
        AND cust_id = 12345

确保它在计划中使用并检查此方法是否真的更快。

另外,请发布此查询返回的内容:

SELECT  COUNT(*), COUNT(DECODE(cust_id, 12345, 1))
FROM    fact f
WHERE   load_num = 100

【讨论】:

  • 通常,如果您必须为索引提供提示,则意味着数据非常偏斜或统计信息不正确。看起来您已经涵盖了第一个案例,但它检查统计数据也会很有用。
  • @Adam:@op 声称统计数据是最新的。
  • 要确保:当我转到 SqlDev 中的 datails 选项卡时,它显示 LAST_ANALYZED: 03-DEC-10。从那以后就没有负载了,所以我认为统计数据是最新的。 (无论哪种方式,cust_id 的分布都不应该改变)。现在检查查询提示。
  • 开玩笑!很抱歉浪费了您的时间,原因如下:customer_id 是 VARCHAR2(20 BYTE)。我看到预测是 to_number(cust_id)= 12345。当我将查询更改为 cust_id = '12345' 时,它会更改为范围扫描,并且返回速度非常快。没想到这个大表上的 cust_id 是 varchar。真的很抱歉,感谢您的帮助!
猜你喜欢
  • 2014-11-24
  • 1970-01-01
  • 2018-12-23
  • 2017-05-29
  • 2017-02-21
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多