mysql优化WHERE子句条件的写法与性能提升

MySQL优化器自动重排WHERE条件顺序,真正影响性能的是索引设计、是否覆盖、ICP支持及避免对索引字段使用函数或运算。

mysql优化where子句条件的写法与性能提升

WHERE 条件顺序不影响 MySQL 执行计划

MySQL 优化器会自动重排 WHERE 子句中的条件顺序,按索引选择性、数据分布、成本估算重新决定执行路径。你写成 WHERE status = 'active' AND created_at > '2023-01-01' 还是反过来,对执行计划没有实质影响——除非你用的是非常老的 MySQL 5.5 且关闭了优化器(几乎不存在)。

真正起作用的是:字段是否在索引中、索引是否覆盖、条件是否能触发索引下推(ICP)、是否用了函数或表达式导致索引失效。

  • 不要手动把“过滤性强”的条件写前面来“优化”,这是过时经验
  • EXPLAINkeypossible_keys,而不是靠肉眼猜顺序
  • 如果发现 typeALLindex,说明没走有效索引,该看的是索引设计,不是 WHERE 写法

避免在 WHERE 字段上用函数或运算

对索引字段做函数调用(如 DATE(created_at))、类型转换(如 CAST(user_id AS CHAR))、数学运算(如 price * 1.1 > 100),会让 MySQL 无法使用该字段上的 B+ 树索引,只能全表扫描或索引全扫。

常见错误写法:

SELECT * FROM orders WHERE YEAR(created_at) = 2023;

正确替代方式:

  • 改用范围查询:created_at >= '2023-01-01' AND created_at
  • 如果必须按年查且高频,可加生成列 + 索引:ALTER TABLE orders ADD COLUMN year_created TINYINT GENERATED ALWAYS AS (YEAR(created_at)) STORED, ADD INDEX idx_year (year_created);
  • 避免 LIKE '%abc',它无法利用索引;LIKE 'abc%' 可以走索引前缀

IN 列表过大时注意性能拐点

WHERE id IN (1,2,3,...,2000) 看似简单,但当值超过几百个时,MySQL 会退化为多个等值查找合并,优化器可能放弃使用索引、改走全表扫描,尤其在旧版本(如 5.6)中更明显。

羚珑

羚珑

京东推出的一站式AI图像处理平台

下载

实操建议:

  • 单次 IN 值数控制在 200 以内,超量拆成多批次查询
  • 若来源是另一张表,优先用 JOIN 替代 IN (SELECT ...),后者容易触发临时表和文件排序
  • MySQL 8.0+ 支持 IN 子查询的物化优化,但仍有阈值,仍建议用 JOIN 更可控
  • 考虑用临时表承载大批量 ID:CREATE TEMPORARY TABLE tmp_ids(id BIGINT PRIMARY KEY); INSERT INTO tmp_ids VALUES (...); SELECT * FROM t JOIN tmp_ids USING(id);

NULL 判断要小心索引失效风险

WHERE col IS NULL 在有允许 NULL 的普通索引(非唯一索引)上通常可以走索引;但 WHERE col != 'x'WHERE col 'x' 会隐式包含 NULL,而 B+ 树索引不存储 NULL 值(除非是唯一索引的 NULL 特殊处理),这类查询往往触发全索引扫描甚至全表扫描。

典型陷阱:

SELECT * FROM users WHERE email != 'test@example.com'; -- 若 email 允许 NULL,此语句实际返回所有 email 不等于该值的行 + 所有 email IS NULL 的行

更安全写法:

  • 明确拆开:WHERE email != 'test@example.com' AND email IS NOT NULL
  • 如果业务上 email 不应为 NULL,就该设为 NOT NULL 并加约束,让优化器更敢用索引
  • 对可空字段建索引时,留意 EXPLAIN 中的 rows 是否异常高——可能正在扫描大量 NULL 项

最常被忽略的一点:复合索引中只要有一个字段允许 NULL,且查询条件跳过它(比如用 WHERE a = 1 AND c = 3,跳过 b),而 b 是可空字段,某些旧版本可能无法高效利用后续字段的索引下推。别只盯着 WHERE 怎么写,先确认表结构和索引定义是否干净。

https://www.php.cn/faq/1991738.html

发表回复

Your email address will not be published. Required fields are marked *