面對數百張同結構分表(如 student_001~student_300)需同步添加多個索引,手工執行極易出錯且效率低。本文展示「游標 + 預處理 + 動態 SQL」組合拳,實現批量 DDL 安全、可控、可重試執行。
information_schema.TABLES 篩選目標表名CONCAT 構建帶反引號的合法 DDLCONTINUE HANDLER 實現單表失敗不中斷全局流程
DROP PROCEDURE IF EXISTS batch_add_indexes;
DELIMITER $$
CREATE PROCEDURE batch_add_indexes()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_tbl VARCHAR(64);
DECLARE v_sql TEXT;
-- 1. 定義游標:篩選前綴為 student_ 的表
DECLARE cur CURSOR FOR
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'school_db'
AND TABLE_NAME LIKE 'student_%';
-- 2. 綁定 NOT FOUND 條件:游標結束置 done=1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_tbl;
IF done = 1 THEN
LEAVE read_loop;
END IF;
-- 3. 動態構建 5 條 CREATE INDEX 語句
SET @sql1 = CONCAT('CREATE INDEX idx_flag ON `', v_tbl, '` (`flag`)');
SET @sql2 = CONCAT('CREATE INDEX idx_state ON `', v_tbl, '` (`state`)');
SET @sql3 = CONCAT('CREATE INDEX idx_upload ON `', v_tbl, '` (`upload`)');
SET @sql4 = CONCAT('CREATE INDEX idx_lockflag ON `', v_tbl, '` (`lockFlag`)');
SET @sql5 = CONCAT('CREATE INDEX idx_comes ON `', v_tbl, '` (`comes`)');
-- 4. 預處理 + 執行 + 釋放(逐條獨立,便於定位失敗)
PREPARE s1 FROM @sql1; EXECUTE s1; DEALLOCATE PREPARE s1;
PREPARE s2 FROM @sql2; EXECUTE s2; DEALLOCATE PREPARE s2;
PREPARE s3 FROM @sql3; EXECUTE s3; DEALLOCATE PREPARE s3;
PREPARE s4 FROM @sql4; EXECUTE s4; DEALLOCATE PREPARE s4;
PREPARE s5 FROM @sql5; EXECUTE s5; DEALLOCATE PREPARE s5;
-- 可選:記錄執行日誌
-- INSERT INTO ddl_log (tbl, sql_text, exec_time) VALUES (v_tbl, CONCAT(@sql1,';',@sql2), NOW());
END LOOP;
CLOSE cur;
END$$
DELIMITER ;
-- 執行
CALL batch_add_indexes();
CONCAT('... `', v_tbl, '` ...') 防止表名含保留字或特殊字符報錯。CONCAT(@sql1, @sql2...) 合併為一條多語句,MySQL 預處理不支持多語句,且合併後失敗難以定位具體索引。CONTINUE HANDLER FOR SQLEXCEPTION:單表單索引失敗記錄日誌並繼續下一張(推薦)EXIT HANDLER:遇錯即停,適合強一致性要求場景INDEX、SELECT(查元數據)權限。
-- 檢查索引是否已存在,避免重複報錯
SET @chk = CONCAT('SELECT COUNT(*) INTO @exist FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA=''school_db'' AND TABLE_NAME=''', v_tbl, ''' AND INDEX_NAME=''idx_flag''');
PREPARE p_chk FROM @chk; EXECUTE p_chk; DEALLOCATE PREPARE p_chk;
IF @exist = 0 THEN
-- 執行 CREATE INDEX
END IF;
information_schema.STATISTICS 索引數量DROP INDEX idx_flag ON `student_001` 批量生成Threads_running、Innodb_row_lock_waits 指標ANALYZE TABLE 更新統計信息,確保優化器感知新索引游標 + 預處理模式不僅適用於加索引,同理可擴展至批量加列、修改列類型、統計表大小等一切「同結構多表」的 Schema 變更場景,是 DBA 自動化工具箱中的核心組件。