我有下表:
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
答案 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是相反的>