MySQL中IS NULL条件下函数索引未生效,求优雅解决方案
解决MySQL中
sent_at IS NULL查询慢的优雅方案 方案1:调整查询语句匹配函数索引
你之前创建的ISNULL(sent_at)函数索引本身有效,只是当前查询条件sent_at IS NULL未触发优化器调用该索引。只需将查询语句修改为匹配函数索引的形式:
SELECT COUNT(*) FROM users WHERE ISNULL(sent_at) = 1;
执行后用EXPLAIN查看,会发现优化器已选中index_users_sent_at_is_null索引,访问类型转为ref或range,避免全表扫描。
方案2:创建虚拟列并建立索引
若不想修改现有查询语句,可通过生成虚拟列让优化器自动关联条件:
- 添加存储型虚拟列(计算结果持久化,不额外消耗查询性能):
ALTER TABLE users ADD COLUMN sent_at_is_null TINYINT GENERATED ALWAYS AS (ISNULL(sent_at)) STORED;
- 给虚拟列建立索引:
CREATE INDEX idx_sent_at_is_null ON users(sent_at_is_null);
此时执行原查询SELECT COUNT(*) FROM users WHERE sent_at IS NULL;,优化器会自动将条件转换为sent_at_is_null = 1,从而使用该索引。虚拟列仅占用1字节存储,比全值datetime索引节省大量空间。
方案3:利用NULL值的索引特性(折中方案)
如果上述两种方式都不适用,可创建仅包含sent_at列的普通索引:
CREATE INDEX idx_sent_at_null ON users(sent_at);
虽然这是全值索引,但MySQL的索引会单独存储NULL值,查询sent_at IS NULL时,优化器会直接定位到索引中的NULL值区域,相比全表扫描效率提升明显。若表中NULL值占比很低,该索引的空间占用也不会过大。
内容的提问来源于stack exchange,提问作者Andrew France
相关产品推荐
相关产品推荐

