I have a table with millions of IP range entries (start_num, end_num respectively) that I need to query through a single IP address to return all ranges that overlap this point. Substantive request:
SELECT start_num
, end_num
, other_data_col
FROM ip_ranges
WHERE :query_ip BETWEEN start_num and end_num;
The table has 8 range sections on start_num and has a local composite index (start_num, end_num). Name it UNQ_RANGE_IDX. Statistics are collected on the table and index.
The query checks the range of indices on the UNQ_RANGE_IDX index as expected, and in some cases works very well. The cases in which it works well are at the bottom of the IP address space (for example, something like 4.4.10.20), and the performance is poor when at the top end. (i.e. 200.2.2.2). I am sure that the problem is that at the lower end, the optimizer can crop all sections above those that contain the corresponding ranges, due to the separation of the ranges by start_num, providing the information needed for prunes. When querying at the upper end of the IP spectrum, it cannot trim the lower sections and, therefore, it takes the input / output of reading additional sections of the index. This can be verified with CR_BUFFER_GETS when tracking execution.
, , , , query_ip, , , , A . Oracle , where, 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 .