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

Posted

技术标签:

【中文标题】PostgreSQL citext 索引与较低的表达式索引性能【英文标题】:PostgreSQL citext index vs lower expression index performance 【发布时间】:2019-04-11 08:23:13 【问题描述】:

我想决定是使用带有索引的citext 列还是使用带有lower() 索引的text 列。

我执行了一些基准测试。令我惊讶的是,使用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.Index 中使用 count(*) 后运行分析。索引扫描仍然继续使用 lower() 上的索引。

【问题讨论】:

我认为原因通常是“索引不能转换回小写值,所以它需要查看表”,但 SELECT lower(a) 也不会使用 Index Only。 【参考方案1】:

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

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

    否则,PostgreSQL 不知道lower(a) 是如何分布的,并且可能会产生错误的成本估算。

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

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

    您可以使用SELECT count(*) FROM ... 进行更公平的基准测试。

【讨论】:

以上是关于PostgreSQL citext 索引与较低的表达式索引性能的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql - 将 varchar 列的大小更改为较低的长度

PostgreSQL/JDBC - 如何准备调用带有参数 CITEXT (TEXT) 的函数?

更喜欢数组中的高索引号而不是较低的索引号

oracle如何定位效率较低的sql

比赛支架放置算法

如何在 PostgreSQL 中列出具有相应大小的表的所有索引?