SQL 性能优化:为什么少用函数在 WHERE 条件中?

在 SQL 性能优化的面试或实战场景中,经常会听到这样一句话:

"不要在 WHERE 条件里对列使用函数。"

那么,为什么会有这样的建议?今天我们就从执行原理出发,结合案例来理解这个问题。

一、问题引入

假设有一张用户表:

CREATE TABLE users (

id INT PRIMARY KEY,

name VARCHAR(50),

created_at DATETIME

);

-- 插入数据

INSERT INTO users VALUES

(1, 'Tom', '2023-01-10 09:30:00'),

(2, 'Alice', '2023-02-01 15:20:00'),

(3, 'Bob', '2023-03-05 11:20:00');

如果我们想查询 2023-02 之后注册的用户,很多人会写:

SELECT * FROM users

WHERE MONTH(created_at) >= 2;

这看似没问题,但性能却很差。

二、函数对索引的影响

SQL 的执行优化器依赖 索引 来加速查询。

如果在 WHERE 子句中直接对列使用函数,比如 MONTH(created_at),数据库必须逐行计算函数结果,然后再比较条件。这会导致 索引失效,最终变成全表扫描。

换句话说:

WHERE 列 = 值 → 可以用索引。

WHERE 函数(列) = 值 → 索引失效,性能骤降。

三、优化写法

正确的写法是:避免对列使用函数,而是把计算提前。

例如上面的查询,可以改成:

SELECT * FROM users

WHERE created_at >= '2023-02-01 00:00:00';

这样数据库能直接使用 created_at 的索引范围扫描,效率大大提升。

再比如想查名字长度为 3 的用户:

错误写法:

SELECT * FROM users

WHERE LENGTH(name) = 3;

优化写法:

SELECT * FROM users

WHERE name >= 'aaa' AND name < 'aaaa';

思路就是:把函数计算转移到常量上,而不是列上。

四、实际建议

  1. 避免函数包裹列

如 WHERE YEAR(date_col) = 2023 改写成 WHERE date_col BETWEEN '2023-01-01' AND '2023-12-31'。

  1. 善用范围条件

BETWEEN、>=、< 通常比函数截取更高效。

  1. 确认索引生效

使用 EXPLAIN 分析执行计划,确保 SQL 走索引而不是全表扫描。

  1. 在必要时使用函数索引

部分数据库(如 MySQL 8.0 的函数索引、Oracle 的函数索引)允许对函数结果建索引,但一般场景下还是推荐避免函数计算。

五、总结

在 WHERE 条件里使用函数,往往会导致 索引失效,查询性能下降。

优化思路是 提前计算常量,把函数逻辑转移到等号右边或用范围条件代替。

如果确实需要函数,可以考虑 函数索引,但这不是常规手段。

一句话总结:

SQL 优化的核心原则之一就是 让索引能被用到,而在 WHERE 子句里少用函数,就是为了保证这一点。

相关推荐
廿一夏5 小时前
MySql存储引擎与索引
数据库·sql·mysql
lzhdim7 小时前
SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题
数据库·sql
瀚高PG实验室7 小时前
瀚高企业版V9.1.1在pg_restore还原备份文件时提示extract函数语法问题
数据库·瀚高数据库
TDengine (老段)8 小时前
TDengine Tag 设计哲学与 Schema 变更机制
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
YOU OU9 小时前
Spring IoC&DI
java·数据库·spring
Muscleheng9 小时前
Navicat连接postgresql时出现‘datlastsysoid does not exist‘报错
数据库·postgresql
罗超驿10 小时前
18.事务的隔离性和隔离级别:MySQL面试高频考点全解析
数据库·mysql·面试
jran-10 小时前
Redis 命令
数据库·redis·缓存
小江的记录本11 小时前
【Java基础】Java 8-21新特性:JDK21 LTS:虚拟线程、模式匹配switch、结构化并发、序列集合(附《思维导图》+《面试高频考点清单》)
java·数据库·python·mysql·spring·面试·maven
June`11 小时前
多线程redis下如何解决aof重写和rdb持久化的数据一致性问题
数据库·redis·缓存