多列索引中的布尔列

时间:2016-12-10 11:30:50

标签: postgresql indexing boolean b-tree

测试表和索引:

CREATE TABLE public.t (id serial, cb boolean, ci integer, co integer)

INSERT INTO t(cb, ci, co) 
SELECT ((round(random()*1))::int)::boolean, round(random()*100), round(random()*100)
FROM generate_series(1, 1000000)

CREATE INDEX "right" ON public.t USING btree (ci, cb, co);
CREATE INDEX wrong ON public.t USING btree (ci, co);
CREATE INDEX right_hack ON public.t USING btree (ci, (cb::integer), co);

问题是我不能强迫PostgreSQL使用“正确”的索引。下一个查询使用“错误”索引。它不是最优的,因为它使用“Filter”(条件:cb = TRUE),因此从内存中读取更多数据(并且执行变得更长):

explain (analyze, buffers)
SELECT * FROM t WHERE cb = TRUE AND ci = 46 ORDER BY co LIMIT 1000

"Limit  (cost=0.42..4063.87 rows=1000 width=13) (actual time=0.057..4.405 rows=1000 loops=1)"
"  Buffers: shared hit=1960"
"  ->  Index Scan using wrong on t  (cost=0.42..21784.57 rows=5361 width=13) (actual time=0.055..4.256 rows=1000 loops=1)"
"        Index Cond: (ci = 46)"
"        Filter: cb"
"        Rows Removed by Filter: 967"
"        Buffers: shared hit=1960"
"Planning time: 0.318 ms"
"Execution time: 4.530 ms"

但是当我将bool列转换为int时,它运行正常。这一点尚不清楚,因为两个索引(right和right_hack)的选择性保持不变。

explain (analyze, buffers)
SELECT * FROM t WHERE cb::int = 1 AND ci = 46 ORDER BY co LIMIT 1000

"Limit  (cost=0.42..2709.91 rows=1000 width=13) (actual time=0.027..1.484 rows=1000 loops=1)"
"  Buffers: shared hit=1003"
"  ->  Index Scan using right_hack on t  (cost=0.42..14525.95 rows=5361 width=13) (actual time=0.025..1.391 rows=1000 loops=1)"
"        Index Cond: ((ci = 46) AND ((cb)::integer = 1))"
"        Buffers: shared hit=1003"
"Planning time: 0.202 ms"
"Execution time: 1.565 ms"

在多列索引中使用布尔列是否有任何限制?

1 个答案:

答案 0 :(得分:1)

条件索引(或两个)似乎确实有效:

CREATE INDEX true_bits ON ttt (ci, co)
  WHERE cb = True ;

CREATE INDEX false_bits ON ttt (ci, co)
  WHERE cb = False ;

VACUUM ANALYZE ttt;

EXPLAIN (ANALYZE, buffers)
SELECT * FROM ttt
WHERE cb = TRUE AND ci = 46 ORDER BY co LIMIT 1000
        ;

计划

                                                          QUERY PLAN                                                           
-------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.25..779.19 rows=1000 width=13) (actual time=0.024..1.804 rows=1000 loops=1)
   Buffers: shared hit=1001
   ->  Index Scan using true_bits on ttt  (cost=0.25..3653.46 rows=4690 width=13) (actual time=0.020..1.570 rows=1000 loops=1)
         Index Cond: (ci = 46)
         Buffers: shared hit=1001
 Planning time: 0.468 ms
 Execution time: 1.949 ms
(7 rows)

尽管如此,低基数列的索引收益却很少。索引条目可以避免页面读取的可能性非常小。对于8K的页面大小和~20的行大小,页面上有大约400条记录。任何页面上都会(几乎)始终是 true 记录(以及 false 记录),因此无论如何都必须阅读该页面。