Dav*_*Eyk 26 postgresql performance index pattern-matching postgresql-8.4
我可能在标题中问错了问题。以下是事实:
在我们基于 Django 的站点的管理界面上进行客户查询时,我的客户服务人员一直抱怨响应速度慢。
我们使用的是 Postgres 8.4.6。我开始记录慢查询,并发现了这个罪魁祸首:
SELECT COUNT(*) FROM "auth_user" WHERE UPPER("auth_user"."email"::text) LIKE UPPER(E'%deyk%')
Run Code Online (Sandbox Code Playgroud)
此查询的运行时间超过 32 秒。下面是 EXPLAIN 提供的查询计划:
QUERY PLAN
Aggregate (cost=205171.71..205171.72 rows=1 width=0)
-> Seq Scan on auth_user (cost=0.00..205166.46 rows=2096 width=0)
Filter: (upper((email)::text) ~~ '%DEYK%'::text)
Run Code Online (Sandbox Code Playgroud)
因为这是 Django ORM 从 Django Admin 应用程序生成的 Django QuerySet 生成的查询,所以我无法控制查询本身。索引似乎是合乎逻辑的解决方案。我尝试创建一个索引来加快速度,但没有任何区别:
CREATE INDEX auth_user_email_upper ON auth_user USING btree (upper(email::text))
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?我怎样才能加快这个查询?
Erw*_*ter 31
不存在用于索引支持LIKE/ILIKE在PostgreSQL的8.4 -除了左锚定的搜索字词。
从PostgreSQL 9.1 开始,附加模块pg_trgm为支持LIKE/ILIKE或正则表达式(运算符~和朋友)的GIN 和 GiST 三元索引提供运算符类。每个数据库安装一次:
CREATE EXTENSION pg_trgm;
Run Code Online (Sandbox Code Playgroud)
示例 GIN 索引:
CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)
有关的:
Tom*_*omH 12
由于匹配开始时的“%”,该索引无济于事 - BTREE 索引只能匹配前缀,而查询开头的通配符意味着没有固定的前缀可供查找。
这就是为什么它会进行表扫描并依次将每条记录与查询字符串进行匹配。
您可能需要考虑使用全文索引和文本匹配运算符,而不是像您目前那样使用 LIKE 进行子字符串搜索。您可以在文档中找到有关全文搜索的更多信息:
http://www.postgresql.org/docs/8.4/static/textsearch-intro.html
事实上,我从那个页面注意到 LIKE 显然从不使用索引,这对我来说似乎很奇怪,因为它应该能够使用 BTREE 索引解析非通配符前缀。然而,一些快速测试表明文档可能是正确的,在这种情况下,当您使用 LIKE 解决查询时,没有多少索引会有所帮助。