函数操作破坏B+树有序性致索引失效,MySQL 8.0+支持函数索引(如DATE(create_time)),但需确定性函数且调用完全一致;老版本可用生成列+普通索引替代。
函数操作直接破坏B+树的有序性
MySQL索引(尤其是InnoDB的B+树)依赖字段原始值的有序排列来快速定位数据。一旦在
子句中对索引列使用函数(如
、
、
),优化器就无法将查询条件映射到索引页中的键范围——因为索引里存的是
的完整时间戳,不是它的年份或日期部分;存的是
的原始大小写,不是全大写后的结果。此时优化器只能放弃索引,退化为全表扫描。
常见错误现象:
中
显示
,
为
,
接近表总行数。
不要写
不要写
不要写
MySQL 8.0+ 函数索引是唯一原生解法
MySQL 5.7及之前版本不支持函数索引,开发者只能靠改写SQL绕过(比如用范围代替
)。但MySQL 8.0.13起正式支持**函数索引(Functional Key)**,允许直接对表达式建索引。它不是“虚拟列+索引”的模拟,而是真正把计算结果作为索引键持久化存储,并参与B+树组织。
关键点:
必须用
生成列(MySQL会自动创建,无需手动声明)
索引定义中必须显式写出函数调用,且与查询中完全一致(包括大小写、括号、参数顺序)
仅适用于InnoDB引擎
示例:
之后这个查询就能命中索引:
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
函数索引的坑比想象中多
函数索引不是万能膏药,用错反而更慢或无效:
函数必须是**确定性(DETERMINISTIC)**的,像
、
、
这类非确定函数不允许用于函数索引
查询中函数调用必须和索引定义**字面完全一致**:写成
建的索引,不能匹配
(小写)或
函数索引不支持
左模糊,
仍会失效,哪怕你建了
索引
函数索引占用额外磁盘空间,且更新时需同步维护,高写入场景下可能增加IO压力
验证是否生效,仍要靠
看
字段是否显示你刚建的函数索引名。
替代方案:生成列 + 普通索引(兼容老版本)
如果你还在用MySQL 5.7或MariaDB,函数索引不可用,可退而求其次用**生成列(Generated Column)+ 普通索引**组合:
先添加生成列:
再对该列建索引:
最后改写查询:
(注意:不能再用
)
这种方式本质是把计算提前固化到表结构中,代价是增加一列存储、写入时多一次计算。但它稳定、可控、兼容性强,是生产环境最常落地的折中方案。
函数索引听着很美,但实际生效极其苛刻——大小写、空格、嵌套层级、函数确定性,漏掉任意一个细节,
里就还是
。别迷信“建了就能用”,每次上线前务必用真实数据+
实测。
WHEREDATE()UPPER()SUBSTRING()create_timenameEXPLAINtypeALLkeyNULLrowsWHERE DATE(create_time) = '2024-05-01'WHERE UPPER(name) = 'LUCY'WHERE SUBSTRING(phone, 1, 3) = '138'DATE()PERSISTENTALTER TABLE orders ADD KEY idx_create_date ((DATE(create_time)));
ALTER TABLE users ADD KEY idx_upper_name ((UPPER(username)));SELECT * FROM orders WHERE DATE(create_time) = '2024-05-01';
SELECT * FROM users WHERE UPPER(username) = 'LUCY';NOW()RAND()UUID()DATE(create_time)date(create_time)DATE(create_time + INTERVAL 0 DAY)LIKEWHERE name LIKE '%abc'(LOWER(name))EXPLAINkeyALTER TABLE orders ADD COLUMN create_date DATE AS (DATE(create_time)) STORED;CREATE INDEX idx_create_date ON orders(create_date);WHERE create_date = '2024-05-01'DATE(create_time)EXPLAINkey: NULLEXPLAIN