-- 最基本的索引类型 CREATE INDEX idx_username ON users(username);
4. 联合索引 (Composite Index)
1 2 3 4 5 6 7 8 9 10 11
-- 多列组合索引,遵循最左前缀原则 CREATE INDEX idx_name_age_city ON users(name, age, city);
-- ✅ 能使用索引的查询 SELECT*FROM users WHERE name ='张三'; SELECT*FROM users WHERE name ='张三'AND age =25; SELECT*FROM users WHERE name ='张三'AND age =25AND city ='北京';
-- ❌ 无法使用索引的查询 SELECT*FROM users WHERE age =25; -- 跳过了name SELECT*FROM users WHERE city ='北京'; -- 跳过了name和age
5. 覆盖索引 (Covering Index)
1 2 3 4 5 6 7 8
-- 当查询的列都在索引中时,无需回表 CREATE INDEX idx_name_email ON users(name, email);
-- ✅ 覆盖索引,不需要回表 SELECT name, email FROM users WHERE name ='张三';
-- ❌ 需要回表获取其他列 SELECT*FROM users WHERE name ='张三';
🔧 EXPLAIN分析查询
1
EXPLAIN SELECT*FROM orders WHERE user_id =100AND status ='paid';
EXPLAIN关键字段解读
字段
说明
优化目标
type
访问类型
system > const > eq_ref > ref > range > index > ALL
key
实际使用的索引
应该使用预期的索引
rows
预估扫描行数
越小越好
Extra
额外信息
避免Using filesort, Using temporary
type类型详解
1 2 3 4 5 6 7 8 9 10 11
-- const: 主键或唯一索引的等值查询 EXPLAIN SELECT*FROM users WHERE id =1;
-- ref: 普通索引的等值查询 EXPLAIN SELECT*FROM users WHERE username ='admin';
-- range: 范围查询 EXPLAIN SELECT*FROM users WHERE age BETWEEN20AND30;
-- ALL: 全表扫描(需要优化!) EXPLAIN SELECT*FROM users WHERE age +1=25;
-- ❌ 索引过多会影响写入性能 CREATE INDEX idx_a ONtable(a); CREATE INDEX idx_b ONtable(b); CREATE INDEX idx_c ONtable(c); CREATE INDEX idx_ab ONtable(a, b); CREATE INDEX idx_bc ONtable(b, c);
-- ✅ 合理设计联合索引,一个索引覆盖多个查询场景 CREATE INDEX idx_abc ONtable(a, b, c);
4. 长字符串使用前缀索引
1 2 3 4 5 6 7 8 9
-- 对于长字符串,使用前缀索引节省空间 CREATE INDEX idx_email_prefix ON users(email(10));
-- 选择合适的前缀长度 SELECT COUNT(DISTINCTLEFT(email, 5)) /COUNT(*) AS len5, COUNT(DISTINCTLEFT(email, 10)) /COUNT(*) AS len10, COUNT(DISTINCTLEFT(email, 15)) /COUNT(*) AS len15 FROM users;
📊 实战案例:电商订单表优化
原始表结构
1 2 3 4 5 6 7 8 9 10
CREATE TABLE orders ( id BIGINTPRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL, user_id BIGINTNOT NULL, product_id BIGINTNOT NULL, amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULLDEFAULT0, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL );
常见查询场景分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
-- 场景1:根据订单号查询(高频,需要快速定位) SELECT*FROM orders WHERE order_no ='ORD202412010001'; -- 建议:唯一索引 CREATEUNIQUE INDEX idx_order_no ON orders(order_no);
-- 场景2:查询用户的订单列表(高频) SELECT*FROM orders WHERE user_id =100ORDERBY create_time DESC; -- 建议:联合索引 CREATE INDEX idx_user_time ON orders(user_id, create_time DESC);
-- 场景3:后台查询某状态的订单(中频) SELECT*FROM orders WHERE status =1AND create_time >'2024-12-01'; -- 建议:联合索引 CREATE INDEX idx_status_time ON orders(status, create_time);
-- 场景4:统计某商品的销售额 SELECTSUM(amount) FROM orders WHERE product_id =500AND status =2; -- 建议:联合索引 + 覆盖索引 CREATE INDEX idx_product_status_amount ON orders(product_id, status, amount);
最终索引设计
1 2 3 4 5
-- 精简后的索引方案 CREATEUNIQUE INDEX idx_order_no ON orders(order_no); CREATE INDEX idx_user_time ON orders(user_id, create_time DESC); CREATE INDEX idx_status_time ON orders(status, create_time); CREATE INDEX idx_product_status ON orders(product_id, status);