【问题标题】:postgresql not using trigram index on text column but uses it on varchar columnpostgresql 不在 text 列上使用 trigram 索引,但在 varchar 列上使用它
【发布时间】:2014-10-12 19:59:07
【问题描述】:

所以基本上我设置了一个非常简单的测试表来测试 postgresql 9.1(库存 Debian 稳定版)中的三元组和全文索引功能。

这里是表和索引的定义:

-- Table: fulltextproba
-- DROP TABLE fulltextproba;
CREATE TABLE fulltextproba
(
  id integer NOT NULL,
  text text,
  varchar600 character varying(600) COLLATE pg_catalog."C.UTF-8",
  CONSTRAINT id PRIMARY KEY (id )
)
WITH (
  OIDS=FALSE
);

-- Index: id_index
-- DROP INDEX id_index;
CREATE UNIQUE INDEX id_index
  ON fulltextproba
  USING btree
  (id );

-- Index: text_gin_fulltext_hun
-- DROP INDEX text_gin_fulltext_hun;
CREATE INDEX text_gin_fulltext_hun
  ON fulltextproba
  USING gin
  (to_tsvector('hungarian'::text, text) );

-- Index: text_gin_trgm
-- DROP INDEX text_gin_trgm;
CREATE INDEX text_gin_trgm
  ON fulltextproba
  USING gin
  (text COLLATE pg_catalog."C.UTF-8" gin_trgm_ops);

-- Index: varchar600
-- DROP INDEX varchar600;
CREATE INDEX varchar600
  ON fulltextproba
  USING btree
  (varchar600 COLLATE pg_catalog."C.UTF-8" varchar_pattern_ops);

-- Index: varchar600_gin_trgm
-- DROP INDEX varchar600_gin_trgm;
CREATE INDEX varchar600_gin_trgm
  ON fulltextproba
  USING gin
  (varchar600 COLLATE pg_catalog."C.UTF-8" gin_trgm_ops);

我的问题是,如果我进行应该使用三元索引的%foo% 搜索,如果我在文本列上搜索,它不会:

SELECT COUNT(id) FROM public.fulltextproba WHERE text LIKE '%almáv%'
 count 
-------
   396
(1 row)

real    0m7.215s
user    0m0.020s
sys 0m0.004s
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Aggregate  (cost=657056.11..657056.12 rows=1 width=4)
   ->  Seq Scan on fulltextproba  (cost=0.00..657052.72 rows=1355 width=4)
         Filter: (text ~~ '%almáv%'::text)
(3 rows)

但是,如果我在 varchar600 列中搜索,它确实使用三元组索引,而且速度更快 - 不足为奇:

SELECT COUNT(id) FROM public.fulltextproba WHERE varchar600 LIKE '%almáv%'
 count 
-------
   373
(1 row)

real    0m0.184s
user    0m0.052s
sys 0m0.004s
                                         QUERY PLAN                                         
--------------------------------------------------------------------------------------------
 Aggregate  (cost=5283.11..5283.12 rows=1 width=4)
   ->  Bitmap Heap Scan on fulltextproba  (cost=62.50..5279.73 rows=1355 width=4)
         Recheck Cond: ((varchar600)::text ~~ '%almáv%'::text)
         ->  Bitmap Index Scan on varchar600_gin_trgm  (cost=0.00..62.16 rows=1355 width=0)
               Index Cond: ((varchar600)::text ~~ '%almáv%'::text)
(5 rows)

所以最终的问题是:

  • 为什么 postgres 不在文本列上使用三元组索引。
  • 如何使 postgres 使用索引?我应该以其他方式定义它吗?

【问题讨论】:

    标签: postgresql indexing trigram


    【解决方案1】:

    text 完全没问题。甚至是最好的选择,正如您在 EXPLAIN 输出中看到的那样:

    Index Cond: ((varchar600)::text ~~ '%almáv%'::text)
    

    排序规则不匹配

    直接原因可能是排序规则不匹配。您的表已定义:

    text text,   -- default collation is ???
    varchar600 character varying(600) COLLATE pg_catalog."C.UTF-8"
    

    虽然两个索引都使用COLLATE pg_catalog."C.UTF-8"。您的默认排序规则是什么?输出来自:

    SHOW LC_COLLATE;
    

    您可能正在混合不同的排序规则。重新测试:

    SELECT COUNT(id) FROM public.fulltextproba
    WHERE text COLLATE pg_catalog."C.UTF-8" LIKE '%almáv%'
    

    Read about collation support in Postgres.

    测试中的一般问题

    显然,您在任一列中都有不同的值。使用 相同 值重复测试。

    要强制 Postgres 使用索引,您可以(仅用于在会话中调试!):

    SET enable_seqscan = off;
    

    然后再试一次。详情:

    Postgres 9.4 中 GIN 索引的展望

    即将发布的 Postgres 9.4 对 GIN 索引进行了多项重大改进。特别是,它们将变得更小更快。

    【讨论】:

    • 谢谢你,你是对的!我的语言环境是hu_HU.UTF-8,通过指定排序规则,三元索引马上就开始使用了(我使用C.UTF-8的原因是该列包含多语言文本)。
    • 至于表的大小,你错了:表包含 14155098 (~14M) 行,所以索引扫描更快。
    • 另外一点:我知道每一列都有不同的值(varchar600 列被截断为 600 个字符;它只对大约 10% 的行很重要),所以我没有结果差异的问题。我不是在测试 postgres 是否传达准确或一致的结果(我假设,我可能错了:)),我正在尝试评估某些环境中一些基本查询的一般性能,以测试使用 postgres 的可行性。到目前为止,它的表现很好。 :)
    • 另外,更改 test 的默认排序规则使原始查询使用索引。设置排序规则需要两个小时... :-P 道德:明智地选择排序规则,并且提前
    • @P.Péter:我把命中的行数误认为是分析输出中的行数。删除了那部分。虽然仍然很困惑,为什么我们看到rows=1355,但从count() 得到的数字要小得多。我还在 Postgres 9.4 中添加了 GIN 索引的前景,您可能会喜欢。
    猜你喜欢
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多