一直以来,对于搜索时模糊匹配的优化一直是个让人头疼的问题,好在强大pgsql提供了优化方案,下面就来简单谈一谈如何经过索引来优化模糊匹配 html
咱们有一张千万级数据的检查报告表,须要经过检查报告来模糊搜索某个条件,咱们先建立以下索引:正则表达式
CREATE INDEX lab_report_report_name_index ON lab_report USING btree (report_name);
而后搜个简单的模糊匹配条件如 LIKE "血常规%",能够发现查询计划生成以下,索引并无被使用上,这是由于传统的btree索引并不支持模糊匹配sql
查阅文档后发现,pgsql能够在Btree索引上指定操做符:text_pattern_ops、varchar_pattern_ops和 bpchar_pattern_ops,它们分别对应字段类型text、varchar和 char,官方解释为“它们与默认操做符类的区别是值的比较是严格按照字符进行而不是根据区域相关的排序规则。这使得这些操做符类适合于当一个数据库没有使用标准“C”区域时被使用在涉及模式匹配表达式(LIKE或POSIX正则表达式)的查询中。”, 有些抽象,咱们先试试看。建立以下索引并查询刚才的条件 LIKE"血常规%":(参考pgsql的文档 https://www.postgresql.org/docs/10/indexes-opclass.html)数据库
CREATE INDEX lab_report_report_name_index ON lab.lab_report (report_name varchar_pattern_ops);
发现确实能够走索引扫描 ,执行时间也从213ms优化到125ms,可是,若是搜索LIKE "%血常规%"就又会走全表扫描了! 这里咱们引入本篇博客的主角"pg_trgm"和"pg_bigm"。ide
建立这两个索引前分别须要引入以下两个扩展包 :post
CREATE EXTENSION pg_trgm; CREATE EXTENSION pg_bigm;
这两个索引的区别是:“pg_tigm”为pgsql官方提供的索引,"pg_tigm"为日本开发者提供。下面是详细的对比:(参考pg_bigm的文档 http://pgbigm.osdn.jp/pg_bigm_en-1-2.html)测试
The pg_trgm contrib module which provides full text search capability using 3-gram (trigram) model is included in PostgreSQL. The pg_bigm was developed based on the pg_trgm. They have the following differences:优化
Functionalities and Features | pg_trgm | pg_bigm |
---|---|---|
Phrase matching method for full text search | 3-gram | 2-gram |
Available index | GIN and GiST | GIN only |
Available text search operators | LIKE (~~), ILIKE (~~*), ~, ~* | LIKE only |
Full text search for non-alphabetic language (e.g., Japanese) |
Not supported (*1) | Supported |
Full text search with 1-2 characters keyword | Slow (*2) | Fast |
Similarity search | Supported | Supported (version 1.1 or later) |
Maximum indexed column size | 238,609,291 Bytes (~228MB) | 107,374,180 Bytes (~102MB) |
pg_bigm 1.1 or later can coexist with pg_trgm in the same database, but pg_bigm 1.0 cannot.ui
如无特殊要求推荐使用"pg_bigm",咱们测试一下效果:this
CREATE INDEX lab_report_report_name_index ON lab_report USING gin (report_name public.gin_bigm_ops);
能够使用位图索引扫描,对于本次案例,使用pg_trgm效果同pg_bigm。
以上
本文只是简单的介绍许多细节并未作深刻的分析,欢迎留言指教或者讨论