Index
BRIN stands for Block Range Index:
This stores a range of values within a number of adjacent pages in the table.
Take an example of 9 numbers, divided into three pages
(pages_per_range
is used to change this setting):
1, 2, 3, 4, 5, 6, 7, 8, 9
1,2,3], [4,5,6], [7,8,9] [
A BRIN index keeps the minimum and maximum values of each block:
That way, when we use the index to find the value 5:
We know this:
If we don't have sorted data, or loosely correlated data:
2,9,5], [1,4,7], [3,8,6] [
The ranges look like this:
2–9], [1–7], [3–8] [
Looking at the index, we find this:
The index is useless, so the query planner will most likely not use it:
We create a BRIN index like so:
= CREATE INDEX sale_fact_sold_at_bix ON sale_fact
db- USING BRIN(sold_at) WITH (pages_per_range = 128);
dbCREATE INDEX
= EXPLAIN (ANALYZE)
db- SELECT *
db- FROM sale_fact
db- WHERE sold_at BETWEEN '2020-07-01' AND '2020-07-31';
dbQUERY PLAN
--------------------
Bitmap Heap Scan on sale_fact (cost=13.11..1135.61 rows=4319 width=41)
>= '2020-07-01'::date) AND (sold_at <= '2020-07-31'::date))
Recheck Cond: ((sold_at Rows Removed by Index Recheck: 23130
Heap Blocks: lossy=256
-> Bitmap Index Scan on sale_fact_sold_at_bix (cost=0.00..12.03 rows=12500 width=0)
Index Cond: ((sold_at >= '2020-07-01'::date) AND (sold_at <= '2020-07-31'::date))
Time: 8.877 ms Execution
We removed ~23000 rows, which costs a lot of I/O.
If we drop the pages_per_range
to 64:
= CREATE INDEX sale_fact_sold_at_bix64 ON sale_fact
db- USING BRIN(sold_at) WITH (pages_per_range = 64);
dbCREATE INDEX
We get only ~9400 rows checked, and a query time of ~5.5ms, compared to the ~8.8ms from before, a ~45% speedup.
= EXPLAIN (ANALYZE)
db- SELECT *
db- FROM sale_fact
db- WHERE sold_at BETWEEN '2020-07-01' AND '2020-07-31';
dbQUERY PLAN
---------------------
Bitmap Heap Scan on sale_fact (cost=13.10..1048.10 rows=4319 width=41)
>= '2020-07-01'::date) AND (sold_at <= '2020-07-31'::date))
Recheck Cond: ((sold_at Rows Removed by Index Recheck: 9434
Heap Blocks: lossy=128
-> Bitmap Index Scan on sale_fact_sold_at_bix64 (cost=0.00..12.02 rows=6667 width=0)
Index Cond: ((sold_at >= '2020-07-01'::date) AND (sold_at <= '2020-07-31'::date))
Time: 5.491 ms Execution
As you can see, the BRIN Index (by default) is ~50 times smaller than the B-Tree index, and can have some performance gains.
Schema | Name | Type | Owner | Table | Size
--------+-----------------------+-------+-------+-----------+-------
public | sale_fact_sold_at_bix | index | haki | sale_fact | 48 kB
public | sale_fact_sold_at_ix | index | haki | sale_fact | 2224 kB