视图中like '%abc%'无法优化,因其下推至基表后因前置通配符导致b-tree索引失效,强制全表扫描;各数据库需分别采用fulltext、pg_trgm+gin或全文目录等替代方案。

因为视图本身不存数据,LIKE '%abc' 这类写法会直接下推到基表执行,而前置通配符让数据库无法使用 B-Tree 索引,强制全表扫描——视图里嵌套了 JOIN 或聚合时,这个代价会被放大数倍。
视图中 LIKE 为什么比普通表更难优化
视图只是封装好的 SELECT 定义,执行时所有条件(包括 WHERE col LIKE '%xxx%')都会被重写并下推到底层表。这意味着:
- 即使你在视图定义里加了索引提示或改写逻辑,只要基表字段上没对应索引,EXPLAIN 依然显示
type: ALL、rows接近总行数 - MySQL 视图不支持在定义中建
FULLTEXT索引,MATCH ... AGAINST必须写在外层查询里,不能藏在视图中 - PostgreSQL 视图若引用多个表,
pg_trgm索引只对单列生效;联合字段(如title || ' ' || content)必须先建表达式索引,并在视图中显式引用该表达式,否则索引不触发 - SQL Server 视图建全文索引有硬限制:不能含
GROUP BY、聚合函数或子查询,否则报错Msg 156, Level 15, State 1, Line 1 Incorrect syntax near the keyword 'FULLTEXT'
LIKE '%abc%' 在不同数据库中的实际表现差异
同一句 col LIKE '%abc%',在不同系统里走的不是同一条路:
- MySQL:默认完全无法索引,除非启用
ngram插件 +FULLTEXT,且查询必须改写为MATCH(col) AGAINST('abc' IN NATURAL LANGUAGE MODE),不能保留LIKE - PostgreSQL:原生不支持,但启用
pg_trgm扩展后,配合GIN索引可让ILIKE '%abc%'走索引扫描(EXPLAIN显示Index Scan using idx_col_gin),前提是字段未被函数包裹(如不用UPPER(col)) - SQL Server:可用
CONTAINS或FREETEXT替代,但要求基表已配置全文目录,且视图定义不能破坏全文索引绑定路径
最容易被忽略的三个失效点
很多性能问题不是出在语法,而是这些隐性细节:
-
UPPER(col) LIKE UPPER('%abc%')—— 函数包裹会让任何索引失效,包括pg_trgm和FULLTEXT;应统一存储规范格式,或用ILIKE(PostgreSQL)、CASE INSENSITIVEcollation(MySQL)替代 - 视图字段用了别名,比如
SELECT name AS user_name FROM users,然后外层查WHERE user_name LIKE '%张%'—— PostgreSQL 中这会导致pg_trgm索引无法下推,必须查原始列名name - 中文字段的 collation 不一致:比如字段是
utf8mb4_unicode_ci,但连接用的是utf8mb4_bin,隐式转换会让索引失效;需确保客户端、连接、字段三者字符集与校对规则统一
真正卡顿的往往不是某条 SQL 写错了,而是没意识到视图里的 LIKE 本质是把模糊逻辑“裸奔”扔给了基表——而基表是否准备好应对这种模式,决定了整条链路的响应时间是毫秒还是秒级。











