未使用范围间隔分区 table 中的本地索引
Local index in Range interval partitioned table is not being used
我有一个分区的范围区间 table。它有 6 万亿数据 1 年。
CREATE TABLE eip.Meter_Read_Alert_test
(
Mfg_serial_num VARCHAR2(50 BYTE) ,
Channel_id NUMBER NOT NULL,
Read_time TIMESTAMP(0),
CONSTRAINT pk_Alert_test PRIMARY KEY (ID,channel_id,Read_time)
)
PARTITION BY RANGE (Read_time) INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION p1 VALUES less than('01-09-19 12:00:00.000000000 AM')
) ;
在以下列上创建本地索引:
CREATE INDEX mfg_SNo_test_idx on eip.Meter_Read_Alert_test ( Mfg_serial_num ) tablespace SPRING_METER_READ Local ;
CREATE INDEX channel_ID_test_idx on eip.Meter_Read_Alert_test (Channel_ID) tablespace SPRING_METER_READ Local ;
CREATE INDEX ReadTime_test_idx on eip.Meter_Read_Alert_test (Read_Time) tablespace SPRING_METER_READ Local ;
问题:
当我 运行 下面的查询时, ReadTime_test_idx 索引没有被使用。正在全面 table 扫描。
select * from meter_read_alert_test
where read_time between '19-11-2019 12:00:00 AM' and '19-11-2019 11:00:00 PM';
Plan hash value: 2722527583
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9090K| 728M| 411K (6)| 00:00:17 | | |
| 1 | PARTITION RANGE ITERATOR| | 9090K| 728M| 411K (6)| 00:00:17 | KEY | KEY |
|* 2 | TABLE ACCESS FULL | METER_READ_ALERT_TEST | 9090K| 728M| 411K (6)| 00:00:17 | KEY | KEY |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("READ_TIME">=TO_TIMESTAMP('19-11-2019 12:00:00 AM') AND
"READ_TIME"<=TO_TIMESTAMP('19-11-2019 11:00:00 PM'))
请指出这里出了什么问题以及如何解决。
Oracle 使用完整 table 扫描而不是索引范围扫描不一定会做错任何事情。全 table 扫描在读取大量数据时最好,因为全 table 扫描可以使用多块读取,而不必为每个值遍历树结构,并且如果索引数据是无序的,索引读取可能必须从 table 中检索所有块。
虽然您的查询只读取了全部数据的一小部分,但它从分区中读取了 "large" 百分比的数据。由于 table 是按月分区的,Oracle 正在使用分区修剪来立即消除大部分数据(您可以在 "Key" 启动和停止分区中看到这一点)。在该分区内,查询正在读取大约一天的数据量,这大约是分区中数据的 3%。没有代表 "large" 百分比的通用数字,但在许多情况下,3% 的完整 table 扫描比索引更好。
这里有可能是 Oracle 猜错了。您可能想尝试使用 select /*+ index(meter_read_alert_test) */ ...
等索引提示进行查询。如果这提高了性能,请首先尝试重新收集统计信息。您通常不需要使用索引提示。
我有一个分区的范围区间 table。它有 6 万亿数据 1 年。
CREATE TABLE eip.Meter_Read_Alert_test
(
Mfg_serial_num VARCHAR2(50 BYTE) ,
Channel_id NUMBER NOT NULL,
Read_time TIMESTAMP(0),
CONSTRAINT pk_Alert_test PRIMARY KEY (ID,channel_id,Read_time)
)
PARTITION BY RANGE (Read_time) INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION p1 VALUES less than('01-09-19 12:00:00.000000000 AM')
) ;
在以下列上创建本地索引:
CREATE INDEX mfg_SNo_test_idx on eip.Meter_Read_Alert_test ( Mfg_serial_num ) tablespace SPRING_METER_READ Local ;
CREATE INDEX channel_ID_test_idx on eip.Meter_Read_Alert_test (Channel_ID) tablespace SPRING_METER_READ Local ;
CREATE INDEX ReadTime_test_idx on eip.Meter_Read_Alert_test (Read_Time) tablespace SPRING_METER_READ Local ;
问题: 当我 运行 下面的查询时, ReadTime_test_idx 索引没有被使用。正在全面 table 扫描。
select * from meter_read_alert_test
where read_time between '19-11-2019 12:00:00 AM' and '19-11-2019 11:00:00 PM';
Plan hash value: 2722527583
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9090K| 728M| 411K (6)| 00:00:17 | | |
| 1 | PARTITION RANGE ITERATOR| | 9090K| 728M| 411K (6)| 00:00:17 | KEY | KEY |
|* 2 | TABLE ACCESS FULL | METER_READ_ALERT_TEST | 9090K| 728M| 411K (6)| 00:00:17 | KEY | KEY |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("READ_TIME">=TO_TIMESTAMP('19-11-2019 12:00:00 AM') AND
"READ_TIME"<=TO_TIMESTAMP('19-11-2019 11:00:00 PM'))
请指出这里出了什么问题以及如何解决。
Oracle 使用完整 table 扫描而不是索引范围扫描不一定会做错任何事情。全 table 扫描在读取大量数据时最好,因为全 table 扫描可以使用多块读取,而不必为每个值遍历树结构,并且如果索引数据是无序的,索引读取可能必须从 table 中检索所有块。
虽然您的查询只读取了全部数据的一小部分,但它从分区中读取了 "large" 百分比的数据。由于 table 是按月分区的,Oracle 正在使用分区修剪来立即消除大部分数据(您可以在 "Key" 启动和停止分区中看到这一点)。在该分区内,查询正在读取大约一天的数据量,这大约是分区中数据的 3%。没有代表 "large" 百分比的通用数字,但在许多情况下,3% 的完整 table 扫描比索引更好。
这里有可能是 Oracle 猜错了。您可能想尝试使用 select /*+ index(meter_read_alert_test) */ ...
等索引提示进行查询。如果这提高了性能,请首先尝试重新收集统计信息。您通常不需要使用索引提示。