MySQL 分库分表脚本实践:批量创建数据库与表
本文介绍了一个批量创建MySQL分库分表架构的自动化脚本解决方案。该脚本通过嵌套循环创建8个数据库(user_0到user_7),每个库包含16张表(user_info_0到user_info_127),共128张表。脚本实现了数据库连接配置、utf8mb4字符集支持、表结构定义(包含用户信息字段和索引)等功能,采用HereDocument语法执行批量SQL命令。该方案可有效解决大数据量下的性能瓶
在实际开发中,当数据量逐渐增大时,单一数据库和表可能无法满足性能需求。分库分表是一种有效的解决方案,可以将数据分散存储到多个数据库和表中,提高系统的性能和可扩展性。本文将介绍如何编写一个批量创建分库分表的 MySQL 脚本,帮助您快速搭建分库分表架构。
一、脚本功能概述
这个 MySQL 脚本实现了以下功能:
- 数据库连接配置:设置数据库连接参数,包括主机地址、端口、用户名和密码。
- 外层循环创建数据库:通过循环创建 8 个数据库,命名为user_0到user_7。
- 内层循环创建表:每个数据库内创建 16 张表,表名格式为user_info_0到user_info_127。
- 表结构定义:每个表都包含相同的表结构,包括用户基本信息字段和索引。
最终将创建8 个数据库 × 16 张表 = 128 张表的分库分表架构。
二、完整脚本代码
#!/bin/bash
# -------------------------- 数据库连接配置 --------------------------
# 根据实际环境修改以下参数
MYSQL_HOST="127.0.0.1" # MySQL主机地址
MYSQL_PORT="3306" # MySQL端口
MYSQL_USER="root" # 连接用户名(需有创建库表权限)
MYSQL_PASSWORD="rootpass"# 连接密码
# -------------------------------------------------------------------
# 外层循环:创建8个数据库(user_0 到 user_7)
for db_idx in $(seq 0 7); do
db_name="user_${db_idx}"
echo "开始创建数据库:${db_name} (${db_idx}/7)"
# 使用Here Document执行SQL命令
mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" << EOF
-- 创建数据库(指定字符集为utf8mb4,支持emoji)
CREATE DATABASE IF NOT EXISTS ${db_name}
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 切换到当前数据库
USE ${db_name};
-- 内层循环:每个数据库创建16张表(user_info_0 到 user_info_15)
EOF
# 内层循环:生成16张表的创建语句
for i in $(seq 0 15); do
table_idx=$((db_idx * 16 + i))
echo " 正在创建表:user_info_${table_idx} (${i}/15)"
# 执行建表SQL
mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" "${db_name}" << EOF
CREATE TABLE IF NOT EXISTS user_info_${table_idx} (
id VARCHAR(36) NOT NULL COMMENT '用户ID(UUID)',
name VARCHAR(50) NOT NULL COMMENT '用户名',
phone VARCHAR(20) NOT NULL COMMENT '手机号',
age TINYINT UNSIGNED DEFAULT NULL COMMENT '年龄(无符号,0-255)',
school VARCHAR(100) DEFAULT NULL COMMENT '学校',
gender TINYINT(1) DEFAULT NULL COMMENT '性别:0-女,1-男,2-未知',
create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id), -- 主键(唯一且非空)
UNIQUE KEY uni_name (name), -- 用户名唯一索引(避免重复)
KEY idx_id_name_phone (id, name, phone) -- 组合索引(优化多字段查询)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COMMENT='用户信息表(分片索引:${table_idx})';
EOF
done
echo "数据库 ${db_name} 创建完成!"
echo "----------------------------------------"
done
echo "所有分库分表创建完毕!"
三、脚本执行输出示例
当您运行上述脚本时,会在终端看到类似以下的输出:
开始创建数据库:user_0 (0/7)
正在创建表:user_info_0 (0/15)
正在创建表:user_info_1 (1/15)
正在创建表:user_info_2 (2/15)
正在创建表:user_info_3 (3/15)
正在创建表:user_info_4 (4/15)
正在创建表:user_info_5 (5/15)
正在创建表:user_info_6 (6/15)
正在创建表:user_info_7 (7/15)
正在创建表:user_info_8 (8/15)
正在创建表:user_info_9 (9/15)
正在创建表:user_info_10 (10/15)
正在创建表:user_info_11 (11/15)
正在创建表:user_info_12 (12/15)
正在创建表:user_info_13 (13/15)
正在创建表:user_info_14 (14/15)
正在创建表:user_info_15 (15/15)
数据库 user_0 创建完成!
----------------------------------------
开始创建数据库:user_1 (1/7)
正在创建表:user_info_16 (0/15)
正在创建表:user_info_17 (1/15)
...
所有分库分表创建完毕!
这种输出格式清晰地显示了脚本的执行进度,包括当前正在创建的数据库和表,以及完成的百分比。
四、脚本详细说明
4.1 数据库连接配置
脚本开头部分定义了数据库连接参数:
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASSWORD="rootpass"
请务必根据实际环境修改这些参数,特别是:
- MYSQL_HOST:数据库服务器的 IP 地址或域名
- MYSQL_PORT:数据库端口,默认是 3306
- MYSQL_USER:具有创建数据库和表权限的用户名
- MYSQL_PASSWORD:对应的密码
4.2 外层循环创建数据库
外层循环使用seq 0 7生成 0 到 7 的索引,创建 8 个数据库:
for db_idx in $(seq 0 7); do
db_name="user_${db_idx}"
echo "开始创建数据库:${db_name} (${db_idx}/7)"
# ... 创建数据库的代码 ...
done
每个数据库名称遵循user_0到user_7的命名规则。echo语句用于显示当前正在创建的数据库及其进度。
4.3 使用 Here Document 创建数据库
使用 MySQL 命令行工具和 Here Document 语法执行创建数据库的 SQL 命令:
mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" << EOF
CREATE DATABASE IF NOT EXISTS ${db_name}
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE ${db_name};
EOF
IF NOT EXISTS子句确保如果数据库已存在,不会产生错误。使用utf8mb4字符集支持包括 emoji 在内的所有 Unicode 字符。
4.4 内层循环创建表
内层循环在每个数据库中创建 16 张表:
for i in $(seq 0 15); do
table_idx=$((db_idx * 16 + i))
echo " 正在创建表:user_info_${table_idx} (${i}/15)"
# ... 创建表的代码 ...
done
表索引通过公式table_idx = db_idx * 16 + i计算得出,确保每个表在整个架构中具有唯一的索引(从 0 到 127)。
4.5 表结构定义
每个表都具有相同的结构定义:
CREATE TABLE IF NOT EXISTS user_info_${table_idx} (
id VARCHAR(36) NOT NULL COMMENT '用户ID(UUID)',
name VARCHAR(50) NOT NULL COMMENT '用户名',
phone VARCHAR(20) NOT NULL COMMENT '手机号',
age TINYINT UNSIGNED DEFAULT NULL COMMENT '年龄(无符号,0-255)',
school VARCHAR(100) DEFAULT NULL COMMENT '学校',
gender TINYINT(1) DEFAULT NULL COMMENT '性别:0-女,1-男,2-未知',
create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id),
UNIQUE KEY uni_name (name),
KEY idx_id_name_phone (id, name, phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表(分片索引:${table_idx})';
表结构详细说明:
字段定义:
- id:使用 VARCHAR (36) 存储 UUID,作为主键
- name:VARCHAR (50) 存储用户名,不能为空
- phone:VARCHAR (20) 存储手机号,不能为空
- age:TINYINT UNSIGNED 类型,范围 0-255
- school:VARCHAR (100) 存储学校信息
- gender:TINYINT (1) 存储性别,0 表示女,1 表示男,2 表示未知
- create_at:TIMESTAMP 类型,默认值为当前时间
- 索引设计:
- PRIMARY KEY (id):主键索引,确保 id 唯一且非空
- UNIQUE KEY uni_name (name):唯一索引,确保用户名唯一
- KEY idx_id_name_phone (id, name, phone):组合索引,优化多字段查询
- 存储引擎和字符集:
- 使用ENGINE=InnoDB存储引擎,支持事务和行级锁
- DEFAULT CHARSET=utf8mb4指定字符集为 utf8mb4,支持所有 Unicode 字符
随着数据量的增长,单库单表会面临以下问题:
- 查询性能下降
- 写入性能下降
- 备份和恢复时间增加
- 硬件资源利用率低
分库分表通过将数据分散存储到多个数据库和表中,可以有效解决这些问题,提高系统的可扩展性和性能。
本脚本采用的分库分表策略
本脚本实现了一种简单的水平分库分表策略:
- 水平分库:将数据分散到多个数据库(user_0 到 user_7)
- 水平分表:每个数据库中再分散到多个表(user_info_0 到 user_info_15)
- 分片键:通过某种算法(如哈希、取模等)将数据映射到具体的数据库和表
分片键计算公式:
TypeScript取消自动换行复制
数据库索引 = 分片键 % 数据库数量
表索引 = (分片键 / 数据库数量) % 表数量
在实际应用中,需要根据业务特点选择合适的分片键。常见的分片键包括:
- 用户 ID
- 时间戳
- 地理位置
- 业务类型
分库分表带来的挑战
分库分表虽然解决了单库单表的性能问题,但也带来了一些新的挑战:
- 分布式事务:跨库操作时,事务处理变得复杂
- 跨库关联查询:无法直接进行 JOIN 操作,需要在应用层处理
- 分布式 ID:需要保证全局唯一的 ID 生成策略
- 数据迁移与扩容:随着数据增长,可能需要重新分片
总结
本文介绍了如何编写一个批量创建分库分表的 MySQL 脚本,该脚本可以创建 8 个数据库,每个数据库包含 16 张表,总共 128 张表的分库分表架构。
关键点包括:
- 使用嵌套循环创建数据库和表
- 采用 utf8mb4 字符集支持所有 Unicode 字符
- 合理设计表结构和索引
- 使用 Here Document 语法执行批量 SQL 命令
分库分表是解决大数据量存储和高性能需求的有效手段,但也需要根据具体业务场景选择合适的分库分表策略,并注意处理随之而来的各种挑战。
通过本脚本,您可以快速搭建一个分库分表的数据库架构,为后续的数据分片存储奠定基础。实际应用中,可以根据业务数据量调整分库分表数量,以达到最佳的性能和资源利用率。
更多推荐


所有评论(0)