化合物(数百万行)を含むテーブルを作成しています。これらの化合物のうち、特定の所定の機能/フラグメントに固定長のビット文字列でフラグが立てられています。このビット文字列には2000〜20000ビットが含まれるため、そこでより正確な数値を決定するには、さらに調査を行う必要があります。特定の特定の機能がある、または特定の機能がない化合物を検索する場合、このビット文字列の選択したサブセットで検索が行われます。これは毎回異なるサブセットになる可能性があります。
PostgreSQL(9.6または10)でこれらの検索を効率的にできるインデックスタイプはありますか?
挿入はまれで、バッチプロセスで行われますが、検索は最もよく使用される操作であり、できれば迅速で、誤検出や誤検出がないことが望ましいです。
私にはこれは漠然とGINインデックスの作業のように聞こえますが、このインデックスタイプについての私の理解では、それが本当に当てはまるかどうかを確認するには不十分です。
実際には別の解決策がある可能性があります。それは、フラグメント識別子(ビット文字列に固定位置があるため、数値識別子も持つ)+化合物IDのペアを含む個別の 'fragment_index'テーブルを作成することです。私の心配は、そのテーブルが巨大になり(フラグメントで平均50ヒットの20Mコンパウンド= 1G行)、それに対する複数の結合(フラグメントごとに1つ)があり、結合がコンパウンドテーブルとの一致の最大80%を返す可能性があることです。 (場合によってはこれが発生する可能性があります)、まったく機能しません。
私は、これを道路上で得る方向に向けて何か提案をいただければ幸いです。
更新:コード化されたショートコードを含むvarchar配列でtrigramモジュールを使用してGINインデックスを試しましたが、主にフィルター操作後に残ったデータの量に応じて、さまざまな結果が得られました。
意味のある例を示すために、テーブルが次のようになっているとします。
CREATE TABLE testcompounds (
id serial primary key,
cd_structure text,
features_as_text varchar(128),
features_as_bits bit varying(32)
);
CREATE INDEX flags_testcompounds on testcompounds using gin (features_as_text gin_trgm_ops);
CREATE TABLE fragments (
id serial primary key,
smarts text,
keystring varchar(4),
frequency int
);
insert into fragments (keystring,smarts) values('AAA', '*=O');
insert into fragments (keystring,smarts) values('AAB', '[#6]=O');
insert into fragments (keystring,smarts) values('AAC', '[#7]=O');
...
insert into fragments (keystring,smarts) values('AAN', '[#6]-F');
insert into fragments (keystring,smarts) values('AAO', '[#6]-Cl');
insert into fragments (keystring,smarts) values('AAP', '[#6]-Br');
...
etc.
そしてfeatures_as_textとfeatures_as_bitsフィールドは完全に入力されています。
これに対して実行できるクエリの例は次のとおりです。
select id, cd_structure from testcompounds
where
(features_as_bits & (B'00000000000000000000000000000001' << (2-1)) = (B'00000000000000000000000000000001' << (2-1)))
AND (features_as_bits & (B'00000000000000000000000000000001' << (18-1)) = (B'00000000000000000000000000000000'))
AND (features_as_bits & (B'00000000000000000000000000000001' << (19-1)) = (B'00000000000000000000000000000000'))
AND (features_as_bits & (B'00000000000000000000000000000001' << (5-1)) = (B'00000000000000000000000000000000'))
AND (features_as_bits & (B'00000000000000000000000000000001' << (6-1)) = (B'00000000000000000000000000000000'))
AND (features_as_bits & (B'00000000000000000000000000000001' << (7-1)) = (B'00000000000000000000000000000000'))
AND (features_as_bits & (B'00000000000000000000000000000001' << (8-1)) = (B'00000000000000000000000000000000'))
AND (features_as_bits & (B'00000000000000000000000000000001' << (9-1)) = (B'00000000000000000000000000000000'))
つまり、機能2があり、機能18、19、5、6、7、8、9がないものをすべて取得します。
ビット演算のインデックス戦略をいくつかテストしました。少し時間がかかります。
まず第一に、
バージョン:PostgreSQL 10.3
ホスト:Amazon RDS db.m4.largeの新しいインスタンス(vCPU:2、メモリ:8GB、ディスク:GP2-SSD 100GB)
CREATE EXTENSION IF NOT EXISTS intarray;
CREATE EXTENSION IF NOT EXISTS bloom;
CREATE TABLE IF NOT EXISTS t_bitwise (
id BIGINT
,c_int INTEGER
,c_bit BIT(31)
,c_int_arr _int4
,c_bool_0 BOOLEAN ,c_bool_1 BOOLEAN ,c_bool_2 BOOLEAN ,c_bool_3 BOOLEAN ,c_bool_4 BOOLEAN
,c_bool_5 BOOLEAN ,c_bool_6 BOOLEAN ,c_bool_7 BOOLEAN ,c_bool_8 BOOLEAN ,c_bool_9 BOOLEAN
,c_bool_10 BOOLEAN ,c_bool_11 BOOLEAN ,c_bool_12 BOOLEAN ,c_bool_13 BOOLEAN ,c_bool_14 BOOLEAN
,c_bool_15 BOOLEAN ,c_bool_16 BOOLEAN ,c_bool_17 BOOLEAN ,c_bool_18 BOOLEAN ,c_bool_19 BOOLEAN
,c_bool_20 BOOLEAN ,c_bool_21 BOOLEAN ,c_bool_22 BOOLEAN ,c_bool_23 BOOLEAN ,c_bool_24 BOOLEAN
,c_bool_25 BOOLEAN ,c_bool_26 BOOLEAN ,c_bool_27 BOOLEAN ,c_bool_28 BOOLEAN ,c_bool_29 BOOLEAN
,c_bool_30 BOOLEAN
,PRIMARY KEY (id)
);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_1 ON t_bitwise (c_bool_1);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_2 ON t_bitwise (c_bool_2);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_3 ON t_bitwise (c_bool_3);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_4 ON t_bitwise (c_bool_4);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_5 ON t_bitwise (c_bool_5);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_6 ON t_bitwise (c_bool_6);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_7 ON t_bitwise (c_bool_7);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_8 ON t_bitwise (c_bool_8);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_9 ON t_bitwise (c_bool_9);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_10 ON t_bitwise (c_bool_10);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_11 ON t_bitwise (c_bool_11);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_12 ON t_bitwise (c_bool_12);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_13 ON t_bitwise (c_bool_13);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_14 ON t_bitwise (c_bool_14);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_15 ON t_bitwise (c_bool_15);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_16 ON t_bitwise (c_bool_16);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_17 ON t_bitwise (c_bool_17);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_18 ON t_bitwise (c_bool_18);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_19 ON t_bitwise (c_bool_19);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_20 ON t_bitwise (c_bool_20);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_21 ON t_bitwise (c_bool_21);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_22 ON t_bitwise (c_bool_22);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_23 ON t_bitwise (c_bool_23);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_24 ON t_bitwise (c_bool_24);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_25 ON t_bitwise (c_bool_25);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_26 ON t_bitwise (c_bool_26);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_27 ON t_bitwise (c_bool_27);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_28 ON t_bitwise (c_bool_28);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_29 ON t_bitwise (c_bool_29);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_30 ON t_bitwise (c_bool_30);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_31 ON t_bitwise (c_bool_31);
CREATE INDEX IF NOT EXISTS idx_btree_on_bool_32 ON t_bitwise (c_bool_32);
CREATE INDEX IF NOT EXISTS idx_btree_on_composite_bool ON t_bitwise (
c_bool_32 ,c_bool_31
,c_bool_30 ,c_bool_29 ,c_bool_28 ,c_bool_27 ,c_bool_26 ,c_bool_25 ,c_bool_24 ,c_bool_23 ,c_bool_22 ,c_bool_21
,c_bool_20 ,c_bool_19 ,c_bool_18 ,c_bool_17 ,c_bool_16 ,c_bool_15 ,c_bool_14 ,c_bool_13 ,c_bool_12 ,c_bool_11
,c_bool_10 ,c_bool_9 ,c_bool_8 ,c_bool_7 ,c_bool_6 ,c_bool_5 ,c_bool_4 ,c_bool_3 ,c_bool_2 ,c_bool_1
)
;
CREATE INDEX IF NOT EXISTS idx_bloom_on_bool ON t_bitwise
USING bloom (
CAST(c_bool_1 AS INTEGER) ,CAST(c_bool_2 AS INTEGER) ,CAST(c_bool_3 AS INTEGER) ,CAST(c_bool_4 AS INTEGER) ,CAST(c_bool_5 AS INTEGER)
,CAST(c_bool_6 AS INTEGER) ,CAST(c_bool_7 AS INTEGER) ,CAST(c_bool_8 AS INTEGER) ,CAST(c_bool_9 AS INTEGER) ,CAST(c_bool_10 AS INTEGER)
,CAST(c_bool_11 AS INTEGER) ,CAST(c_bool_12 AS INTEGER) ,CAST(c_bool_13 AS INTEGER) ,CAST(c_bool_14 AS INTEGER) ,CAST(c_bool_15 AS INTEGER)
,CAST(c_bool_16 AS INTEGER) ,CAST(c_bool_17 AS INTEGER) ,CAST(c_bool_18 AS INTEGER) ,CAST(c_bool_19 AS INTEGER) ,CAST(c_bool_20 AS INTEGER)
,CAST(c_bool_21 AS INTEGER) ,CAST(c_bool_22 AS INTEGER) ,CAST(c_bool_23 AS INTEGER) ,CAST(c_bool_24 AS INTEGER) ,CAST(c_bool_25 AS INTEGER)
,CAST(c_bool_26 AS INTEGER) ,CAST(c_bool_27 AS INTEGER) ,CAST(c_bool_28 AS INTEGER) ,CAST(c_bool_29 AS INTEGER) ,CAST(c_bool_30 AS INTEGER)
,CAST(c_bool_31 AS INTEGER) ,CAST(c_bool_32 AS INTEGER)
) WITH (length=128)
;
CREATE OR REPLACE FUNCTION bitcheck_int(INTEGER, INTEGER)
RETURNS INTEGER
LANGUAGE SQL
IMMUTABLE
SECURITY INVOKER
PARALLEL SAFE
COST 0.01
AS $$
SELECT CASE
WHEN $1 & (1 << ($2 - 1)) > 0 THEN $2
ELSE -$2
END
$$
;
CREATE INDEX IF NOT EXISTS idx_bloom_on_int ON t_bitwise
USING bloom (
bitcheck_int(c_int, 1)
,bitcheck_int(c_int, 2)
,bitcheck_int(c_int, 3)
,bitcheck_int(c_int, 4)
,bitcheck_int(c_int, 5)
,bitcheck_int(c_int, 6)
,bitcheck_int(c_int, 7)
,bitcheck_int(c_int, 8)
,bitcheck_int(c_int, 9)
,bitcheck_int(c_int, 10)
,bitcheck_int(c_int, 11)
,bitcheck_int(c_int, 12)
,bitcheck_int(c_int, 13)
,bitcheck_int(c_int, 14)
,bitcheck_int(c_int, 15)
,bitcheck_int(c_int, 16)
,bitcheck_int(c_int, 17)
,bitcheck_int(c_int, 18)
,bitcheck_int(c_int, 19)
,bitcheck_int(c_int, 20)
,bitcheck_int(c_int, 21)
,bitcheck_int(c_int, 22)
,bitcheck_int(c_int, 23)
,bitcheck_int(c_int, 24)
,bitcheck_int(c_int, 25)
,bitcheck_int(c_int, 26)
,bitcheck_int(c_int, 27)
,bitcheck_int(c_int, 28)
,bitcheck_int(c_int, 29)
,bitcheck_int(c_int, 20)
,bitcheck_int(c_int, 31)
,bitcheck_int(c_int, 32)
) WITH (length=128)
;
CREATE OR REPLACE FUNCTION bitcheck_bit(BIT(32), INTEGER)
RETURNS INTEGER
LANGUAGE SQL
IMMUTABLE
SECURITY INVOKER
PARALLEL SAFE
COST 0.01
AS $$
SELECT CASE
WHEN $1::INTEGER & (1 << ($2 - 1)) > 0 THEN $2
ELSE -$2
END
$$
;
CREATE INDEX IF NOT EXISTS idx_bloom_on_bit ON t_bitwise
USING bloom (
bitcheck_bit(c_bit, 1)
,bitcheck_bit(c_bit, 2)
,bitcheck_bit(c_bit, 3)
,bitcheck_bit(c_bit, 4)
,bitcheck_bit(c_bit, 5)
,bitcheck_bit(c_bit, 6)
,bitcheck_bit(c_bit, 7)
,bitcheck_bit(c_bit, 8)
,bitcheck_bit(c_bit, 9)
,bitcheck_bit(c_bit, 10)
,bitcheck_bit(c_bit, 11)
,bitcheck_bit(c_bit, 12)
,bitcheck_bit(c_bit, 13)
,bitcheck_bit(c_bit, 14)
,bitcheck_bit(c_bit, 15)
,bitcheck_bit(c_bit, 16)
,bitcheck_bit(c_bit, 17)
,bitcheck_bit(c_bit, 18)
,bitcheck_bit(c_bit, 19)
,bitcheck_bit(c_bit, 20)
,bitcheck_bit(c_bit, 21)
,bitcheck_bit(c_bit, 22)
,bitcheck_bit(c_bit, 23)
,bitcheck_bit(c_bit, 24)
,bitcheck_bit(c_bit, 25)
,bitcheck_bit(c_bit, 26)
,bitcheck_bit(c_bit, 27)
,bitcheck_bit(c_bit, 28)
,bitcheck_bit(c_bit, 29)
,bitcheck_bit(c_bit, 20)
,bitcheck_bit(c_bit, 31)
,bitcheck_bit(c_bit, 32)
) WITH (length=128)
;
CREATE INDEX IF NOT EXISTS idx_gin_on_int_arr ON t_bitwise
USING GIN(c_int_arr gin__int_ops)
;
CREATE OR REPLACE FUNCTION convert_int_to_int_arr(INTEGER)
RETURNS _int4
LANGUAGE SQL
IMMUTABLE
STRICT
SECURITY INVOKER
PARALLEL SAFE
COST 0.01
AS $$
SELECT ARRAY(
SELECT
CASE
WHEN (1 << (i - 1)) & $1 > 0 THEN i
ELSE -i
END
FROM generate_series(1, 32) AS i
)
$$
;
CREATE INDEX IF NOT EXISTS idx_gin_int_on_int ON t_bitwise
USING GIN(convert_int_to_int_arr(c_int) gin__int_ops)
;
CREATE OR REPLACE FUNCTION convert_bit_to_int_arr(BIT(32))
RETURNS _int4
LANGUAGE SQL
IMMUTABLE
STRICT
SECURITY INVOKER
PARALLEL SAFE
COST 0.01
AS $$
SELECT ARRAY(
SELECT
CASE
WHEN (1 << (i - 1)) & $1::INTEGER > 0 THEN i
ELSE -i
END
FROM generate_series(1, 32) AS i
)
$$
;
CREATE INDEX IF NOT EXISTS idx_gin_int_on_bit ON t_bitwise
USING GIN(convert_bit_to_int_arr(c_bit) gin__int_ops)
;
時間がかかります。
INSERT INTO t_bitwise (
id ,c_int ,c_bit ,c_int_arr
,c_bool_1 ,c_bool_2 ,c_bool_3 ,c_bool_4 ,c_bool_5 ,c_bool_6 ,c_bool_7 ,c_bool_8 ,c_bool_9 ,c_bool_10
,c_bool_11 ,c_bool_12 ,c_bool_13 ,c_bool_14 ,c_bool_15 ,c_bool_16 ,c_bool_17 ,c_bool_18 ,c_bool_19 ,c_bool_20
,c_bool_21 ,c_bool_22 ,c_bool_23 ,c_bool_24 ,c_bool_25 ,c_bool_26 ,c_bool_27 ,c_bool_28 ,c_bool_29 ,c_bool_30
,c_bool_31 ,c_bool_32
) SELECT
id
,t.Rand_int
,t.Rand_int::BIT(32)
/*
,ARRAY(
SELECT
(1 << (i - 1)) & t.Rand_int
FROM generate_series(1, 32) AS i
WHERE
((1 << (i - 1)) & t.Rand_int > 0)
)
*/
,ARRAY(
SELECT
CASE
WHEN (1 << (i - 1)) & t.Rand_int > 0 THEN i
ELSE -i
END
FROM generate_series(1, 32) AS i
)
,(1 << 0) & t.Rand_int > 0 ,(1 << 1) & t.Rand_int > 0 ,(1 << 2) & t.Rand_int > 0 ,(1 << 3) & t.Rand_int > 0
,(1 << 4) & t.Rand_int > 0 ,(1 << 5) & t.Rand_int > 0 ,(1 << 6) & t.Rand_int > 0 ,(1 << 7) & t.Rand_int > 0
,(1 << 8) & t.Rand_int > 0 ,(1 << 9) & t.Rand_int > 0 ,(1 << 10) & t.Rand_int > 0 ,(1 << 11) & t.Rand_int > 0
,(1 << 12) & t.Rand_int > 0 ,(1 << 13) & t.Rand_int > 0 ,(1 << 14) & t.Rand_int > 0 ,(1 << 15) & t.Rand_int > 0
,(1 << 16) & t.Rand_int > 0 ,(1 << 17) & t.Rand_int > 0 ,(1 << 18) & t.Rand_int > 0 ,(1 << 19) & t.Rand_int > 0
,(1 << 20) & t.Rand_int > 0 ,(1 << 21) & t.Rand_int > 0 ,(1 << 22) & t.Rand_int > 0 ,(1 << 23) & t.Rand_int > 0
,(1 << 24) & t.Rand_int > 0 ,(1 << 25) & t.Rand_int > 0 ,(1 << 26) & t.Rand_int > 0 ,(1 << 27) & t.Rand_int > 0
,(1 << 28) & t.Rand_int > 0 ,(1 << 29) & t.Rand_int > 0 ,(1 << 30) & t.Rand_int > 0 ,(1 << 31) & t.Rand_int > 0
FROM (
SELECT
id
,(random() * 4294967295)::BIGINT::BIT(32)::INTEGER AS Rand_int
FROM generate_series(1, 30000000) AS id
) AS t
;
SELECT
gin_clean_pending_list('idx_gin_on_int_arr')
,gin_clean_pending_list('idx_gin_int_on_int')
,gin_clean_pending_list('idx_gin_int_on_bit')
;
VACUUM FULL
;
ANALYZE t_bitwise
;
SELECT COUNT(*) FROM t_bitwise
;
SELECT
indexname,
pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,
pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size
FROM pg_tables t
LEFT OUTER JOIN pg_class c ON t.tablename = c.relname
LEFT OUTER JOIN (
SELECT
c.relname AS ctablename, ipg.relname AS indexname, indexrelname
FROM pg_index x
JOIN pg_class c ON c.oid = x.indrelid
JOIN pg_class ipg ON ipg.oid = x.indexrelid
JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid
) AS foo ON t.tablename = foo.ctablename
WHERE t.schemaname = 'public' AND t.tablename = 't_bitwise' AND indexname != 't_bitwise_pkey'
;
結果
indexname | table_size | index_size
-----------------------------+------------+------------
idx_btree_on_bool_1 | 6893 MB | 643 MB
idx_btree_on_bool_2 | 6893 MB | 643 MB
idx_btree_on_bool_3 | 6893 MB | 643 MB
idx_btree_on_bool_4 | 6893 MB | 643 MB
idx_btree_on_bool_5 | 6893 MB | 643 MB
idx_btree_on_bool_6 | 6893 MB | 643 MB
idx_btree_on_bool_7 | 6893 MB | 643 MB
idx_btree_on_bool_8 | 6893 MB | 643 MB
idx_btree_on_bool_9 | 6893 MB | 643 MB
idx_btree_on_bool_10 | 6893 MB | 643 MB
idx_btree_on_bool_11 | 6893 MB | 643 MB
idx_btree_on_bool_12 | 6893 MB | 643 MB
idx_btree_on_bool_13 | 6893 MB | 643 MB
idx_btree_on_bool_14 | 6893 MB | 643 MB
idx_btree_on_bool_15 | 6893 MB | 643 MB
idx_btree_on_bool_16 | 6893 MB | 643 MB
idx_btree_on_bool_17 | 6893 MB | 643 MB
idx_btree_on_bool_18 | 6893 MB | 643 MB
idx_btree_on_bool_19 | 6893 MB | 643 MB
idx_btree_on_bool_20 | 6893 MB | 643 MB
idx_btree_on_bool_21 | 6893 MB | 643 MB
idx_btree_on_bool_22 | 6893 MB | 643 MB
idx_btree_on_bool_23 | 6893 MB | 643 MB
idx_btree_on_bool_24 | 6893 MB | 643 MB
idx_btree_on_bool_25 | 6893 MB | 643 MB
idx_btree_on_bool_26 | 6893 MB | 643 MB
idx_btree_on_bool_27 | 6893 MB | 643 MB
idx_btree_on_bool_28 | 6893 MB | 643 MB
idx_btree_on_bool_29 | 6893 MB | 643 MB
idx_btree_on_bool_30 | 6893 MB | 643 MB
idx_btree_on_bool_31 | 6893 MB | 643 MB
idx_btree_on_bool_32 | 6893 MB | 643 MB
idx_btree_on_composite_bool | 6893 MB | 1423 MB
idx_bloom_on_bool | 6893 MB | 633 MB
idx_bloom_on_int | 6893 MB | 633 MB
idx_bloom_on_bit | 6893 MB | 633 MB
idx_gin_on_int_arr | 6893 MB | 1030 MB
idx_gin_int_on_int | 6893 MB | 1030 MB
idx_gin_int_on_bit | 6893 MB | 1030 MB
すべての実行時間結果は、secondクエリ結果から取得されます。これは、最初のクエリは通常、インデックスをメモリにロードするのに時間がかかるためです。
1ビットフィルタリング(Parallel Seq Scan、実行時間:122930.731 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_int & 1 = 1
;
16ビットフィルタリング(Parallel Seq Scan、122896.131 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_int & 255 = 255
AND (c_int >> 8) & 255 = 0
;
1ビットフィルタリング(シーケンススキャン、実行時間:122853.069 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_bool_1 IS TRUE
;
16ビットフィルタリング(並列シーケンス、実行時間:122834.960ミリ秒)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_bool_1 IS TRUE
AND c_bool_2 IS TRUE
AND c_bool_3 IS TRUE
AND c_bool_4 IS TRUE
AND c_bool_5 IS TRUE
AND c_bool_6 IS TRUE
AND c_bool_7 IS TRUE
AND c_bool_8 IS TRUE
AND c_bool_9 IS FALSE
AND c_bool_10 IS FALSE
AND c_bool_11 IS FALSE
AND c_bool_12 IS FALSE
AND c_bool_13 IS FALSE
AND c_bool_14 IS FALSE
AND c_bool_15 IS FALSE
AND c_bool_16 IS FALSE
;
16ビットフィルタリング(idx_btree_on_composite_boolを使用、実行時間:293.317 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_bool_32 IN (TRUE, FALSE)
AND c_bool_31 IN (TRUE, FALSE)
AND c_bool_30 IN (TRUE, FALSE)
AND c_bool_29 IN (TRUE, FALSE)
AND c_bool_28 IN (TRUE, FALSE)
AND c_bool_27 IN (TRUE, FALSE)
AND c_bool_26 IN (TRUE, FALSE)
AND c_bool_25 IN (TRUE, FALSE)
AND c_bool_24 IN (TRUE, FALSE)
AND c_bool_23 IN (TRUE, FALSE)
AND c_bool_22 IN (TRUE, FALSE)
AND c_bool_21 IN (TRUE, FALSE)
AND c_bool_20 IN (TRUE, FALSE)
AND c_bool_19 IN (TRUE, FALSE)
AND c_bool_18 IN (TRUE, FALSE)
AND c_bool_17 IN (TRUE, FALSE)
AND c_bool_16 IS FALSE
AND c_bool_15 IS FALSE
AND c_bool_14 IS FALSE
AND c_bool_13 IS FALSE
AND c_bool_12 IS FALSE
AND c_bool_11 IS FALSE
AND c_bool_10 IS FALSE
AND c_bool_9 IS FALSE
AND c_bool_8 IS TRUE
AND c_bool_7 IS TRUE
AND c_bool_6 IS TRUE
AND c_bool_5 IS TRUE
AND c_bool_4 IS TRUE
AND c_bool_3 IS TRUE
AND c_bool_2 IS TRUE
AND c_bool_1 IS TRUE
;
1ビットフィルタリング(シーケンススキャン、実行時間:122726.850ミリ秒)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
CAST(c_bool_1 AS INTEGER) = 1
;
16ビットフィルタリング(idx_bloom_on_boolを使用、実行時間:373.581 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
CAST(c_bool_1 AS INTEGER) = 1
AND CAST(c_bool_2 AS INTEGER) = 1
AND CAST(c_bool_3 AS INTEGER) = 1
AND CAST(c_bool_4 AS INTEGER) = 1
AND CAST(c_bool_5 AS INTEGER) = 1
AND CAST(c_bool_6 AS INTEGER) = 1
AND CAST(c_bool_7 AS INTEGER) = 1
AND CAST(c_bool_8 AS INTEGER) = 1
AND CAST(c_bool_9 AS INTEGER) = 0
AND CAST(c_bool_10 AS INTEGER) = 0
AND CAST(c_bool_11 AS INTEGER) = 0
AND CAST(c_bool_12 AS INTEGER) = 0
AND CAST(c_bool_13 AS INTEGER) = 0
AND CAST(c_bool_14 AS INTEGER) = 0
AND CAST(c_bool_15 AS INTEGER) = 0
AND CAST(c_bool_16 AS INTEGER) = 0
;
1ビットフィルタリング(シーケンススキャン、実行時間:122660.620ミリ秒)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
bitcheck_int(c_int, 1) = 1
;
16ビットフィルタリング(idx_bloom_on_intを使用、実行時間:391.335 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
bitcheck_int(c_int, 1) = 1
AND bitcheck_int(c_int, 2) = 2
AND bitcheck_int(c_int, 3) = 3
AND bitcheck_int(c_int, 4) = 4
AND bitcheck_int(c_int, 5) = 5
AND bitcheck_int(c_int, 6) = 6
AND bitcheck_int(c_int, 7) = 7
AND bitcheck_int(c_int, 8) = 8
AND bitcheck_int(c_int, 9) = -9
AND bitcheck_int(c_int, 10) = -10
AND bitcheck_int(c_int, 11) = -11
AND bitcheck_int(c_int, 12) = -12
AND bitcheck_int(c_int, 13) = -13
AND bitcheck_int(c_int, 14) = -14
AND bitcheck_int(c_int, 15) = -15
AND bitcheck_int(c_int, 16) = -16
;
1ビットフィルタリング(シーケンススキャン、実行時間:122434.644 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
bitcheck_bit(c_bit, 1) = 1
;
16ビットフィルタリング(idx_bloom_on_bitを使用、実行時間:397.157 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
bitcheck_bit(c_bit, 1) = 1
AND bitcheck_bit(c_bit, 2) = 2
AND bitcheck_bit(c_bit, 3) = 3
AND bitcheck_bit(c_bit, 4) = 4
AND bitcheck_bit(c_bit, 5) = 5
AND bitcheck_bit(c_bit, 6) = 6
AND bitcheck_bit(c_bit, 7) = 7
AND bitcheck_bit(c_bit, 8) = 8
AND bitcheck_bit(c_bit, 9) = -9
AND bitcheck_bit(c_bit, 10) = -10
AND bitcheck_bit(c_bit, 11) = -11
AND bitcheck_bit(c_bit, 12) = -12
AND bitcheck_bit(c_bit, 13) = -13
AND bitcheck_bit(c_bit, 14) = -14
AND bitcheck_bit(c_bit, 15) = -15
AND bitcheck_bit(c_bit, 16) = -16
;
1ビットフィルタリング(idx_gin_on_int_arrが使用され、実行時間:440942.779 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_int_arr @> (ARRAY[1])::_int4
;
16ビットフィルタリング(idx_gin_on_int_arrを使用、実行時間:15322.953 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
c_int_arr @> (ARRAY[1,2,3,4,5,6,7,8,-9,-10,-11,-12,-13,-14,-15,-16])::_int4
;
1ビットフィルタリング(idx_gin_int_on_intが使用され、実行時間:489909.621 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
convert_int_to_int_arr(c_int) @> (ARRAY[1])::_int4
;
16ビットフィルタリング(idx_gin_int_on_intが使用され、実行時間:15259.772 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
convert_int_to_int_arr(c_int) @> (ARRAY[1,2,3,4,5,6,7,8,-9,-10,-11,-12,-13,-14,-15,-16])::_int4
;
1ビットフィルタリング(idx_gin_int_on_bitが使用され、実行時間:506071.625 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
convert_bit_to_int_arr(c_bit) @> (ARRAY[1])::_int4
;
16ビットフィルタリング(idx_gin_int_on_bitが使用され、実行時間:15292.945 ms)
EXPLAIN ANALYZE SELECT 1 FROM t_bitwise
WHERE
convert_bit_to_int_arr(c_bit) @> (ARRAY[1,2,3,4,5,6,7,8,-9,-10,-11,-12,-13,-14,-15,-16])::_int4
;
化合物(数百万行)を含むテーブルを作成しています。これらの化合物のうち、特定の所定の機能/フラグメントに固定長のビット文字列でフラグが立てられています。このビット文字列は2000から20000ビットの範囲にあります。そこでより正確な数値を決定するには、さらに調査を行う必要があります。特定の特定の機能がある、または特定の機能がない化合物を検索する場合、このビット文字列の選択サブセットで検索が実行されます。これは毎回異なるサブセットになる可能性があります。
ここでは bloom
index を使用できると思います。
CREATE EXTENSION bloom;
ブードゥー法を実行して、引数のブール値を返します。
// (Bitwise AND it against the bit flag)
CREATE FUNCTION myT1 (int)
RETURNS bool AS $$
SELECT true -- YOU WRITE CODE HERE
$$ LANGUAGE SQL
IMMUTABLE;
// (Bitwise AND it against the bit flag)
CREATE FUNCTION myT2 (int)
RETURNS bool AS $$
SELECT $1 & b'10'::bit(32) -- YOU WRITE CODE HERE
$$ LANGUAGE SQL
IMMUTABLE;
// (Bitwise AND it against the bit flag)
CREATE FUNCTION myTn (int)
RETURNS bool AS $$
SELECT $1 & b'01'::bit(32) -- YOU WRITE CODE HERE
$$ LANGUAGE SQL
IMMUTABLE;
CREATE INDEX b ON f
USING bloom (myT1(id), myT2, myTn(id))
WITH (length=80, col1=1);
これは、PostgreSQLの列制限を回避しながら、任意の条件で大きな検索文字列へのインデックス付きアクセスを提供するために機能する場合がありますが、面倒です。インデックスは偽陽性を返します。ただし、クエリは再チェックされるので、心配する必要はありません。