🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
> 关于gsql在模糊查询中执行过程中不走索引的问题,可以通过 pg_trgm+gin索引来实现。 > pg_trgm扩展是用于字符串的相似度匹配的,在一些情况下也可以拿来代替全文检索做字符匹配,因此需要配合gin索引类型(倒排索引)一起使用。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;关于pgsql在模糊查询中执行过程中不走索引的问题,一开始以为命中数据量越大会导致不走索引,后来分析了这个扩展的原理之后发现,是否走索引是根据提供的搜索字符串个数有关。<br> **前置条件:** 1. 安装pg_trgm扩展 2. 对需要模糊搜索的字段创建倒排索引 ``` // 查看已安装的扩展 postgres=# select * from pg_extension; oid | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition -------+----------------+----------+--------------+----------------+------------+-----------+-------------- 13566 | plpgsql | 10 | 11 | f | 1.0 | | 16439 | first_last_agg | 10 | 2200 | t | 0.1.4 | | 16446 | pg_trgm | 10 | 2200 | t | 1.5 | | (3 rows) // 对event_desc 字段创建gin类型索引 postgres=# CREATE INDEX index_attack_alarm_event_desc ON "public"."alerts" USING gin (event_desc gin_trgm_ops); CREATE INDEX postgres=# select * from pg_indexes where tablename='alerts' and indexname='index_attack_alarm_event_desc'; schemaname | tablename | indexname | tablespace | indexdef ------------+-----------+-------------------------------+------------+------------------------------------------------------------------------------------------------- public | alerts | index_attack_alarm_event_desc | | CREATE INDEX index_attack_alarm_event_desc ON public.alerts USING gin (event_desc gin_trgm_ops) (1 row) ``` **pg_trgm扩展实现原理:** 1. 将字符串的前端添加2个空格,末尾添加1个空格 2. 每连续的3个字符标记为一个TOKEN 3. 对TOKEN建立GIN倒排索引 ``` // 比如 字符串 'abc',会在前后添加前后两个空格之后,连续3个字符拆分标记为TOKEN,并建立倒排索引 postgres=# select show_trgm('abc'); show_trgm ------------------------- {" a"," ab",abc,"bc "} (1 row) ``` **根据实现原理分析pg\_trgm扩展的使用场景:** 1. 有前缀的模糊查询,例如a%,**至少需要提供1个字符**。(搜索的是token \='a') 2. 有后缀的模糊查询,例如%ab,**至少需要提供2个字符**。(搜索的是token ='ab') 3. 前后模糊查询,例如%abcd%,**至少需要提供3个字符**。(这个使用数组搜索,搜索的是token包含了{“a”,“ab”,abc,bcd,“cd”}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;也就是说,前缀模糊,至少需要输入一个字符才能走索引;后缀模糊至少需要两个字符才能走索引,而全模糊查询,至少需要三个字符才能走索引。<br> **验证分析:** **场景1:** 前缀模糊查询,匹配一个字符,命中30w+数据,结果会经过索引 ![](https://img.kancloud.cn/a5/1f/a51f6113ae0c899c532a43ac8b006d0c_1002x462.png) **场景2:** 后缀模糊,仅匹配一个字符不会走索引,跟命中数据量无关,需要两个字符串以上才会 ![](https://img.kancloud.cn/61/8e/618eded149d0f9a047cfd694bdc6588b_963x382.png) **场景3:** 全模糊,匹配两个字符不会走索引,跟命中数据量无关,需要三个字符串以上才会 ![](https://img.kancloud.cn/a4/1d/a41dff157c5f3d6055c80ebf930499df_988x360.png)<br> **在全模糊情况下,bree索引和gin索引的语句耗时对比如下:** 1、 event\_desc字段创建btree索引,全模糊搜索三个字符没有走索引,语句耗时2.6s,命中40w+ ![](https://img.kancloud.cn/e7/0b/e70b9ec7adf646efbbeb9b29ddc0df3a_1334x769.png) 2、使用pg_trgm和gin索引,全模糊搜索三个字符会走索引,语句耗时2.4s,命中40w+ ![](https://img.kancloud.cn/2b/07/2b07da1fee30ce1e104d6e946a1f99ce_1323x771.png)<br> **pg_trgm扩展测试结论:** 1. 对应的字段需要使用gin索引类型(倒排索引),创建此耗时比btree索引长约10倍(980w数据重建索引,数据越大耗时越长),对数据实时插入表的性能影响未知 2. 此扩展的使用场景,后缀模糊需要输入两个字符串以上,全模糊需要输入三个字符串以上,才会走索引。可能不满足真实业务场景(真实业务场景可能是:全模糊搜索两个字符就走索引) 3. 在聚合场景,命中40w+数据情况下,虽然有走索引,但是对比btree索引查询耗时未明显下降,效果不明显