PostgreSQL Citext索引与较低的表达式索引性能

时间:2019-04-11 08:23:14

标签: postgresql query-performance database-indexes

我想决定在索引上使用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()上进行索引。

1 个答案:

答案 0 :(得分:2)

您的测试具有误导性。这里有两个问题:

  1. 创建索引ANALYZE后,您没有运行lowertextind

    否则,PostgreSQL不知道lower(a)的分布方式,可能会产生错误的成本估算。

  2. 通过使用SELECT *,您无意中允许将仅索引扫描用于第一个查询,而不能用于第二个查询。这是因为第一个索引包含所有表列,但第二个索引不包含。

    由于第二个索引不包含a,因此必须从表中获取该值,从而导致额外的工作。

    您可以使用SELECT count(*) FROM ...获得更公平的基准。