mysql索引优化需要配合表结构吗_mysql整体设计说明

来源:这里教程网 时间:2026-02-28 20:51:24 作者:

索引优化必须基于表结构设计来展开

单独建索引却忽略字段类型、长度、是否允许 NULL、主键选择等,大概率会失效或拖慢写入。MySQL 的

EXPLAIN
显示
type=ALL
key=NULL
,往往不是索引没建,而是字段定义和索引不匹配。

VARCHAR(255)
上建前缀索引要小心:如果业务常查前 10 字符,
INDEX(col(10))
可行;但若
WHERE col = 'xxx'
是完整值匹配,而索引只截了前 5 位,就无法用上
联合索引顺序必须贴合查询条件顺序:
INDEX(a, b, c)
能加速
WHERE a=1 AND b=2
,但对
WHERE b=2 AND c=3
无效
TINYINT
ENUM
做状态字段时,如果经常
ORDER BY status DESC
,记得在索引里包含该字段并显式声明
DESC
(MySQL 8.0+ 支持)

NULL 值处理直接影响索引可用性

MySQL 中,含

NULL
的列在 B+ 树索引中会被特殊存储,导致部分场景下无法使用索引做范围扫描或排序。比如
status TINYINT NULL
,即使加了
INDEX(status)
WHERE status != 1
也可能走全表扫描——因为
NULL != 1
恒为 true,优化器不敢依赖索引过滤。

能用
NOT NULL
就别留空:除非业务语义明确需要“未知”,否则默认设
NOT NULL DEFAULT 0
查询中避免对可空字段用
!=
NOT IN
,改用
IS NOT NULL AND status != 1
显式排除
联合索引里尽量把可能为
NULL
的字段放后面,否则前导列一旦为
NULL
,整条索引路径就断了

字符集与排序规则影响索引比较逻辑

同一个

VARCHAR
字段,在
utf8mb4_general_ci
utf8mb4_0900_as_cs
下,索引的匹配行为完全不同。大小写敏感(
_cs
)或重音敏感(
_as
)会导致隐式转换,让索引失效。

查拼音首字母时,
WHERE name LIKE 'Z%'
_ci
排序下能走索引;但在
_cs
下若数据存的是小写
zhang
,就匹配不上
联表字段字符集不一致(如 A 表用
utf8mb4_unicode_ci
,B 表用
utf8mb4_general_ci
),即使都有索引,
JOIN
也可能放弃使用索引,转为 Block Nested-Loop
新建表统一用
utf8mb4_0900_as_cs
(MySQL 8.0+),避免旧排序规则的模糊匹配陷阱

大字段(TEXT/BLOB)和虚拟列对索引的限制

MySQL 不允许直接对

TEXT
BLOB
列建普通索引,也不支持在它们上面建函数索引(如
JSON_EXTRACT()
结果)。但可通过生成列(generated column)绕过。

想对 JSON 字段里的
$.user_id
建索引?先加生成列:
user_id INT AS (JSON_UNQUOTE(JSON_EXTRACT(data, '$.user_id'))) STORED
,再对
user_id
建索引
TEXT
字段需前缀索引时,长度不能超 3072 字节(InnoDB 页面限制),且前缀长度必须是字符数,不是字节数——
utf8mb4
下一个汉字占 4 字节,
INDEX(content(100))
实际最多覆盖 100 个字符,不是 100 字节
虚拟列(
STORED
)会占用磁盘空间,但能被索引和
EXPLAIN
正确识别;
VIRTUAL
列不存盘,但多数版本不支持对其建索引
实际调优时,最常被跳过的动作是:改完表结构后忘记
ANALYZE TABLE
更新统计信息。InnoDB 的索引选择严重依赖这些数据,旧统计可能导致优化器坚持走错路。

相关推荐