PostgreSQL没有使用具有非强制功能的索引

时间:2017-04-08 08:40:06

标签: postgresql

我有下表:

CREATE TABLE products (
  id   bigserial NOT NULL PRIMARY KEY,
  name varchar(2048)
  -- Many other rows
);

我想在LIKE上对案例和变音符号不敏感name查询。

为此,我创建了以下功能:

CREATE EXTENSION IF NOT EXISTS unaccent;
CREATE OR REPLACE FUNCTION immutable_unaccent(varchar)
  RETURNS text AS $$
    SELECT unaccent($1)
  $$ LANGUAGE sql IMMUTABLE;

然后使用此函数在name上创建索引:

CREATE INDEX products_search_name_key ON products(immutable_unaccent(name));

然而,当我进行查询时,查询非常慢(300k行约2.5s)。我非常确定PostgreSQL没有使用索引

-- Slow (~2.5s for 300k rows)
SELECT products.* FROM products
    WHERE immutable_unaccent(products.name) LIKE immutable_unaccent('%Hello world%')

-- Fast (~60ms for 300k rows), and there is no index
SELECT products.* FROM products
    WHERE products.name LIKE '%Hello world%'

我尝试创建一个单独的列,其中包含一个case和变音符号不敏感的名称副本,就像这样,在这种情况下查询很快:

ALTER TABLE products ADD search_name varchar(2048);
UPDATE products
    SET search_name = immutable_unaccent(name);

-- Fast (~60ms for 300k rows), and there is no index
SELECT products.* FROM products
    WHERE products.search_name LIKE immutable_unaccent('%Hello world%')

我做错了什么?为什么我的索引方法不起作用?

编辑:慢查询的执行计划

explain analyze SELECT products.* FROM products
    WHERE immutable_unaccent(products.name) LIKE immutable_unaccent('%Hello world%')

Seq Scan on products  (cost=0.00..79568.32 rows=28 width=2020) (actual time=1896.131..1896.131 rows=0 loops=1)
  Filter: (immutable_unaccent(name) ~~ '%Hello world%'::text)
  Rows Removed by Filter: 277986
Planning time: 1.014 ms
Execution time: 1896.220 ms

1 个答案:

答案 0 :(得分:2)

如果你想要做一个像'%hello world%'类型查询,你必须找到另一种方法来索引它。

(您可能需要对几个contrib模块进行一些初始安装。为此,请以postgres admin / root用户身份登录并发出以下命令)

先决条件:

CREATE EXTENSION pg_trgm;
CREATE EXTENSION fuzzystrmatch;

尝试以下方法:

create index on products using gist (immutable_unaccent(name) gist_trgm_ops);

此时应该在您的查询中使用索引。

select * from product 
where immutable_unaccent(name) like '%Hello world%';

注意:这个索引可能会变大,但是有240个字符限制,可能不会那么大。

您也可以使用全文搜索,但这更复杂。

以上场景的作用是索引"三元组"名称,IE,每组" 3个字母"在名称中。因此,该产品被称为" hello world"它会索引hel,ell,llo,lo,wo,wor,orl和rld。 然后,它可以以更有效的方式对您的搜索词使用该索引。如果您愿意,可以使用gist或gin索引类型。

基本上 GIST查询速度稍慢,但更新速度更快。 GIN是相反的>