代码改变世界

LIKE比较查询优化

  abce  阅读(157)  评论(0编辑  收藏  举报

在执行检索时,有两种方式可以使用到索引:
1.单值查询,比如where id=2
2.范围查询,比如where id between 2 and 20、where id<20

当使用like来检索文本的开始位置,实际上是一种范围查找。事实上,下面的两个查询是等价的:

1
2
SELECT ... FROM ... WHERE name LIKE 'B%';
SELECT ... FROM ... WHERE name >= 'B' AND name < 'C';

使用like匹配文本开始位置通常是可以使用到索引的。

有时候,like处理匹配文本的开始,还包含其它匹配,比如:name like 'A%B%C',也会使用到索引。

在文本的中间使用like检索,是无法用到索引的。但我们可以继续想想是否做点什么从而优化查询。

 

1.是否可以从文本的开始进行匹配
在真是世界中,有很多这样的查询:like '%middle of text%'。而实际上,他们是可以改成like 'beginning%of%text%'的。
也许是开发人员没有深入的分析,也是他们压根就是错的。无论是哪种原因,都应该仔细考虑一下,是否做这种转换。

 

2.借助神奇的单字符_和%
_表示任意一个字符
%表示0个或任意多个字符
如果可能,使用一个_或任意个_来代替%,这会减少检索的字符的数量。比如:

1
2
SELECT ... FROM ... WHERE code LIKE '%x%';
SELECT ... FROM ... WHERE code LIKE '__x%';

假设code有20个字符。第一个SQL会检索所有的字符;第二个SQL只会检索三个字符。即使这两个SQL都不能使用上索引,第二个也会快一点,因为做的工作少。

 

3.合并检索
有时候,你需要在文本的中间做多种字符串检索,但是你是知道他们的出现顺序的。可以考虑看看是否可以合并成一个检索,加快查询:
来看下面的例子:

1
SELECT ... FROM ... WHERE code LIKE '%XX%' AND code LIKE '%YY%';

如果你知道,在文本种"XX"是不可能出现在"YY"后面的,你可以用这种方式优化查询:

1
SELECT ... FROM ... WHERE code LIKE '%XX%YY%';

这样,只有在XX出现后,才会匹配YY。

如果你知道在两个字符串之间有多少个字符,还可以更好的优化:

1
2
3
4
-- XX和YY之间只有3个字符:
SELECT ... FROM ... WHERE code LIKE '%XX__YY%';
-- XX和YY之间至少有3个字符:
SELECT ... FROM ... WHERE code LIKE '%XX__%YY%';

 

4.similar to语法
有些数据库,比如postgresql,支持similar to语法。比like更灵活,但没有regexp灵活。
有人可能会争论说similar to没用,但是我们会在这里使用它。当然你喜欢用regexp,也没人阻止你。
similar to有时候可用于结合两个like条件。看下面的例子:

1
2
SELECT ... FROM ... WHERE code LIKE '%XX%' OR code LIKE '%YY%';
SELECT ... FROM ... WHERE code LIKE '%(XX|YY)%';

 

5.标志位
有时我们使用LIKE来搜索包含某个标志的文本(可能是代码)。在这种情况下,我们通常需要查找少量可能的标志。这与基于用户输入任何内容的搜索非常不同。

如果重要标志的数量很少(为了给你一个数字,我说3个),你可以考虑创建布尔列,如果标志存在,则为TRUE,否则为FALSE。你可以使用生成列(generated columns)来确保布尔值的正确性:

1
2
3
4
ALTER TABLE table_name
    ADD COLUMN is_tkk BOOLEAN
    AS (product_code LIKE '%tkk%')
    STORED;

这个生成列的值在插入或更新的时候会被计算出来。

 

6.使用gin索引

1
CREATE INDEX idx_gin_code ON code USING gin (code);

 

7.使用逆序

从文本的尾部匹配
从文本的尾部匹配无法使用索引。但是有一种替换方式。
将文中的内容和like匹配的关键字都变得逆序。就变成了从文本头部匹配了。

1
2
3
SELECT ... FROM ... WHERE code LIKE '%abc';
-- will become:
SELECT ... FROM ... WHERE code_rev LIKE REVERSE('%abc');

可以在应用中将列的内容逆序,也可以借助生成列(generated column)

1
2
3
4
5
ALTER TABLE table_name
    ADD COLUMN code_rev VARCHAR(200)
        AS (REVERSE(code))
        STORED,
    ADD INDEX idx_code_rev (code_rev);

如果code列的值很长,我们需要考虑是否需要将所有值都逆序。也可以截取一部分,比如 REVERSE(LEFT(code, 10))

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2022-06-15 【PostgreSQL】PostgreSQL中的锁--轻量级的锁
2022-06-15 【PostgreSQL】PostgreSQL中的锁--表锁
2017-06-15 ORA-32004: obsolete or deprecated parameter(s) specified for RDBMS instance
2016-06-15 必须使用"角色管理工具"安装或配置microsoft.net framework 3.5
点击右上角即可分享
微信分享提示