问题
该任务有可能使您的数据库服务器停止使用非平凡大小的表,因为只要您不能为其使用索引,它就是一个O(N²)问题。
在顺序扫描中,您必须检查两行的所有可能组合,即n * (n-1) / 2
组合 - Postgres 将运行n * n-1
测试,因为排除反向重复组合并不容易。如果您对第一场比赛感到满意,它会变得更便宜 - 多少取决于数据分布。对于许多匹配,Postgres 会提前找到一行匹配,并且可以跳过测试其余部分。对于少数匹配,无论如何都必须执行大多数检查。
无论哪种方式,性能都会随着表中的行数而迅速下降。EXPLAIN ANALYZE
使用表中的 10、100、1000 等行测试每个查询,以亲自查看。
解决方案
在- 最好是GIN上创建一个三元组索引。word
CREATE INDEX tbl_word_trgm_gin_idx ON tbl USING gin (word gin_trgm_ops);
细节:
到目前为止,两个答案中的查询都不会使用索引,即使你有它。使用可以实际使用此索引的查询:
列出所有匹配项(根据问题正文):
使用LATERAL CROSS JOIN
:
SELECT t2.word_id, t2.word, t1.word_id, t1.word
FROM tbl t1
, LATERAL (
SELECT word_id, word
FROM tbl
WHERE word_id <> t1.word_id
AND word like format('%%%s%%', t1.word)
) t2;
要获取任何匹配的行(根据您的标题):使用EXISTS
半联接:
SELECT t1.word_id, t1.word
FROM tbl t1
WHERE EXISTS (
SELECT 1
FROM tbl
WHERE word_id <> t1.word_id
AND word like format('%%%s%%', t1.word)
);