加索引是否可以立即加?
加索引是否可以立即加?
可以立即加,但需要考虑以下因素:
立即添加的情况:
-
✅ 数据量小的表(< 10万行)
-
✅ 业务低峰期
-
✅ 有合适的维护窗口
-
✅ 测试环境
需要谨慎的情况:
-
❌ 生产环境大表(> 100万行)
-
❌ 业务高峰期
-
❌ 表频繁写入
-
❌ 磁盘空间不足
2. 数据量大小的影响
不同数据量级的影响对比
| 数据量级 | 加索引耗时 | 对业务影响 | 建议操作 |
|---|---|---|---|
| < 10万行 | 秒级完成 | 几乎无影响 | 可直接添加 |
| 10-100万行 | 几秒到几分钟 | 轻微影响 | 低峰期添加 |
| 100-1000万行 | 几分钟到几十分钟 | 中等影响 | 维护窗口添加 |
| > 1000万行 | 几十分钟到几小时 | 重大影响 | 需要特殊处理 |
3. 加索引的风险和影响
可能的影响:
-
表锁定:某些操作可能锁表,导致写操作阻塞
-
磁盘空间:索引会占用额外磁盘空间
-
性能波动:创建过程中可能导致性能下降
-
内存使用:需要足够的内存来排序和构建索引
4. 最佳实践建议
方案一:小表直接添加
sql
-- 直接添加简单索引
ALTER TABLE table_name ADD INDEX index_name (column_name);
方案二:大表安全添加(推荐)
sql
-- 1. 先查看表大小
SELECT
TABLE_NAME,
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS '表大小(MB)',
TABLE_ROWS AS '行数'
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'table_name';
-- 2. 使用在线DDL(MySQL 5.6+)
ALTER TABLE table_name
ADD INDEX idx_column (column_name)
ALGORITHM=INPLACE,
LOCK=NONE; -- 或 LOCK=SHARED
-- 3. 或者使用pt-online-schema-change工具(Percona Toolkit)
方案三:分段创建索引
sql
-- 对于超大表,考虑使用存储过程分段创建
DELIMITER $$
CREATE PROCEDURE p_add_index_safely()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE batch_size INT DEFAULT 10000;
-- 添加索引,但先禁用
ALTER TABLE large_table
ADD INDEX idx_temp (column_name) ALGORITHM=INPLACE,
LOCK=NONE;
-- 如果需要,可以分批处理数据
-- ...
END$$
DELIMITER ;
5. 实际操作检查清单
执行前检查:
sql
-- 1. 检查表当前状态
SHOW TABLE STATUS LIKE 'table_name';
-- 2. 检查是否有长事务
SELECT * FROM information_schema.INNODB_TRX\G
-- 3. 检查表锁定情况
SHOW OPEN TABLES WHERE In_use > 0;
-- 4. 检查磁盘空间
SELECT
table_schema,
table_name,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
ORDER BY size_mb DESC;
-- 5. 预估索引大小
SELECT
ROUND(SUM(data_length) / 1024 / 1024, 2) AS data_size_mb,
ROUND(SUM(index_length) / 1024 / 1024, 2) AS index_size_mb
FROM information_schema.tables
WHERE table_name = 'table_name';
6. 针对不同场景的具体建议
场景1:紧急修复生产问题
sql
-- 使用最安全的在线DDL方式
ALTER TABLE problematic_table
ADD INDEX idx_critical_column (critical_column)
ALGORITHM=INPLACE,
LOCK=NONE,
COMMENT='紧急修复索引 - 时间戳';
场景2:常规维护窗口
sql
-- 维护窗口内,可以使用稍微激进的方式
SET SESSION lock_wait_timeout = 300;
SET SESSION innodb_lock_wait_timeout = 300;
ALTER TABLE large_table
ADD INDEX idx_column1 (column1),
ADD INDEX idx_column2 (column2)
ALGORITHM=INPLACE,
LOCK=SHARED;
场景3:测试环境
sql
-- 测试环境可以更灵活
ALTER TABLE test_table ADD INDEX idx_test (column_name);
-- 查看执行计划验证效果
EXPLAIN SELECT * FROM test_table WHERE column_name = 'value';
7. 监控和回滚方案
监控索引创建进度
sql
-- MySQL 8.0+ 可以查看进度
SELECT * FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE 'stage/innodb/alter%';
-- 通用方法:查看进程
SHOW PROCESSLIST;
创建前备份信息
sql
-- 1. 备份当前索引定义
SHOW CREATE TABLE table_name;
-- 2. 记录当前性能指标
SHOW GLOBAL STATUS LIKE 'Innodb_rows%';
SHOW GLOBAL STATUS LIKE 'Threads_running';
-- 3. 创建测试语句验证
EXPLAIN SELECT * FROM table_name WHERE indexed_column = 'test';
回滚方案
sql
-- 如果发现问题,可以删除索引
ALTER TABLE table_name DROP INDEX index_name;
-- 或者恢复到原状态
-- 1. 删除新索引
-- 2. 如果有备份,重新导入
8. 特殊情况的处理
超大表的特殊处理
bash
# 使用pt-online-schema-change工具
pt-online-schema-change \
--alter "ADD INDEX idx_column (column_name)" \
D=database,t=table \
--execute \
--critical-load Threads_running=50 \
--max-load Threads_running=25
只读从库先添加
sql
-- 在从库先测试添加索引
-- 1. 在从库添加索引
-- 2. 观察影响
-- 3. 再在主库添加
9. 针对你提到的表的建议
基于你之前的SQL,需要为以下表添加索引:
sql
-- 先检查表大小
SELECT
TABLE_NAME,
TABLE_ROWS,
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN (
'kh_gitlab_commit_detail',
'kh_gitlab_branch_commit_rel',
'kh_project',
'kh_gitlab_repository',
'kh_project__repository'
);
-- 如果表不大,可直接添加
ALTER TABLE kh_gitlab_commit_detail
ADD INDEX idx_repository_id_committed_date (repository_id, committed_date),
ALGORITHM=INPLACE,
LOCK=NONE;
10. 最终建议
-
先评估:使用上面提到的SQL检查表大小和当前索引
-
选时机:在业务低峰期操作(如凌晨2-5点)
-
用工具:大表使用pt-online-schema-change等工具
-
有监控:操作过程中监控数据库状态
-
备回滚:准备好回滚方案
安全添加索引的黄金法则:
sql
-- 永远使用最安全的选项开始
ALTER TABLE your_table
ADD INDEX idx_name (columns)
ALGORITHM=INPLACE, -- 在线算法
LOCK=NONE; -- 无锁或共享锁
如果无法确定,可以先在从库或测试环境执行,观察效果后再应用到生产环境。

浙公网安备 33010602011771号