本质:同一字段存在多个重复或包含关系的索引
典型场景
INDEX(a)
和 INDEX(a)
INDEX(a,b,c)
时再建INDEX(a,b)
面试考点
SHOW INDEX
识别冗余索引黄金法则:索引包含查询需要的所有字段
性能飞跃原理
-- 需要回表
SELECT name FROM users WHERE age > 25; -- 使用INDEX(age)
-- 覆盖索引
CREATE INDEX idx_age_name ON users(age, name);
SELECT name FROM users WHERE age > 25; -- 无需回表
面试高频问题
EXPLAIN
的Extra
列识别Using index
INDEX(a,b)
可覆盖WHERE a=? ORDER BY b
反常识优势场景
面试陷阱题
FORCE INDEX(PRIMARY)
强制全表扫描优化查询维度 | 索引冗余 | 覆盖索引 | 全表扫描 |
---|---|---|---|
读性能(QPS) | 可能降低10-20% | 提升3-10倍 | 稳定但绝对值最低 |
写性能(TPS) | 指数级下降 | 线性增长 | 无影响 |
存储消耗 | 倍增风险 | 增加30-50% | 0 |
维护成本 | 高(双重维护) | 中 | 低 |
适用查询类型 | 多条件混合查询 | 固定模式查询 | 大数据量分析 |
def choose_strategy(query):
if query.selectivity < 5%: # 低选择性
if index_coverage(query): # 覆盖索引可用
return "覆盖索引"
else:
return "B+树索引"
elif 5% < selectivity < 30%: # 中等选择性
if has_redundant_index(query): # 存在冗余索引
return "评估索引合并"
else:
return "新建覆盖索引"
else: # 高选择性
if table_size < buffer_pool/5: # 热数据全在内存
return "全表扫描"
else:
return "分区扫描"
原始结构
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id INT,
item_id INT,
create_time DATETIME,
INDEX idx_user (user_id),
INDEX idx_time (create_time)
);
问题查询
SELECT item_id, create_time
FROM orders
WHERE user_id = 1001
ORDER BY create_time DESC
LIMIT 100;
优化方案
idx_user
和idx_time
INDEX idx_user_time(item_id, create_time)
错误实践
-- 在10亿条日志表上盲目创建覆盖索引
CREATE INDEX idx_full_coverage ON logs(timestamp, level, service, message);
后果
问题:“什么情况下应该删除索引?”
满分回答:
"当索引的收益成本比小于1时需要删除,具体可通过三个维度判断:
- 使用频率:通过
SHOW INDEX_STATISTICS
观察索引使用次数- 维护代价:计算该索引导致写操作增加的耗时比例
- 替代方案:是否可以被其他索引或覆盖查询替代
例如一个日均使用<5次但使插入变慢30%的索引就应该删除"
当面试官问到:“你觉得索引越多越好吗?”
降维打击式回答:
"这其实是个存储引擎的博弈论问题。从B+树的结构特性来看:
- 每个索引都是一棵独立的B+树,导致写放大效应
- 内存中需要维护多个索引的缓冲页,加剧内存竞争
- 优化器的选择困难症会增加执行计划分析时间
根据Google的实证研究,当表索引超过5个时,系统整体吞吐量会下降22%以上"
典型问题:“INDEX(a)和INDEX(b)同时存在,WHERE a=1 AND b=2会怎样?”
专业回答:
"这取决于优化器的成本计算:
- 如果存在覆盖索引会优先使用
- 可能使用Intersection Merge:同时扫描两个索引求交集
- 关键指标是
index_merge_intersection_limit
(默认20)
但要注意这种合并需要双倍的索引扫描,在SSD上可能比全表扫描更慢"
进阶问题:“INDEX(a,b,c)能覆盖WHERE b=? AND c=?吗?”
深度解析:
"常规情况不能,但通过以下技巧可实现:
- 虚拟列技术:ALTER TABLE ADD COLUMN bc VARCHAR(200) AS (CONCAT(b,c))
- 函数索引:CREATE INDEX idx_func ON tbl((b+c))
- 调整查询:WHERE a IS NOT NULL AND b=? AND c=?(利用索引跳跃扫描)
不过这些方法都有适用限制,需要根据具体DBMS特性选择"
免费下载 | 开箱即用 | AI赋能 | 全链路SQL开发
✅ 敏捷开发团队快速迭代
✅ DBA智能运维管理
✅ 数据分析师自助查询
✅ 教学培训SQL编程
✅ 企业级数据资产管理
→ [立即下载] https://sourceforge.net/projects/dblens-for-mysql