我想决定在索引上使用citext
列还是在text
上使用具有索引的lower()
列。
我进行了一些基准测试。令我惊讶的是,在lower()
上进行索引搜索会导致索引扫描,但是在citext
的情况下,我得到了仅索引扫描。我期望lower()
上的索引也导致仅扫描索引。
此外,使用citext
索引的总成本为4.44,但是使用lower()
索引的总成本为8.44。
所以我首先想到的是citext
列索引比text
列上的表达式索引要好。
CREATE TABLE test_citext(a citext NOT NULL);
INSERT INTO test_citext
SELECT cast(x as text)
FROM generate_series(1, 1000000) AS x;
VACUUM (FREEZE, ANALYZE) test_citext;
create index citextind on test_citext(a);
Select * from test_citext where a = 'test';
--Index Only Scan.Total cost 4.44
CREATE TABLE test_textlowerindex(a text NOT NULL);
INSERT INTO test_textlowerindex
SELECT cast(x as text)
FROM generate_series(1, 1000000) AS x;
VACUUM (FREEZE, ANALYZE) test_textlowerindex;
create index lowertextind on test_textlowerindex(lower(a));
Select * from test_textlowerindex where lower(a) = 'test';
--Index Scan.Total cost 8.44
我对吗?
Laurenz Albe先生,谢谢您的回答。正如您所说,我更改了上述脚本。 结果:
CREATE TABLE test_citext(a citext NOT NULL);
INSERT INTO test_citext
SELECT cast(x as text)
FROM generate_series(1, 1000000) AS x;
create index citextind on test_citext(a);
VACUUM (FREEZE, ANALYZE) test_citext;
Select count(*) from test_citext where a = 'test';
--Index Only Scan 4.44 + 4.46
CREATE TABLE test_textlowerindex(a text NOT NULL);
INSERT INTO test_textlowerindex
SELECT cast(x as text)
FROM generate_series(1, 1000000) AS x;
create index lowertextind on test_textlowerindex(lower(a));
VACUUM (FREEZE, ANALYZE) test_textlowerindex;
Select count(*) from test_textlowerindex where lower(a) = 'test';
--Index Scan 8.44 + 8.46
但是,即使我在创建索引并在select中使用count(*)之后运行分析,也没有任何改变。IndexScan仍会继续在Lower()上进行索引。
答案 0 :(得分:2)
您的测试具有误导性。这里有两个问题:
创建索引ANALYZE
后,您没有运行lowertextind
。
否则,PostgreSQL不知道lower(a)
的分布方式,可能会产生错误的成本估算。
通过使用SELECT *
,您无意中允许将仅索引扫描用于第一个查询,而不能用于第二个查询。这是因为第一个索引包含所有表列,但第二个索引不包含。
由于第二个索引不包含a
,因此必须从表中获取该值,从而导致额外的工作。
您可以使用SELECT count(*) FROM ...
获得更公平的基准。