模糊查询分为以下几种情况:
右模糊查询(前缀匹配):LIKE '前缀%'
左模糊查询(后缀匹配):LIKE '%后缀'
全模糊查询(包含匹配):LIKE '关键字'
在右模糊查询时,因为前缀本身是有序的,通常右模糊查询是可以通过使用传统的Btree索引来提高查询效率的。但是在某些情况下,需要模糊查询的字段上即使创建了Btree索引,也无法使用到。
今天我们就来介绍两个右模糊查询时应该避免的坑。
字符串拼接时,要使用“||”而不是“concat”
有这么一种应用场景,我们需要把参数与%拼接后的字符串作为右模糊查询的条件。在PG中要实现字符串拼接就有两种方法,一是直接使用字符串连接运算符“||”来实现,另外一种是使用concat函数来实现:

从上图中的执行计划可以看出’你好’||’%’会被优化器化简为’你好%’,于是使用了info字段上的索引,而优化器认为concat(’你好’,’%’)是一个动态的表达式,而非一个确定的常量,于是右模糊查询就不能够使用到info字段上的索引。
数据库的lc_collate设置不当,会导致右模糊查询不能使用索引
PostgreSQL 的 lc_collate 用于指定数据库中字符串排序和比较规则,基于特定语言或地区的文化习惯,可以设置为例如“C”、“en_US.UTF8”、“zh_CN.UTF8”等值,其中"C"表示使用POSIX标准的"C"语言环境。
我们通过下面的例子来看一看lc_collate会对PostgreSQL的右模糊查询使用索引带来什么样的影响:
我们先创建三个数据库,分别指定其lc_collate为“C”、“en_US.UTF8”和“zh_CN.UTF8”:

我们通过一个demo来测试右模糊查询:创建一张表tb_test,包含字符串类型的info字段,往表中插入10万行随机数据,基于info字段创建btree索引,再执行对info字段的模糊查询。下面依次是三个数据库中的测试结果:
lc_collate=C的数据库:

lc_collate=en_US.UTF8的数据库:

lc_collate=zh_CN.UTF8的数据库:

通过上面的demo可以看出,在lc_collate不为C,右模糊查询无法使用字段上的Btree索引。并且在数据库创建后,lc_collate就无法更改,我们想要在lc_collate不为C的数据库中使用右模糊查询,并且要能够使用Btree索引加速查询,也可以通过以下两种方式实现:
字符串类型上创建Btree索引的opclass的默认值为text_ops,当lc_collate不为C时,默认的opclass不支持右模糊查询。我们可以创建索引时指定opclass为text_pattern_ops:

在创建索引时,指定索引的collate为C:

技术总结
要使用拼接后字符串来进行右模糊查询时,使用“||”操作符来拼接而不是concat函数。
如果数据库的lc_collate不为C,在需要做右模糊查询的字段上创建索引时,需要通过指定opclass为text_pattern_ops或者指定索引的collate为C。
最后,欢迎感兴趣的各位加入DB演武场交流群,在这里可以交流PostgreSQL、Linux、Kingbase、openGauss等各类技术知识,期待您的加入。





