For some reason queries on the high range of are extremely slow and queries on the low range are extremely fast.
My index is an adapted version of the answer in Optimizing queries on a range of timestamps (two columns):
CREATE INDEX idx_ip_range_inversed ON ip_range_domains(low, high);
but it only works for low ranges for some reason.
Table
CREATE TABLE IF NOT EXISTS ip_range_domains (
ip_range_domain_id BIGSERIAL PRIMARY KEY,
domain_id BIGINT REFERENCES domains NOT NULL,
source_type_id INTEGER REFERENCES source_types NOT NULL,
low INET NOT NULL,
high INET NOT NULL,
auto_high_conf BOOLEAN NOT NULL DEFAULT FALSE,
invalidation_reason_id INTEGER REFERENCES invalidation_reasons DEFAULT NULL,
invalidated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT current_timestamp
);
CREATE INDEX domain_id_btree ON ip_range_domains (domain_id);
CREATE INDEX idx_ip_range_inversed ON ip_range_domains(low, high);
This is fast:
=> EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM ip_range_domains WHERE '8.8.8.8'::INET BETWEEN low AND high;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on ip_range_domains (cost=25411.02..278369.96 rows=948529 width=55) (actual time=61.514..61.567 rows=55 loops=1)
Recheck Cond: (('8.8.8.8'::inet >= low) AND ('8.8.8.8'::inet <= high))
Heap Blocks: exact=23
Buffers: shared hit=3613
-> Bitmap Index Scan on idx_ip_range_inversed (cost=0.00..25173.89 rows=948529 width=0) (actual time=61.493..61.493 rows=55 loops=1)
Index Cond: (('8.8.8.8'::inet >= low) AND ('8.8.8.8'::inet <= high))
Buffers: shared hit=3590
Planning time: 0.537 ms
Execution time: 61.631 ms
This is slow:
=> EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM ip_range_domains WHERE '200.8.8.8'::INET BETWEEN low AND high;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Seq Scan on ip_range_domains (cost=0.00..586084.02 rows=1016801 width=55) (actual time=14090.840..21951.343 rows=1 loops=1)
Filter: (('200.8.8.8'::inet >= low) AND ('200.8.8.8'::inet <= high))
Rows Removed by Filter: 23156868
Buffers: shared hit=21232 read=217499
Planning time: 0.111 ms
Execution time: 21951.376 ms
After a bit of manual investigation I found that 74.181.234.146 uses the index but 74.181.234.147 does not. Interestingly, as I get higher, the queries that use the index start taking 600-700ms. Perhaps that's just an issue of finding the data on disk. That's an acceptable response time but faster would be better.
=> EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM ip_range_domains WHERE '74.181.234.146'::INET BETWEEN low AND high;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on ip_range_domains (cost=256258.42..580278.67 rows=5685950 width=55) (actual time=593.066..593.068 rows=3 loops=1)
Recheck Cond: (('74.181.234.146'::inet >= low) AND ('74.181.234.146'::inet <= high))
Heap Blocks: exact=3
Buffers: shared hit=38630
-> Bitmap Index Scan on idx_ip_range_inversed (cost=0.00..254836.93 rows=5685950 width=0) (actual time=593.057..593.057 rows=3 loops=1)
Index Cond: (('74.181.234.146'::inet >= low) AND ('74.181.234.146'::inet <= high))
Buffers: shared hit=38627
Planning time: 0.108 ms
Execution time: 593.094 ms
Lowest query that doesn't use an index:
=> EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM ip_range_domains WHERE '74.181.234.147'::INET BETWEEN low AND high;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Seq Scan on ip_range_domains (cost=0.00..586084.02 rows=5685950 width=55) (actual time=5723.461..21914.826 rows=3 loops=1)
Filter: (('74.181.234.147'::inet >= low) AND ('74.181.234.147'::inet <= high))
Rows Removed by Filter: 23156866
Buffers: shared hit=21864 read=216867
Planning time: 0.108 ms
Execution time: 21914.850 ms
Version:
=> SELECT version();
version
---------------------------------------------------------------------------------------------------------------
PostgreSQL 9.4.4 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16), 64-bit