本文目录导读:

我来给您介绍几种常见数据库的自动分区脚本编写方法。
MySQL 自动分区脚本
按日期范围自动分区
-- 存储过程:自动创建月分区
DELIMITER $$
CREATE PROCEDURE auto_create_partitions()
BEGIN
DECLARE v_max_date DATE;
DECLARE v_next_date DATE;
DECLARE v_partition_name VARCHAR(50);
-- 获取最大分区日期
SELECT MAX(SUBSTRING_INDEX(PARTITION_DESCRIPTION, "'", -2))
INTO v_max_date
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'your_table';
-- 如果没有分区,从当前月开始
IF v_max_date IS NULL THEN
SET v_max_date = DATE_FORMAT(NOW(), '%Y-%m-01');
END IF;
-- 创建未来3个月的分区
SET @counter = 1;
WHILE @counter <= 3 DO
SET v_next_date = DATE_ADD(v_max_date, INTERVAL @counter MONTH);
SET v_partition_name = CONCAT('p', DATE_FORMAT(v_next_date, '%Y%m'));
SET @sql = CONCAT(
'ALTER TABLE your_table ADD PARTITION (',
'PARTITION ', v_partition_name,
' VALUES LESS THAN (\'', v_next_date, '\')',
')'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @counter = @counter + 1;
END WHILE;
END$$
DELIMITER ;
-- 设置定时任务每月执行
CREATE EVENT IF NOT EXISTS monthly_partition_event
ON SCHEDULE EVERY 1 MONTH
STARTS DATE_ADD(LAST_DAY(NOW()), INTERVAL 1 DAY)
DO
CALL auto_create_partitions();
PostgreSQL 自动分区脚本
使用函数自动创建分区
-- 创建分区函数
CREATE OR REPLACE FUNCTION auto_create_partition()
RETURNS TRIGGER AS $$
DECLARE
v_partition_name TEXT;
v_start_date DATE;
v_end_date DATE;
BEGIN
-- 计算分区范围(按月分区)
v_start_date := DATE_TRUNC('month', NEW.created_date);
v_end_date := v_start_date + INTERVAL '1 month';
v_partition_name := 'your_table_' || TO_CHAR(v_start_date, 'YYYYMM');
-- 检查分区是否存在
IF NOT EXISTS (
SELECT 1 FROM pg_class
WHERE relname = v_partition_name
) THEN
-- 创建新分区
EXECUTE FORMAT(
'CREATE TABLE %I PARTITION OF your_table
FOR VALUES FROM (%L) TO (%L)',
v_partition_name,
v_start_date,
v_end_date
);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER auto_partition_trigger
BEFORE INSERT ON your_table
FOR EACH ROW
EXECUTE FUNCTION auto_create_partition();
-- 或使用定时任务
CREATE OR REPLACE FUNCTION scheduled_partition_creation()
RETURNS VOID AS $$
DECLARE
v_partition_name TEXT;
v_start_date DATE;
v_end_date DATE;
v_counter INTEGER := 0;
BEGIN
-- 创建未来6个月的分区
WHILE v_counter < 6 LOOP
v_start_date := DATE_TRUNC('month', NOW() + (v_counter || ' month')::INTERVAL);
v_end_date := v_start_date + INTERVAL '1 month';
v_partition_name := 'your_table_' || TO_CHAR(v_start_date, 'YYYYMM');
IF NOT EXISTS (
SELECT 1 FROM pg_class
WHERE relname = v_partition_name
) THEN
EXECUTE FORMAT(
'CREATE TABLE %I PARTITION OF your_table
FOR VALUES FROM (%L) TO (%L)',
v_partition_name,
v_start_date,
v_end_date
);
END IF;
v_counter := v_counter + 1;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 创建定时任务(需要pg_cron扩展)
SELECT cron.schedule('create-partitions', '0 0 1 * *',
'SELECT scheduled_partition_creation();');
Shell 脚本自动化(通用方案)
#!/bin/bash
# auto_partition.sh - 自动分区脚本
DB_HOST="localhost"
DB_USER="root"
DB_PASS="password"
DB_NAME="your_database"
TABLE_NAME="your_table"
# MySQL版本
mysql_partition() {
local month_offset=$1
local next_month=$(date -d "+${month_offset} month" +%Y-%m-01)
local partition_name="p$(date -d "+${month_offset} month" +%Y%m)"
mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASS} ${DB_NAME} <<EOF
ALTER TABLE ${TABLE_NAME} ADD PARTITION (
PARTITION ${partition_name}
VALUES LESS THAN ('${next_month}')
);
EOF
}
# PostgreSQL版本
psql_partition() {
local month_offset=$1
local start_date=$(date -d "+${month_offset} month" +%Y-%m-01)
local end_date=$(date -d "+$((month_offset + 1)) month" +%Y-%m-01)
local partition_name="${TABLE_NAME}_$(date -d "+${month_offset} month" +%Y%m)"
PGPASSWORD=${DB_PASS} psql -h ${DB_HOST} -U ${DB_USER} -d ${DB_NAME} <<EOF
CREATE TABLE IF NOT EXISTS ${partition_name}
PARTITION OF ${TABLE_NAME}
FOR VALUES FROM ('${start_date}') TO ('${end_date}');
EOF
}
# 检查并创建未来3个月的分区
for i in {1..3}; do
mysql_partition $i
# psql_partition $i # PostgreSQL版本
done
# 清理过期的分区(保留6个月)
cleanup_old_partitions() {
local cutoff_date=$(date -d "-6 months" +%Y-%m-01)
# MySQL清理
mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASS} ${DB_NAME} <<EOF
SELECT CONCAT('ALTER TABLE ${TABLE_NAME} DROP PARTITION ',
PARTITION_NAME, ';')
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = '${TABLE_NAME}'
AND SUBSTRING_INDEX(PARTITION_DESCRIPTION, "'", -2) < '${cutoff_date}';
EOF
}
# 添加到crontab
# 0 0 1 * * /path/to/auto_partition.sh
Python 自动化脚本
#!/usr/bin/env python3
# auto_partition.py
import mysql.connector
import psycopg2
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
import logging
import schedule
import time
class AutoPartition:
def __init__(self, db_type='mysql', config=None):
self.db_type = db_type
self.config = config or {
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'your_database'
}
self.table_name = 'your_table'
self.setup_logging()
def setup_logging(self):
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('partition.log'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def create_connection(self):
"""创建数据库连接"""
if self.db_type == 'mysql':
return mysql.connector.connect(**self.config)
elif self.db_type == 'postgresql':
return psycopg2.connect(**self.config)
def get_month_boundaries(self, months_ahead=0):
"""获取月份边界"""
current = datetime.now()
target_date = current + relativedelta(months=months_ahead)
# 月初
start_date = target_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
# 下个月初
next_month = start_date + relativedelta(months=1)
return start_date, next_month
def create_mysql_partition(self, cursor, start_date, end_date):
"""创建MySQL分区"""
partition_name = f"p{start_date.strftime('%Y%m')}"
end_date_str = end_date.strftime('%Y-%m-%d')
# 检查分区是否存在
cursor.execute("""
SELECT PARTITION_NAME
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = %s AND PARTITION_NAME = %s
""", (self.table_name, partition_name))
if not cursor.fetchone():
sql = f"""
ALTER TABLE {self.table_name}
ADD PARTITION (
PARTITION {partition_name}
VALUES LESS THAN ('{end_date_str}')
)
"""
cursor.execute(sql)
self.logger.info(f"Created partition: {partition_name}")
return True
return False
def create_pgsql_partition(self, cursor, start_date, end_date):
"""创建PostgreSQL分区"""
partition_name = f"{self.table_name}_{start_date.strftime('%Y%m')}"
start_str = start_date.strftime('%Y-%m-%d')
end_str = end_date.strftime('%Y-%m-%d')
# 检查分区是否存在
cursor.execute("""
SELECT EXISTS (
SELECT 1 FROM pg_class WHERE relname = %s
)
""", (partition_name,))
if not cursor.fetchone()[0]:
sql = f"""
CREATE TABLE {partition_name}
PARTITION OF {self.table_name}
FOR VALUES FROM ('{start_str}') TO ('{end_str}')
"""
cursor.execute(sql)
self.logger.info(f"Created partition: {partition_name}")
return True
return False
def create_partitions(self, months_ahead=3):
"""创建未来几个月的分区"""
conn = self.create_connection()
cursor = conn.cursor()
created = False
for i in range(1, months_ahead + 1):
start_date, end_date = self.get_month_boundaries(i)
if self.db_type == 'mysql':
result = self.create_mysql_partition(cursor, start_date, end_date)
elif self.db_type == 'postgresql':
result = self.create_pgsql_partition(cursor, start_date, end_date)
if result:
created = True
if created:
conn.commit()
self.logger.info("Partitions created successfully")
else:
self.logger.info("No new partitions needed")
cursor.close()
conn.close()
def cleanup_old_partitions(self, months_to_keep=6):
"""清理旧分区"""
conn = self.create_connection()
cursor = conn.cursor()
cutoff_date = datetime.now() - relativedelta(months=months_to_keep)
cutoff_str = cutoff_date.strftime('%Y-%m-%d')
if self.db_type == 'mysql':
cursor.execute(f"""
SELECT PARTITION_NAME, PARTITION_DESCRIPTION
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = '{self.table_name}'
AND CAST(SUBSTRING_INDEX(PARTITION_DESCRIPTION, "'", -2) AS DATE) < '{cutoff_str}'
""")
for row in cursor.fetchall():
drop_sql = f"ALTER TABLE {self.table_name} DROP PARTITION {row[0]}"
cursor.execute(drop_sql)
self.logger.info(f"Dropped partition: {row[0]}")
conn.commit()
cursor.close()
conn.close()
def run_scheduled(self):
"""运行定时任务"""
self.create_partitions(months_ahead=3)
self.cleanup_old_partitions(months_to_keep=6)
# 使用示例
if __name__ == "__main__":
# MySQL配置
mysql_config = {
'host': 'localhost',
'user': 'root',
'password': 'password',
'database': 'your_database'
}
partitioner = AutoPartition(db_type='mysql', config=mysql_config)
# 立即执行
partitioner.create_partitions(months_ahead=3)
partitioner.cleanup_old_partitions(months_to_keep=6)
# 设置定时任务(每月1号执行)
schedule.every().month.at("00:00").do(partitioner.run_scheduled)
# 保持运行
while True:
schedule.run_pending()
time.sleep(3600) # 每小时检查一次
最佳实践建议
分区策略选择
-- 1. 范围分区(推荐)
CREATE TABLE orders (
order_id INT,
order_date DATE,
amount DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);
-- 2. 哈希分区(均匀分布)
CREATE TABLE user_logs (
user_id INT,
action VARCHAR(50),
created_at TIMESTAMP
)
PARTITION BY HASH (user_id) PARTITIONS 8;
-- 3. 列表分区(特定值)
CREATE TABLE area_data (
area_id INT,
area_name VARCHAR(50),
data_value DECIMAL(10,2)
)
PARTITION BY LIST (area_id) (
PARTITION p_north VALUES IN (1, 2, 3),
PARTITION p_south VALUES IN (4, 5, 6)
);
监控和维护脚本
-- 查看分区信息
SELECT
TABLE_NAME,
PARTITION_NAME,
PARTITION_METHOD,
PARTITION_EXPRESSION,
TABLE_ROWS,
DATA_LENGTH
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'your_table';
-- 查看分区数据量
SELECT
PARTITION_NAME,
TABLE_ROWS,
DATA_LENGTH/1024/1024 as 'Size(MB)'
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'your_table';
注意事项
- 备份策略:分区操作前一定要备份
- 监控报警:监控分区创建失败和磁盘空间
- 性能考虑:避免频繁ALTER操作影响性能
- 兼容性:不同数据库版本语法可能有差异
- 错误处理:完善错误处理和日志记录
选择适合您业务场景的分区方案,建议先从时间范围分区开始。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播