Python基础(②⑥分库分表)
为什么要分库分表?
当数据量越来越大时(比如用户表有几亿行):
单个数据库压力太大 → 查询变慢
单表数据太多 → 索引失效、锁竞争严重
单机资源有限 → CPU、内存、磁盘都可能成为瓶颈
举例:用户表分表
假设原始表:
CREATE TABLE users (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50),email VARCHAR(100)
);
水平分表(按 ID 取模)
CREATE TABLE users_0 (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50),email VARCHAR(100)
);CREATE TABLE users_1 (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50),email VARCHAR(100)
);
插入时:
-- 用户ID % 2 = 0 → 插入 users_0
INSERT INTO users_0 (username, email) VALUES ('alice', 'a@example.com');-- 用户ID % 2 = 1 → 插入 users_1
INSERT INTO users_1 (username, email) VALUES ('bob', 'b@example.com');
查询时:
-- 先计算 user_id % 2,决定查哪张表
SELECT * FROM users_1 WHERE id = 101;
123
场景 | 单表 1 亿 | 分表 3 个 | 分表 10 个 |
---|---|---|---|
插入速度 | 慢(索引大,写入变慢) | 中等(提升约 20~40%) | 快(提升 50%+) |
主键查询 | 慢(几十 ms) | 较快(10~30 ms) | 快(5~15 ms) |
全表扫描 | 最慢(分钟级) | 中等(缩短到 1/3) | 快(缩短到 1/10) |
维护成本 | 高(DDL/备份很慢) | 中(3 张表还行) | 低(单表小,维护轻松) |
应用复杂度 | 最简单 | 一般(id%3 路由) | 较复杂(id%10 路由) |
代码
import pymysql# 数据库连接配置(假设两个库在同一台 MySQL 上)
DB_CONFIG = {"host": "127.0.0.1","user": "root","password": "123456","port": 3306
}# 路由函数:根据 user_id 选择库和表
def get_db_and_table(user_id):db_index = user_id % 2 # 两个库table_index = user_id % 5 # 每库 5 张表db_name = f"users_db_{db_index}"table_name = f"users_{table_index}"return db_name, table_name# 插入用户
def insert_user(user_id, username):db_name, table_name = get_db_and_table(user_id)conn = pymysql.connect(**DB_CONFIG, database=db_name)try:with conn.cursor() as cursor:sql = f"INSERT INTO {table_name} (user_id, username) VALUES (%s, %s)"cursor.execute(sql, (user_id, username))conn.commit()finally:conn.close()print(f"✅ 插入成功: user_id={user_id} → {db_name}.{table_name}")# 查询用户
def get_user(user_id):db_name, table_name = get_db_and_table(user_id)conn = pymysql.connect(**DB_CONFIG, database=db_name)try:with conn.cursor() as cursor:sql = f"SELECT * FROM {table_name} WHERE user_id=%s"cursor.execute(sql, (user_id,))result = cursor.fetchone()finally:conn.close()return result# 测试
if __name__ == "__main__":# 插入用户insert_user(101, "Alice")insert_user(202, "Bob")insert_user(303, "Charlie")# 查询用户print(get_user(101))print(get_user(202))print(get_user(303))
账号表放在 MySQL(权威存储)+ Redis 做缓存
MySQL:存账号 → user_id 的权威数据(保证一致性)。
Redis:存一份缓存映射,比如:
key: account:alice
value: user_id=101
登录流程:
用户输入账号 → 先查 Redis
如果 Redis 有 → 直接拿到 user_id,去分表查详情
如果 Redis 没有 → 去 MySQL 账号表查 → 回写 Redis