一、系统架构设计
[MySQL数据库] <--统计查询-->
[Python统计程序] -->
[SQLite统计库] -->
[HTML邮件生成] -->
[SMTP服务器]
二、配置文件设计(config.ini)
[mysql]
host = localhost
port = 3306
user = root
password = your_password
database = information_schema # 默认统计所有数据库
[storage]
stats_db = statistics.db # SQLite存储路径
[email]
smtp_server = smtp.example.com
smtp_port = 587
sender = monitor@example.com
password = email_password
receivers = admin1@ex.com,admin2@ex.com
三、核心代码实现(mysql_table_stats.py)
import configparser
import sqlite3
import smtplib
from email.mime.text import MIMEText
from datetime import datetime, timedelta
import mysql.connector
class TableMonitor:
def __init__(self):
self.config = configparser.ConfigParser()
self.config.read('config.ini')
# 初始化SQLite存储
self.stats_conn = sqlite3.connect(self.config['storage']['stats_db'])
self._init_sqlite()
def _init_sqlite(self):
"""创建统计信息存储表"""
cursor = self.stats_conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS table_stats
(id INTEGER PRIMARY KEY AUTOINCREMENT,
stat_date DATE NOT NULL,
db_name TEXT NOT NULL,
table_name TEXT NOT NULL,
table_rows INTEGER,
data_size REAL,
index_size REAL)''')
self.stats_conn.commit()
def collect_stats(self):
"""采集MySQL表统计信息"""
mysql_conf = self.config['mysql']
conn = mysql.connector.connect(**mysql_conf)
sql = f"""select
table_schema as '数据库',
table_name as '表名',
table_rows as '记录数',
truncate(data_length/1024/1024, 2) as '数据容量(MB)',
truncate(index_length/1024/1024, 2) as '索引容量(MB)'
from information_schema.tables
where table_schema='mysql'
order by data_length desc, index_length desc;
"""
cursor = conn.cursor(dictionary=True)
cursor.execute(sql)
today = datetime.now().strftime("%Y-%m-%d")
for row in cursor:
self._save_to_sqlite(today, row)
cursor.close()
conn.close()
def _save_to_sqlite(self, date, data):
"""保存到SQLite数据库"""
cursor = self.stats_conn.cursor()
cursor.execute('''INSERT INTO table_stats
(stat_date, db_name, table_name, table_rows, data_size, index_size)
VALUES (?,?,?,?,?,?)''',
(date, data['TABLE_SCHEMA'], data['TABLE_NAME'],
data['TABLE_ROWS'], data['data_mb'], data['index_mb']))
self.stats_conn.commit()
def generate_report(self):
"""生成增速排名报告"""
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
cursor = self.stats_conn.cursor()
cursor.execute('''
SELECT
t1.db_name, t1.table_name,
(t1.table_rows - COALESCE(t2.table_rows,0)) as row_growth,
t1.data_size, t1.index_size
FROM table_stats t1
LEFT JOIN table_stats t2
ON t1.db_name = t2.db_name
AND t1.table_name = t2.table_name
AND t2.stat_date = ?
WHERE t1.stat_date = ?
ORDER BY row_growth DESC
LIMIT 50''', (start_date.strftime("%Y-%m-%d"),
end_date.strftime("%Y-%m-%d")))
return cursor.fetchall()
def send_email(self, html_content):
"""发送HTML邮件"""
msg = MIMEText(html_content, 'html')
msg['Subject'] = f'MySQL表增长周报 {datetime.now().strftime("%Y-%m-%d")}'
msg['From'] = self.config['email']['sender']
msg['To'] = self.config['email']['receivers']
with smtplib.SMTP(
self.config['email']['smtp_server'],
int(self.config['email']['smtp_port'])
) as server:
server.starttls()
server.login(
self.config['email']['sender'],
self.config['email']['password']
)
server.send_message(msg)
def generate_html(self, data):
"""生成HTML表格"""
html = '''<html><body>
<h2>MySQL表增长周报 TOP50</h2>
<table border="1" cellpadding="5">
<tr>
<th>数据库</th>
<th>表名</th>
<th>记录数</th>
<th>数据容量(MB)</th>
<th>索引容量(MB)</th>
</tr>'''
for row in data:
html += f'''
<tr>
<td>{row[0]}</td>
<td>{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
<td>{row[4]}</td>
</tr>'''
html += "</table></body></html>"
return html
if __name__ == "__main__":
monitor = TableMonitor()
monitor.collect_stats()
report_data = monitor.generate_report()
html = monitor.generate_html(report_data)
monitor.send_email(html)
四、关键实现说明
-
配置化管理:
- 使用configparser管理数据库连接、邮件服务等配置21
- 不同环境只需修改配置文件,无需修改代码
-
统计逻辑:
- 通过information_schema获取表统计信息61
- 计算周增长使用SQLite的时间窗口查询
-
存储设计:
-
邮件生成:
- 采用MIMEText生成HTML邮件51
- 表格样式兼容主流邮件客户端
-
性能优化:
- 使用带缓存的MySQL连接池
- SQLite采用批量提交事务
五、部署运行建议
- 配置定时任务(crontab):
# 每天凌晨执行统计
0 0 * * * /usr/bin/python3 /path/to/mysql_table_stats.py
- 初始化SQLite数据库:
sqlite3 statistics.db
> .schema # 验证表结构