This presentation will provide an overview of the index BRIN provided by PotgreSQL, how it works, and how to tune it.
We hope that you will consider using BRIN indexes as an option when designing your database.
句に brin を指定する。 postgres@brin=# \d test Unlogged table "public.test" Column | Type | Collation | Nullable | Default --------+--------------------------+-----------+----------+--------- id | integer | | not null | reg_ts | timestamp with time zone | | | data | text | | | Indexes: "test_pkey" PRIMARY KEY, btree (id) postgres@brin=# CREATE INDEX reg_ts_brin ON test USING brin (reg_ts); CREATE INDEX
postgres@brin=# CREATE TABLE ut_test(id int, fd fraction, dummy text); CREATE TABLE postgres@brin=# \d ut_test Table "public.ut_test" Column | Type | Collation | Nullable | Default --------+----------+-----------+----------+--------- id | integer | | | fd | fraction | | | dummy | text | | | postgres@brin=# EXPLAIN SELECT * FROM ut_test WHERE fd >= '999/2' AND fd <= '1005/2'; QUERY PLAN ---------------------------------------------------------------------- Seq Scan on ut_test (cost=0.00..25.30 rows=5 width=52) Filter: ((fd >= '999/2'::fraction) AND (fd <= '1005/2'::fraction)) (2 rows) postgres@brin=# CREATE INDEX fd_brin ON ut_test USING brin (fd); ERROR: data type fraction has no default operator class for access method "brin" HINT: You must specify an operator class for the index or define a default operator class for the data type. postgres@brin=#
を使った検索の実行計画例 postgres@brin=# EXPLAIN SELECT * FROM test WHERE reg_ts BETWEEN '2025-01-01' AND '2025-01-02'; QUERY PLAN ------------------------------------------------------------------------------------------------------------- -------------------------------------------- Bitmap Heap Scan on test (cost=21.59..35190.58 rows=6239 width=45) Recheck Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-02 00:00:00+09'::timestamp with time zone)) -> Bitmap Index Scan on reg_ts_brin (cost=0.00..20.03 rows=12407 width=0) Index Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01- 02 00:00:00+09'::timestamp with time zone)) (4 rows)
SELECT * FROM test WHERE reg_ts BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 01:00:00'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------- -------------------------------------- Bitmap Heap Scan on test (cost=20.10..35189.08 rows=258 width=45) (actual time=0.879..2.611 rows=277 loops=1) Recheck Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Rows Removed by Index Recheck: 12139 Heap Blocks: lossy=128 -> Bitmap Index Scan on reg_ts_brin (cost=0.00..20.03 rows=12407 width=0) (actual time=0.204..0.205 rows=1280 loops=1) Index Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Planning Time: 0.254 ms Execution Time: 2.751 ms (8 rows) 最小限のブロックスキャン なので高速
SELECT * FROM test WHERE reg_ts BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 01:00:00'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------- ---------- ---------------------------- Bitmap Heap Scan on test (cost=33.18..229725.69 rows=282 width=45) (actual time=13.760..1559.978 rows=277 loops=1) Recheck Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Rows Removed by Index Recheck: 9999723 Heap Blocks: lossy=103093 -> Bitmap Index Scan on reg_ts_brin (cost=0.00..33.11 rows=5082895 width=0) (actual time=3.556..3.558 rows=1031280 loops =1) Index Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Planning Time: 0.097 ms Execution Time: 1560.306 ms (8 rows) 大量のブロックを読込み ほとんど Recheck で除外 とても遅い・・・
test WHERE reg_ts BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 01:00:00'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- ---------------------------------------- Bitmap Heap Scan on test (cost=20.11..35189.09 rows=299 width=45) (actual time=0.854..2.545 rows=277 loops=1) Recheck Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Rows Removed by Index Recheck: 12139 Heap Blocks: lossy=128 -> Bitmap Index Scan on reg_ts_brin (cost=0.00..20.03 rows=12407 width=0) (actual time=0.188..0.188 rows=1280 loops=1) Index Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Planning Time: 0.557 ms Execution Time: 2.676 ms (8 rows)
* FROM test WHERE reg_ts BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 01:00:00'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- ---------------------------------------- Bitmap Heap Scan on test (cost=20.11..35913.31 rows=329 width=45) (actual time=0.698..124.456 rows=277 loops=1) Recheck Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Rows Removed by Index Recheck: 1004843 Heap Blocks: lossy=10363 -> Bitmap Index Scan on reg_ts_brin (cost=0.00..20.03 rows=12415 width=0) (actual time=0.313..0.314 rows=103630 loops=1) Index Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Planning Time: 0.062 ms Execution Time: 124.605 ms (8 rows)
--------------------------- 80 (1 row) Time: 176.186 ms EXPLAIN ANALYZE SELECT * FROM test WHERE reg_ts BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 01:00:00'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- ---------------------------------------- Bitmap Heap Scan on test (cost=24.11..35917.31 rows=329 width=45) (actual time=0.577..1.599 rows=277 loops=1) Recheck Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Rows Removed by Index Recheck: 12139 Heap Blocks: lossy=128 -> Bitmap Index Scan on reg_ts_brin (cost=0.00..24.03 rows=12415 width=0) (actual time=0.181..0.181 rows=1280 loops=1) Index Cond: ((reg_ts >= '2025-01-01 00:00:00+09'::timestamp with time zone) AND (reg_ts <= '2025-01-01 01:00:00+09'::timestamp with time zone)) Planning Time: 0.058 ms Execution Time: 1.730 ms (8 rows)