【发布时间】:2011-04-09 08:25:22
【问题描述】:
我有一个包含数百万 IP 范围记录(分别为 start_num 和 end_num)的表,我需要通过单个 IP 地址对其进行查询,以便返回与该点重叠的所有范围。查询本质上是:
SELECT start_num
, end_num
, other_data_col
FROM ip_ranges
WHERE :query_ip BETWEEN start_num and end_num;
该表在 start_num 上有 8 个范围分区,并在 (start_num, end_num) 上有一个本地复合索引。称之为 UNQ_RANGE_IDX。已针对表和索引收集统计信息。
查询按预期对 UNQ_RANGE_IDX 索引进行索引范围扫描,并且在某些情况下执行得非常好。它表现良好的情况是接近 IP 地址空间的底部(即类似 4.4.10.20),而在高端时性能较差。 (即 200.2.2.2)我确信问题在于,在低端,优化器可以修剪包含适用范围的分区之上的所有分区,因为 start_num 上的范围分区提供了必要的信息修剪。在 IP 频谱的顶端进行查询时,它无法修剪较低的分区,因此会产生读取附加索引分区的 I/O。这可以在跟踪执行时通过 CR_BUFFER_GETS 的数量来验证。
实际上,满足查询的范围不会在任何分区中,而是在 query_ip 所在的分区或紧接其下方或上方的分区,因为范围大小不会大于 A 类和每个分区每个都涵盖许多 A 类。我可以通过在 where 子句中指定该信息让 Oracle 使用该信息,但有没有办法通过统计、直方图或自定义/域索引将此类信息传达给 Oracle?在搜索涵盖特定日期的日期范围时,似乎会有一种常见的解决方案/方法来解决此类问题。
我正在寻找使用 Oracle 及其功能来解决此问题的解决方案,但也欢迎其他解决方案类型。我已经想到了一些在 Oracle 范围之外可行的方法,但我希望有一种更好的索引、统计数据收集或分区方法来解决问题。
要求的信息:
CREATE TABLE IP_RANGES (
START_NUM NUMBER NOT NULL,
END_NUM NUMBER NOT NULL,
OTHER NUMBER NOT NULL,
CONSTRAINT START_LTE_END CHECK (START_NUM <= END_NUM)
)
PARTITION BY RANGE(START_NUM)
(
PARTITION part1 VALUES LESS THAN(1090519040) TABLESPACE USERS,
PARTITION part2 VALUES LESS THAN(1207959552) TABLESPACE USERS
....<snip>....
PARTITION part8 VALUES LESS THAN(MAXVALUE) TABLESPACE USERS
);
CREATE UNIQUE INDEX IP_RANGES_IDX ON IP_RANGES(START_NUM, END_NUM, OTHER) LOCAL NOLOGGING;
ALTER TABLE IP_RANGES ADD CONSTRAINT PK_IP_RANGE
PRIMARY KEY(START_NUM, END_NUM, OTHER) USING INDEX IP_RANGES_IDX;
为范围分区选择的截止值没有什么特别之处。它们只是 A 类地址,其中每个分区的范围数相当于大约 1M 条记录。
【问题讨论】:
-
start_num和end_num的数据类型是什么?
-
start_num 和 end_num 的类型为 NUMBER
-
表和每个分区有多少行?
-
可以分享一下分区脚本吗?我想看看范围和其他细节。另外为什么要本地分区索引?为什么不是全局分区索引?
-
表中的行数略低于 8M,每个分区大约有 1M 行。
标签: sql database oracle database-design