在SQLite里做模糊查询,绝大多数人第一反应是用LIKE,但翻阅官方文档时会发现还有一个GLOB运算符,功能看起来十分相似。如果只是简单地把它们当成同一个东西混用,很容易在大小写敏感、通配符语法和索引利用上踩坑。本文将从匹配规则、大小写处理、通配符语法、索引与性能等角度,系统对比这两个运算符,并给出实际SQL示例和选择建议。

一、基本语法与匹配规则差异
先从最基础的语法说起。LIKE是SQL标准中的模糊匹配运算符,SQLite完整实现了它;GLOB则是SQLite特有的运算符,语法风格来源于Unix文件名通配匹配。两者的基本用法都是表达式 匹配模式的形式,返回布尔结果,可以用在WHERE子句、CASE表达式等任何允许布尔表达式的地方。
看下面的对比示例:
-- 创建测试表并插入数据
CREATE TABLE users (name TEXT);
INSERT INTO users (name) VALUES ('apple'), ('Apple'), ('banana'), ('Banana'), ('applepie');
-- LIKE 查询:不区分大小写
SELECT * FROM users WHERE name LIKE 'a%';
-- 结果:apple, Apple, applepie
-- GLOB 查询:区分大小写
SELECT * FROM users WHERE name GLOB 'a*';
-- 结果:apple, applepie(Apple 被排除)从结果可以直观看出,同一个模式串,两个运算符返回的数据集不同。这是两者最容易被忽视、也最容易引发线上问题的差异点。假如你在做用户名校验或者文件名匹配,用错了运算符,就可能查出本不该出现的数据。
二、通配符体系:百分号下划线 vs 星号问号
LIKE和GLOB使用完全不同的通配符。LIKE用百分号%匹配零个或多个任意字符,用下划线_匹配恰好一个字符;GLOB用星号*匹配零个或多个任意字符,用问号?匹配恰好一个字符。对应关系可以用一张表说明:
| 匹配含义 | LIKE通配符 | GLOB通配符 |
|---|---|---|
| 匹配任意长度字符串(含空) | % | * |
| 匹配单个任意字符 | _ | ? |
| 字符集合匹配 | 不支持 | 支持 [abc]、[a-z] |
GLOB额外支持方括号字符集语法,这一点非常实用。比如要匹配所有以数字开头的字符串,用GLOB可以这样写:
-- 匹配以数字开头的名称 SELECT * FROM users WHERE name GLOB '[0-9]*'; -- 匹配第二个字符为元音字母的名称(区分大小写) SELECT * FROM users WHERE name GLOB '?[aeiou]*'; -- LIKE 没有字符集语法,只能拆成多个 OR 条件,可读性差很多 SELECT * FROM users WHERE name LIKE '_a%' OR name LIKE '_e%' OR name LIKE '_i%';
另外要提醒一点:GLOB只支持Shell风格的通配符,不支持正则表达式的量词语法,不要把它和REGEXP运算符混为一谈。如果需要真正的正则匹配,得通过注册自定义函数的方式实现REGEXP。
三、大小写敏感与转义处理
大小写处理是两者最重要的分水岭。LIKE对ASCII字母默认不区分大小写,也就是说'apple' LIKE 'APPLE'返回真。这个行为遵循SQL标准,且仅针对ASCII字符有效,Unicode字符依然区分大小写。GLOB则始终严格区分大小写,没有任何开关可以改变这一行为。
LIKE还支持ESCAPE子句来转义通配符本身。比如要查找字面意义上包含百分号的字符串,可以这样处理:
-- 插入包含特殊字符的数据
INSERT INTO users (name) VALUES ('100%纯果汁');
-- 不加转义时,% 会被当成通配符,用 ESCAPE 指定转义符
SELECT * FROM users WHERE name LIKE '%100!%%' ESCAPE '!';
-- 模式中的 !% 表示字面的百分号
-- GLOB 中匹配字面的方括号,需要把 [ 放进字符集
SELECT * FROM users WHERE name GLOB '*[[]*';
-- 这里用 [[] 匹配字面的左方括号如果业务场景要求LIKE也区分大小写,一个常见变通办法是执行PRAGMA case_sensitive_like = ON。这个PRAGMA可以把LIKE改成区分大小写的模式,但要注意它是连接级别的全局设置,修改后影响该连接上的所有LIKE查询,使用时需谨慎评估影响范围,用完记得关闭。
四、索引利用与性能表现
很多人关心哪个更快,答案取决于模式串的形态。SQLite对LIKE有一个优化:当模式串以非通配符开头,例如LIKE 'abc%',且字段建立了索引,查询可以走索引快速定位。但如果模式串以通配符开头,例如LIKE '%abc',索引就无能为力,只能全表扫描。
GLOB的情况略有不同。因为GLOB天然区分大小写,无需依赖PRAGMA状态,只要模式串以字面字符开头(如GLOB 'abc*'),且字段上有索引,SQLite就能直接走索引范围扫描。这意味着在大小写敏感的匹配场景下,GLOB的索引利用比LIKE更稳定、更可预测。
-- 建立索引以便利用前缀匹配优化 CREATE INDEX idx_users_name ON users(name); -- 以下写法可以走索引 SELECT * FROM users WHERE name LIKE 'app%'; SELECT * FROM users WHERE name GLOB 'app*'; -- 以下写法无法走索引,只能全表扫描 SELECT * FROM users WHERE name LIKE '%app'; SELECT * FROM users WHERE name GLOB '*app'; -- 验证执行计划,走索引会看到 SEARCH 而不是 SCAN EXPLAIN QUERY PLAN SELECT * FROM users WHERE name GLOB 'app*';
对于大表来说,把通配符放在模式串尾部是提升模糊查询性能最简单有效的手段。如果业务确实需要中间匹配,可以考虑配合FTS5全文索引或者把数据冗余一份反向字段来优化。
五、如何选择:实践建议
总结一下选择思路。如果需求是大小写不敏感的普通文本搜索,比如站内关键词搜索、标签匹配,LIKE是标准做法,生态兼容性好,迁移到其他数据库时SQL基本不用改。如果需求是大小写敏感的匹配,尤其是文件名、路径、代码标识符这类天然区分大小写的数据,GLOB更合适,语义准确且索引利用稳定。
还有几个细节值得注意:第一,GLOB是SQLite专属的,如果项目未来可能切换到MySQL或PostgreSQL,尽量避免依赖GLOB;第二,需要字符集匹配能力时,GLOB的方括号语法比LIKE的多个OR条件简洁得多;第三,无论用哪个,都要警惕用户输入中混入通配符导致的全表扫描问题,必要时在应用层先过滤掉%、_、*、?这些特殊字符,或者用ESCAPE子句做转义处理。
理解了这些差异,你在写模糊查询时就能根据数据特征和业务语义选对运算符,既保证结果准确,又不牺牲查询性能。