对索引列使用函数会导致索引失效,因为b+树只存储原始值而非函数结果;如where date(create_time) = '2024-01-01'需逐行计算,无法利用索引有序性,优化器被迫全表扫描;应改用where create_time >= '2024-01-01' and create_time
对索引列使用函数会导致索引失效,根本原因不是数据库“不支持”,而是B+树索引压根没法匹配函数计算后的结果——它只存原始值,不存函数输出。
WHERE中调用DATE()、YEAR()等日期函数会绕过索引
比如
WHERE DATE(create_time) = '2024-01-01',数据库必须对每一行的create_time先执行DATE(),再比对,无法利用索引的有序结构定位。优化器看到的是“对索引列做了不可下推的运算”,只能退化为全表扫描。
- ✅ 正确改法:
WHERE create_time >= '2024-01-01' AND create_time (左闭右开,精度可控)- ❌ 避免
BETWEEN '2024-01-01' AND '2024-01-01 23:59:59':秒级精度易漏数据,且时间类型可能含微秒- ⚠️ PostgreSQL/Oracle虽支持
CREATE INDEX ON t(DATE(create_time)),但写入性能下降,别轻易建SUBSTR()、UPPER()等字符串函数破坏前缀匹配能力
WHERE SUBSTR(name, 1, 3) = 'adm'无法走name上的普通索引,因为B+树按完整字符串排序,函数截取后失去位置映射关系。
- ✅ 优先转为前缀匹配:
WHERE name LIKE 'adm%'(可走索引)- ✅ 大小写不敏感场景,建索引时指定校对规则更可靠,如MySQL的
utf8mb4_0900_as_cs- ⚠️ MySQL 5.7及以前不支持函数索引,
UPPER(name)查询只能靠冗余字段或应用层处理隐式转换本质也是“对索引列加了函数”
表面看没写函数,但
WHERE user_id = 123(user_id是VARCHAR)会让MySQL自动执行CAST(user_id AS SIGNED),等效于在索引列上套函数。
- ✅ 统一类型:
user_id是字符串就写'123',是数字就别加引号- ⚠️ MySQL有时对
id = '2'(id是INT)仍能走索引,这是兼容行为,PostgreSQL/Oracle直接报错或强制全表扫描- ? 自查方法:执行
EXPLAIN,看key是否为NULL,Extra是否出现Using where; Using index以外的内容真正容易被忽略的点是:函数索引(MySQL 8.0+、PostgreSQL)不是“万能解药”。它让查询变快,但每次
INSERT/UPDATE都要多算一次函数值并写入索引页——高写入场景下,这个代价可能远超读取收益。












