面對大表性能瓶頸,按業務維度(如站點 ID)水平拆分為多張結構相同的子表是常見優化手段。本文提供一個完整的存儲過程,實現:根據基礎表記錄數動態計算分表數量、批量創建子表、按範圍遷移數據。
tbl_base_syslog(系統日誌),含 site_id 字段tbl_base_site(站點表),記錄總數決定分表數tbl_base_syslog_NDELIMITER $$
CREATE PROCEDURE `sp_split_syslog_by_site`()
BEGIN
DECLARE v_i INT DEFAULT 1;
DECLARE v_siteCount INT;
DECLARE v_sqlStr VARCHAR(2560);
DECLARE v_sqlInsert VARCHAR(2560);
-- 1. 獲取站點總數
SELECT COUNT(0) INTO v_siteCount FROM tbl_base_site;
-- 2. 循環創建分表並遷移數據
WHILE (v_i - 1) * 300 < v_siteCount DO
-- 2.1 動態建表
SET v_sqlStr = CONCAT(
'CREATE TABLE tbl_base_syslog', v_i, '(',
'syslog_id INT(11) AUTO_INCREMENT PRIMARY KEY,',
'create_user VARCHAR(32),',
'description TEXT,',
'create_time DATETIME,',
'site_id INT(11),',
'ip VARCHAR(64),',
'version_id SMALLINT(2),',
'module_identity VARCHAR(64),',
'right_name VARCHAR(64)',
') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
PREPARE stmt FROM v_sqlStr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2.2 遷移對應站點範圍的數據
SET v_sqlInsert = CONCAT(
'INSERT INTO tbl_base_syslog', v_i, '(',
'syslog_id, create_user, description, create_time,',
'site_id, ip, version_id, module_identity, right_name',
')',
'SELECT syslog_id, create_user, description, create_time,',
'site_id, ip, version_id, module_identity, right_name',
'FROM tbl_base_syslog',
'WHERE site_id IN (',
'SELECT tbs.site_id FROM (',
'SELECT site_id FROM tbl_base_site LIMIT ', (v_i * 300), ', 300',
') AS tbs',
')',
'ORDER BY syslog_id'
);
PREPARE stmt FROM v_sqlInsert;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET v_i = v_i + 1;
END WHILE;
END$$
DELIMITER ;
MySQL 存儲過程不支持直接執行變量 SQL,必須用 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; 三步走。
SELECT site_id FROM tbl_base_site LIMIT offset, count
配合 WHERE site_id IN (...) 精確篩選每批遷移的站點範圍。
使用 v_ 前綴區分局部變量,避免與列名衝突;原文用 @i 易混淆為用戶變量。
-- 執行分表遷移
CALL sp_split_syslog_by_site();
-- 驗證結果
SHOW TABLES LIKE 'tbl_base_syslog%';
SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES
WHERE TABLE_NAME LIKE 'tbl_base_syslog%';
pt-online-schema-change / gh-ost 在線遷移site_id 路由到對應子表CREATE PROCEDURE sp_generic_sharding(
IN src_table VARCHAR(64),
IN dst_prefix VARCHAR(64),
IN shard_key VARCHAR(64),
IN ref_table VARCHAR(64),
IN batch_size INT
)
-- 通用化參數:源表、目標前綴、分片鍵、基準表、批次大小
-- 邏輯同上,動態拼接列名(需查詢 information_schema.COLUMNS)
動態分表存儲過程適合一次性歷史數據遷移;線上業務分表建議使用中間件(ShardingSphere、MyCat)或應用層路由,避免 DDL 阻塞業務。