MySQL的分库分表(Sharding)是一种将数据水平拆分为多个库和表的技术,以解决单个数据库性能瓶颈和存储限制。这种技术可以提高数据库的并发处理能力,分散数据存储负载。下面详细介绍如何进行MySQL的分库分表,并结合代码进行说明。
一、分库分表的策略
- 水平分表:将一张大表拆分为多张小表。
- 水平分库:将一个库的数据拆分到多个库中,每个库包含部分数据。
- 垂直分表:将一张大表按列拆分为多张小表(通常不涉及水平分库分表的讨论)。
二、分库分表的实现步骤
1. 设计分库分表策略
常见的分库分表策略有Hash分片、Range分片和List分片。以下以水平分库分表为例,采用Hash分片策略。
假设我们有一个用户表users
,需要进行分库分表。
1.1 选择分片键
选择一个确定分片方法的字段,比如用户ID (user_id
)。
1.2 确定分片规则
假设我们将数据拆分到4个库中,每个库包含4张表,总共16张表。分片规则可以是:
- 库编号 =
user_id % 4
- 表编号 =
user_id / 4 % 4
1.3 创建数据库和表
sql
-- 创建4个数据库
CREATE DATABASE user_db_0;
CREATE DATABASE user_db_1;
CREATE DATABASE user_db_2;
CREATE DATABASE user_db_3;
-- 在每个数据库中创建4张用户表
USE user_db_0;
CREATE TABLE users_0 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
CREATE TABLE users_1 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
CREATE TABLE users_2 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
CREATE TABLE users_3 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
USE user_db_1;
CREATE TABLE users_0 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
CREATE TABLE users_1 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
CREATE TABLE users_2 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
CREATE TABLE users_3 (user_id INT PRIMARY KEY, user_name VARCHAR(255), ...);
-- 重复以上步骤在 user_db_2 和 user_db_3 中创建表
2. 实现数据的插入、查询和管理
2.1 插入数据
根据分片规则插入数据:
python
def insert_user(user_id, user_name):
db_index = user_id % 4
table_index = (user_id // 4) % 4
db_name = f"user_db_{db_index}"
table_name = f"users_{table_index}"
sql = f"INSERT INTO {db_name}.{table_name} (user_id, user_name) VALUES (%s, %s)"
# 执行SQL插入操作(使用具体的数据库连接库,比如pymysql)
cursor.execute(sql, (user_id, user_name))
connection.commit()
# 示例插入
insert_user(123, 'John Doe')
2.2 查询数据
根据分片规则查询数据:
python
def get_user(user_id):
db_index = user_id % 4
table_index = (user_id // 4) % 4
db_name = f"user_db_{db_index}"
table_name = f"users_{table_index}"
sql = f"SELECT * FROM {db_name}.{table_name} WHERE user_id = %s"
# 执行SQL查询操作
cursor.execute(sql, (user_id,))
result = cursor.fetchone()
return result
# 示例查询
user = get_user(123)
print(user)
3. 使用中间件进行分库分表
手动管理分库分表较为复杂,通常使用中间件来简化分库分表的实现。常用的分库分表中间件包括ShardingSphere、Mycat和Vitess等。
3.1 使用ShardingSphere
ShardingSphere是一个开源的分布式数据库中间件,支持分库分表、读写分离和数据加密等功能。
3.1.1 安装ShardingSphere
下载并解压ShardingSphere Proxy:
bash
wget https://archive.apache.org/dist/shardingsphere/5.0.0/apache-shardingsphere-5.0.0-shardingsphere-proxy-bin.tar.gz
tar xzf apache-shardingsphere-5.0.0-shardingsphere-proxy-bin.tar.gz
3.1.2 配置ShardingSphere
编辑conf/server.yaml
和conf/config-sharding.yaml
文件。
server.yaml
:
yaml
authentication:
users:
root:
password: root
sharding:
password: sharding
props:
max-connections-size-per-query: 1
acceptor-size: 16 # The default value is available processors count * 2.
executor-size: 16 # Infinite by default.
proxy-frontend-flush-threshold: 128 # The default value is 128.
proxy-transaction-type: LOCAL
proxy-opentracing-enabled: false
proxy-hint-enabled: false
query-with-cipher-column: true
sql-show: false
check-table-metadata-enabled: false
config-sharding.yaml
:
yaml
schemaName: sharding_db
dataSources:
ds_0:
url: jdbc:mysql://127.0.0.1:3306/user_db_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
ds_1:
url: jdbc:mysql://127.0.0.1:3306/user_db_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
ds_2:
url: jdbc:mysql://127.0.0.1:3306/user_db_2?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
ds_3:
url: jdbc:mysql://127.0.0.1:3306/user_db_3?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
shardingRule:
tables:
users:
actualDataNodes: ds_${0..3}.users_${0..3}
tableStrategy:
inline:
shardingColumn: user_id
algorithmExpression: users_${user_id % 4}
keyGenerator:
type: SNOWFLAKE
column: user_id
defaultDatabaseStrategy:
inline:
shardingColumn: user_id
algorithmExpression: ds_${user_id % 4}
defaultTableStrategy:
none:
3.1.3 启动ShardingSphere
bash
sh bin/start.sh
现在,您可以通过连接到ShardingSphere Proxy来进行数据库操作,而不需要手动管理分库分表逻辑:
python
# 示例连接
import pymysql
connection = pymysql.connect(
host='127.0.0.1',
port=3307, # ShardingSphere默认监听端口
user='sharding',
password='sharding',
db='sharding_db'
)
cursor = connection.cursor()
cursor.execute("INSERT INTO users (user_id, user_name) VALUES (%s, %s)", (123, 'John Doe'))
connection.commit()
cursor.execute("SELECT * FROM users WHERE user_id = %s", (123,))
result = cursor.fetchone()
print(result)
三、总结
分库分表可以有效地解决单库性能瓶颈问题,提高数据库的扩展性和并发处理能力。我们通过手动分库分表和中间件(如ShardingSphere)两种方式进行了详细说明。
- 手动分库分表:适用于简单场景,但需要手动管理分片逻辑和数据分布。
- 中间件分库分表:如Sharding