我在此列上有表Users
,其中包含displayName (text)
列和pg_trgm gin index
列。
CREATE INDEX "Users-displayName-pg-trgm-index"
ON "Users"
USING gin
("displayName" COLLATE pg_catalog."default" gin_trgm_ops);
这是我的问题:
SELECT "User"."id"
,"User"."displayName"
,"User"."firstName"
,"User"."lastName"
,"User"."email"
,"User"."password"
,"User"."isVerified"
,"User"."isBlocked"
,"User"."verificationToken"
,"User"."birthDate"
,"User"."gender"
,"User"."isPrivate"
,"User"."role"
,"User"."coverImageUrl"
,"User"."profileImageUrl"
,"User"."facebookId"
,"User"."deviceType"
,"User"."deviceToken"
,"User"."coins"
,"User"."LocaleId"
,"User"."createdAt"
,"User"."updatedAt"
FROM "Users" AS "User"
WHERE (similarity("User"."displayName", 'John') > 0.2)
ORDER BY similarity("User"."displayName", 'John')
,"User"."id" ASC LIMIT 25;
上面的查询需要~200ms
才能返回结果。当我删除
ORDER BY similarity("User"."displayName", 'John')
并按id
排序,然后查询速度最高为30ms
。
我在50k
个用户的桌面上查询。
以下是解释分析:http://explain.depesz.com/s/lXC
出于某种原因,我没有看到任何索引使用情况(gin pg_trgm
上的displayName
)
似乎当我更换行
WHERE (similarity("User"."displayName", 'John') > 0.2)
与
WHERE ("User"."displayName" % 'John')
查询速度超快 - 有谁能告诉我原因?我认为%
运算符只检查相似度(...)是否大于阈值...那么有什么区别?
答案 0 :(得分:4)
PostgreSQL不使用索引作为函数,它仅为运算符使用索引。
按equality()排序的查询会调用每行的函数,然后对行进行排序。
使用%
的查询使用索引并对匹配的函数运行相似性函数(没有索引仅扫描函数)。
如果您想按相似度(如问题中)排序相似度大于0.2的相似度,则应使用distance operator <->
。
像这样:
WHERE "User"."displayName" <-> 'John' < 0.8
ORDER BY "User"."displayName" <-> 'John' DESC
距离是1-相似性因此0.8
答案 1 :(得分:1)
我无法在Jakub Kania的答案中添加评论。我想以下查询:
WHERE "User"."displayName" <-> 'John' < 0.8
ORDER BY "User"."displayName" <-> 'John' DESC
索引也不会被使用。
您可以使用以下查询:
SELECT set_limit(0.2);
...
WHERE "User"."displayName" % 'John'
ORDER BY "User"."displayName" <-> 'John' DESC
答案 2 :(得分:0)
根据我的经验,GIST索引在相似性排序方面的效果更好/更快。
在这个例子中,我的客户表有大约500k行。
select *,similarity(coalesce(details::text,'') || coalesce(name,''),'9')
from customer
order by (coalesce(details::text,'') || coalesce(name,'')) <-> '9'
asc limit 50;
没有任何索引查询需要大约8,5s的查询计划:
QUERY PLAN
-----------------------------------------------------------------------------------
Limit (cost=47687.03..47687.16 rows=50 width=1144)
-> Sort (cost=47687.03..49184.52 rows=598995 width=1144)
Sort Key: (((COALESCE((details)::text, ''::text) ||
(COALESCE(name, ''::character varying))::text) <-> '9'::text))
-> Seq Scan on customer (cost=0.00..27788.85 rows=598995 width=1144)
(4 rows)
添加GIN索引时:
CREATE INDEX ON customer USING gin ((coalesce(details::text,'') || coalesce(name,'')) gin_trgm_ops);
什么都没发生。查询计划看起来仍然相同,查询仍需要大约8.5秒才能完成。没有索引用于订购。
创建GIST索引后:
CREATE INDEX ON customer USING gist ((coalesce(details::text,'') || coalesce(name,'')) gist_trgm_ops);
查询大约需要240毫秒,查询计划会显示正在使用的索引
QUERY PLAN
--------------------------------------------------------------------------
Limit (cost=0.42..10.19 rows=50 width=1144)
-> Index Scan using customer_expr_idx1 on customer (cost=0.42..117106.73 rows=598995 width=1144)
Order By: ((COALESCE((details)::text, ''::text) ||
(COALESCE(name, ''::character varying))::text) <-> '9'::text)
(3 rows)
为了好奇,返回的行看起来像这样:
id | name | details | similarity
--------+--------------------------+------------------------+------------
25 | Generic Company (9) Inc. | | 0.0909091
125 | Generic Company (9) Inc. | | 0.0909091
268649 | 9bg1ubTCYo7mMcDaHmCC | { "fatty": "McDaddy" } | 0.0294118
470217 | 9hSXtDmW9cXvKk4Q6McD | { "fatty": "McDaddy" } | 0.0285714
180775 | 9pRPi1w9nqV9999g2ceo | { "fatty": "McDaddy" } | 0.0285714
162931 | 9qMyYbWNJLZdv7uYYbOl | { "fatty": "McDaddy" } | 0.0285714
176961 | 9ow1NcTjAmCDyRsapDl4 | { "fatty": "McDaddy" } | 0.0285714
... etc ...