加索引是否可以立即加?

加索引是否可以立即加?

可以立即加,但需要考虑以下因素:

立即添加的情况:

  • ✅ 数据量小的表(< 10万行)

  • ✅ 业务低峰期

  • ✅ 有合适的维护窗口

  • ✅ 测试环境

需要谨慎的情况:

  • ❌ 生产环境大表(> 100万行)

  • ❌ 业务高峰期

  • ❌ 表频繁写入

  • ❌ 磁盘空间不足

2. 数据量大小的影响

不同数据量级的影响对比

 
数据量级加索引耗时对业务影响建议操作
< 10万行 秒级完成 几乎无影响 可直接添加
10-100万行 几秒到几分钟 轻微影响 低峰期添加
100-1000万行 几分钟到几十分钟 中等影响 维护窗口添加
> 1000万行 几十分钟到几小时 重大影响 需要特殊处理

3. 加索引的风险和影响

可能的影响:

  1. 表锁定:某些操作可能锁表,导致写操作阻塞

  2. 磁盘空间:索引会占用额外磁盘空间

  3. 性能波动:创建过程中可能导致性能下降

  4. 内存使用:需要足够的内存来排序和构建索引

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. 最终建议

  1. 先评估:使用上面提到的SQL检查表大小和当前索引

  2. 选时机:在业务低峰期操作(如凌晨2-5点)

  3. 用工具:大表使用pt-online-schema-change等工具

  4. 有监控:操作过程中监控数据库状态

  5. 备回滚:准备好回滚方案

安全添加索引的黄金法则:

sql
-- 永远使用最安全的选项开始
ALTER TABLE your_table 
ADD INDEX idx_name (columns) 
ALGORITHM=INPLACE,   -- 在线算法
LOCK=NONE;           -- 无锁或共享锁

如果无法确定,可以先在从库或测试环境执行,观察效果后再应用到生产环境。

 
 
posted @ 2025-12-29 11:37  ni当像鸟飞往你的山  阅读(4)  评论(0)    收藏  举报