本文目录导读:

对于Python拆分大表同步任务分片,以下是几种常用方案:
基于主键范围分片(推荐)
import pymysql
from typing import List, Tuple
import time
class TableShardSplitter:
def __init__(self, db_config, table_name, primary_key='id', shard_size=10000):
self.db_config = db_config
self.table_name = table_name
self.primary_key = primary_key
self.shard_size = shard_size
def get_shards(self) -> List[Tuple[int, int]]:
"""获取分片范围"""
conn = pymysql.connect(**self.db_config)
cursor = conn.cursor()
# 获取主键最小值和最大值
cursor.execute(f"SELECT MIN({self.primary_key}), MAX({self.primary_key}) FROM {self.table_name}")
min_id, max_id = cursor.fetchone()
cursor.close()
conn.close()
if not min_id or not max_id:
return []
# 按固定大小分片
shards = []
current = min_id
while current <= max_id:
end = min(current + self.shard_size - 1, max_id)
shards.append((current, end))
current = end + 1
return shards
# 使用示例
def sync_shard(table_name, start_id, end_id, db_config, target_config):
"""同步单个分片数据"""
conn = pymysql.connect(**db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 读取分片数据
cursor.execute(
f"SELECT * FROM {table_name} WHERE id BETWEEN %s AND %s",
(start_id, end_id)
)
records = cursor.fetchall()
# 处理数据(示例:写入目标表)
process_records(records, target_config)
cursor.close()
conn.close()
print(f"Sync completed: id {start_id} - {end_id}, records: {len(records)}")
# 主执行函数
def main_sync():
db_config = {
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'source_db'
}
target_config = {
'host': 'target_host',
'user': 'target_user',
'password': 'target_pass',
'database': 'target_db'
}
# 创建分片器
splitter = TableShardSplitter(
db_config=db_config,
table_name='big_table',
primary_key='id',
shard_size=10000 # 每片1万条
)
# 获取分片
shards = splitter.get_shards()
print(f"Total shards: {len(shards)}")
# 顺序执行(可以改为多线程并行)
for start_id, end_id in shards:
sync_shard('big_table', start_id, end_id, db_config, target_config)
基于时间范围分片
class TimeBasedSharder:
def get_time_shards(self, table_name, time_column, start_date, end_date, interval_days=7):
"""按时间范围分片"""
from datetime import datetime, timedelta
shards = []
current = start_date
while current < end_date:
next_date = min(current + timedelta(days=interval_days), end_date)
shards.append((current.strftime('%Y-%m-%d'), next_date.strftime('%Y-%m-%d')))
current = next_date
return shards
def sync_time_shard(self, table_name, start_date, end_date, db_config):
"""按时间范围同步"""
conn = pymysql.connect(**db_config)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute(f"""
SELECT * FROM {table_name}
WHERE {self.time_column} BETWEEN %s AND %s
""", (start_date, end_date))
records = cursor.fetchall()
# 处理数据...
cursor.close()
conn.close()
并行执行方案
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
class ParallelShardSync:
def __init__(self, max_workers=4):
self.max_workers = max_workers
self.lock = threading.Lock()
def parallel_sync(self, shards, table_name, db_config, target_config):
"""并行执行分片同步"""
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures = []
for shard in shards:
future = executor.submit(
self.sync_shard_worker,
shard, table_name, db_config, target_config
)
futures.append(future)
# 收集结果
for future in as_completed(futures):
try:
result = future.result()
print(f"Shard completed: {result}")
except Exception as e:
print(f"Shard failed: {e}")
def sync_shard_worker(self, shard, table_name, db_config, target_config):
"""工作线程函数"""
try:
# 创建独立数据库连接(避免线程冲突)
local_conn = pymysql.connect(**db_config)
# 执行同步逻辑
sync_shard(table_name, shard[0], shard[1], db_config, target_config)
finally:
if local_conn:
local_conn.close()
动态调整分片大小
class AdaptiveShardSplitter:
def __init__(self, target_records_per_shard=10000, max_retries=3):
self.target_records = target_records_per_shard
self.max_retries = max_retries
def adaptive_shard(self, db_config, table_name):
"""动态调整分片大小"""
conn = pymysql.connect(**db_config)
cursor = conn.cursor()
# 获取表统计信息
cursor.execute(f"""
SELECT
COUNT(*) as total_records,
CEIL(COUNT(*) / {self.target_records}) as estimated_shards
FROM {table_name}
""")
stats = cursor.fetchone()
total_records = stats[0]
estimated_shards = stats[1]
# 计算实际分片大小
actual_shard_size = max(5000, total_records // estimated_shards)
# 获取分片边界
cursor.execute(f"""
SELECT
id,
NTILE({estimated_shards}) OVER (ORDER BY id) as bucket
FROM {table_name}
WHERE MOD(id, 100) = 0
GROUP BY bucket
""")
shard_boundaries = []
for row in cursor.fetchall():
if row[1] in [1, estimated_shards]:
shard_boundaries.append(row[0])
cursor.close()
conn.close()
return shard_boundaries
断点续传支持
class ResumeableShardSync:
def __init__(self, progress_file='shard_progress.json'):
self.progress_file = progress_file
self.completed_shards = self.load_progress()
def load_progress(self):
"""加载同步进度"""
import json
import os
if os.path.exists(self.progress_file):
with open(self.progress_file, 'r') as f:
return set(tuple(shard) for shard in json.load(f))
return set()
def save_progress(self, shard):
"""保存同步进度"""
import json
self.completed_shards.add(shard)
with open(self.progress_file, 'w') as f:
json.dump(list(self.completed_shards), f)
def sync_with_progress(self, all_shards, sync_func):
"""带断点续传的同步"""
remaining_shards = [s for s in all_shards if s not in self.completed_shards]
for shard in remaining_shards:
try:
sync_func(shard)
self.save_progress(shard)
print(f"Completed shard: {shard}")
except Exception as e:
print(f"Failed shard {shard}: {e}")
# 记录失败的分片,后续重试
raise
使用建议:
-
选择分片策略:
- 有自增ID:用ID范围分片
- 有时间字段:用时间分片
- 没有索引:考虑ROW_NUMBER()分页
-
性能优化:
- 使用连接池管理数据库连接
- 批量插入(每次500-1000条)
- 关闭自动提交,事务提交
-
异常处理:
- 断点续传机制
- 失败重试策略
- 监控和告警
根据你的具体场景选择合适的方案,生产环境建议使用分布式调度框架(如Apache Airflow)来管理这些同步任务。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播