深入解析MySQL执行计划中最关键的指标之一,助你快速定位索引优化点,提升查询性能!
在MySQL执行计划中,key_len表示查询实际使用索引的字节长度。这个指标是索引优化的核心,它能揭示:
key_len = 数据类型基础长度 + NULL标记(1字节) + 变长类型额外开销(2字节)
| 数据类型 | 基础长度 | NULL开销 | VARCHAR开销 | NOT NULL示例 | NULL示例 |
|---|---|---|---|---|---|
| INT | 4字节 | +1字节 | - | 4 |
5 |
| BIGINT | 8字节 | +1字节 | - | 8 |
9 |
| TINYINT | 1字节 | +1字节 | - | 1 |
2 |
| FLOAT | 4字节 | +1字节 | - | 4 |
5 |
| DOUBLE | 8字节 | +1字节 | - | 8 |
9 |
| DATE | 3字节 | +1字节 | - | 3 |
4 |
| DATETIME | 8字节 | +1字节 | - | 8 |
9 |
| TIMESTAMP | 4字节 | +1字节 | - | 4 |
5 |
| CHAR(10) | 10×字符集字节 | +1字节 | - | 40 (utf8mb4) |
41 (utf8mb4) |
| VARCHAR(50) | 50×字符集字节 | +1字节 | +2字节 | 202 (utf8mb4) |
203 (utf8mb4) |
核心要点:
- VARCHAR类型在索引中固定增加2字节长度前缀
(实际行存储时规则不一致:≤255字符+1字节,>255字符+2字节)- 字符集直接影响长度:utf8mb4=4字节/字符,latin1=1字节/字符
- NULL列增加1字节开销
-- 表结构
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL, -- key_len:50×4+2=202
age TINYINT NOT NULL, -- key_len:1
email VARCHAR(100) NOT NULL, -- key_len:100×4+2=402
INDEX idx_profile (name, age, email)
) CHARSET=utf8mb4;
-- 场景1:仅使用name列
EXPLAIN SELECT * FROM users WHERE name = 'John';
-- key_len = 202(复合索引第一列)
-- 场景2:使用前两列
EXPLAIN SELECT * FROM users WHERE name = 'John' AND age = 30;
-- key_len = 203(202+1)
-- 场景3:使用所有列
EXPLAIN SELECT * FROM users WHERE name = 'John' AND age = 30 AND email = 'john@example.com';
-- key_len = 605(202+1+402)
-- latin1字符集对比
CREATE TABLE logs_latin1 (
message VARCHAR(100) NOT NULL
) CHARSET=latin1;
CREATE TABLE logs_utf8mb4 (
message VARCHAR(100) NOT NULL
) CHARSET=utf8mb4;
EXPLAIN SELECT * FROM logs_latin1 WHERE message = 'error';
-- key_len = 102 (100×1 + 2)
EXPLAIN SELECT * FROM logs_utf8mb4 WHERE message = 'error';
-- key_len = 402 (100×4 + 2)
-- 允许NULL的列
ALTER TABLE users MODIFY age TINYINT NULL;
-- 相同查询条件
EXPLAIN SELECT * FROM users WHERE name = 'John' AND age = 30;
-- key_len = 204(202+1+1,比非NULL多1字节)
当key_len
-- 1. 补充缺失查询条件
SELECT ... WHERE col1=1 AND col2=2 AND col3=3
-- 2. 重建索引(高频查询列前置)
ALTER TABLE orders DROP INDEX idx_old;
ALTER TABLE orders ADD INDEX idx_new (status, user_id, created_at);
-- 3. 使用覆盖索引
SELECT indexed_columns FROM table WHERE ...
-- 方案1:前缀索引(减少长度)
ALTER TABLE products ADD INDEX (description(20));
-- key_len从402降为82(VARCHAR(100)→20×4+2)
-- 优化前(允许NULL)
ALTER TABLE users MODIFY phone VARCHAR(20) NULL;
-- key_len=20×4+2+1=83
-- 优化后(禁止NULL)
ALTER TABLE users
MODIFY phone VARCHAR(20) NOT NULL DEFAULT '';
-- key_len=82(节省1字节/行)
EXPLAIN FORMAT=JSON
SELECT * FROM users WHERE name='Lisa';
/* 输出片段 */
{
"query_block": {
"table": {
"key_length": 202,
"used_key_parts": ["name"],
// ...其他信息
}
}
}
终极技巧:当发现key_len显著小于索引长度时,立即检查:
- 是否缺少必要查询条件?
- 索引列顺序是否合理?
- 是否存在数据类型转换?
- 字符集选择是否合适?
登录查看全部
参与评论
手机查看
返回顶部