B树索引好像没有用?
B-tree index does not seem to be used?
我是 Postgres 的新手,我想更多地了解索引。我使用的是 12.5 版,这是我的代码:
CREATE TABLE textfun(content TEXT);
CREATE UNIQUE INDEX text_b ON textfun(content);
INSERT INTO textfun (content)
SELECT (CASE WHEN (random()<=0.3) THEN 'https://mywebsite/nanana/'
WHEN (random()<=0.6) THEN 'https://mywebsite/friendy/'
ELSE 'https://mywebsite/mina/' END) || generate_series(1000000,2000000);
这里,我创建了一百万条记录,希望能看到索引的效果。
当我尝试获取查询计划时:
explain analyze
SELECT content FROM textfun WHERE content LIKE 'mina%';
我回来了:
Gather (cost=1000.00..14300.34 rows=100 width=32) (actual time=77.574..80.054 rows=0 loops=1)
Workers Planned: 2
Workers Launched: 2
Parallel Seq Scan on textfun (cost=0.00..13290.34 rows=42 width=32) (actual time=69.022..69.022 rows=0 loops=3)
Filter: (content ~~ 'mina%'::text)
Rows Removed by Filter: 333334
Planning Time: 0.254 ms
Execution Time: 80.071 ms
(8 rows)
我期待并行索引扫描。
我试过了:
explain analyze
SELECT content FROM textfun WHERE content LIKE '1500000%';
和:
explain analyze
SELECT content FROM textfun WHERE content LIKE '%mina';
但都给我一个顺序扫描计划。
这里有没有我遗漏的细节,为什么我没有进行索引扫描?
要支持 LIKE 条件,您需要使用 text_pattern_ops
创建索引
CREATE UNIQUE INDEX text_b ON textfun(content text_pattern_ops);
这样,结果就是下面的执行计划:
Bitmap Heap Scan on textfun (cost=191.68..7654.53 rows=5000 width=32) (actual time=2.553..2.554 rows=0 loops=1)
Filter: (content ~~ '1500000%'::text)
-> Bitmap Index Scan on text_b (cost=0.00..190.43 rows=5000 width=0) (actual time=2.550..2.550 rows=0 loops=1)
Index Cond: ((content ~>=~ '1500000'::text) AND (content ~<~ '1500001'::text))
Planning Time: 6.247 ms
Execution Time: 6.809 ms
正确第一。您的谓词将找不到 'https://mywebsite/mina/':
content LIKE 'mina%'
其中一个可行:
content LIKE '%mina%'
content ~ 'mina'
但是 btree 索引都不支持。三字母索引可以做到这一点:
CREATE INDEX ON textfun USING gin (content gin_trgm_ops);
参见:
- PostgreSQL LIKE query performance variations
或者 text search index(在你的 URI 中分隔单词之后......)
但是 GIN 索引不能强制唯一性。您可能需要第二个 B 树索引。 (或暗示此类索引的约束)。
为了真正支持您原来的左锚定谓词,我将使用具有 COLLATE "C"
:
的 B 树索引
CREATE UNIQUE INDEX text_b ON textfun(content COLLATE "C");
Per-column collation support added with Postgres 9.1 largely obsoleted the old xxx_pattern_ops
operator classes。参见:
db<>fiddle here - COLLATE "C"
,行数更少(足以证明这一点)。
这里是 Postgres 中模式匹配选项的综合概述:
除此之外,只有三个不同值的测试用例不是很有用。当 Postgres 期望获取所有行的百分之几以上时,它通常根本不会使用任何索引,因为顺序扫描通常更快。它会知道一些“最常见的值”,因为它会按 ANALYZE
(或默认情况下 autovacuum
)更新统计信息。
在这方面搜索 content LIKE '1500000%'
是不同的,因为 Postgres 会知道它不常见并使用适用的索引 ...
索引优化取决于全貌:环境和要求...
我是 Postgres 的新手,我想更多地了解索引。我使用的是 12.5 版,这是我的代码:
CREATE TABLE textfun(content TEXT);
CREATE UNIQUE INDEX text_b ON textfun(content);
INSERT INTO textfun (content)
SELECT (CASE WHEN (random()<=0.3) THEN 'https://mywebsite/nanana/'
WHEN (random()<=0.6) THEN 'https://mywebsite/friendy/'
ELSE 'https://mywebsite/mina/' END) || generate_series(1000000,2000000);
这里,我创建了一百万条记录,希望能看到索引的效果。
当我尝试获取查询计划时:
explain analyze
SELECT content FROM textfun WHERE content LIKE 'mina%';
我回来了:
Gather (cost=1000.00..14300.34 rows=100 width=32) (actual time=77.574..80.054 rows=0 loops=1)
Workers Planned: 2
Workers Launched: 2
Parallel Seq Scan on textfun (cost=0.00..13290.34 rows=42 width=32) (actual time=69.022..69.022 rows=0 loops=3)
Filter: (content ~~ 'mina%'::text)
Rows Removed by Filter: 333334
Planning Time: 0.254 ms
Execution Time: 80.071 ms
(8 rows)
我期待并行索引扫描。
我试过了:
explain analyze
SELECT content FROM textfun WHERE content LIKE '1500000%';
和:
explain analyze
SELECT content FROM textfun WHERE content LIKE '%mina';
但都给我一个顺序扫描计划。
这里有没有我遗漏的细节,为什么我没有进行索引扫描?
要支持 LIKE 条件,您需要使用 text_pattern_ops
创建索引CREATE UNIQUE INDEX text_b ON textfun(content text_pattern_ops);
这样,结果就是下面的执行计划:
Bitmap Heap Scan on textfun (cost=191.68..7654.53 rows=5000 width=32) (actual time=2.553..2.554 rows=0 loops=1)
Filter: (content ~~ '1500000%'::text)
-> Bitmap Index Scan on text_b (cost=0.00..190.43 rows=5000 width=0) (actual time=2.550..2.550 rows=0 loops=1)
Index Cond: ((content ~>=~ '1500000'::text) AND (content ~<~ '1500001'::text))
Planning Time: 6.247 ms
Execution Time: 6.809 ms
正确第一。您的谓词将找不到 'https://mywebsite/mina/':
content LIKE 'mina%'
其中一个可行:
content LIKE '%mina%'
content ~ 'mina'
但是 btree 索引都不支持。三字母索引可以做到这一点:
CREATE INDEX ON textfun USING gin (content gin_trgm_ops);
参见:
- PostgreSQL LIKE query performance variations
或者 text search index(在你的 URI 中分隔单词之后......)
但是 GIN 索引不能强制唯一性。您可能需要第二个 B 树索引。 (或暗示此类索引的约束)。
为了真正支持您原来的左锚定谓词,我将使用具有 COLLATE "C"
:
CREATE UNIQUE INDEX text_b ON textfun(content COLLATE "C");
Per-column collation support added with Postgres 9.1 largely obsoleted the old xxx_pattern_ops
operator classes。参见:
db<>fiddle here - COLLATE "C"
,行数更少(足以证明这一点)。
这里是 Postgres 中模式匹配选项的综合概述:
除此之外,只有三个不同值的测试用例不是很有用。当 Postgres 期望获取所有行的百分之几以上时,它通常根本不会使用任何索引,因为顺序扫描通常更快。它会知道一些“最常见的值”,因为它会按 ANALYZE
(或默认情况下 autovacuum
)更新统计信息。
在这方面搜索 content LIKE '1500000%'
是不同的,因为 Postgres 会知道它不常见并使用适用的索引 ...
索引优化取决于全貌:环境和要求...