4. 数据源集成(一):关系型数据库 MySQL
在实时监控大屏项目中,MySQL 是最常用的持久化数据源之一。本节将系统讲解从 MySQL 建表、Python 连接(pymysql / SQLAlchemy)到数据读取并转为 DataFrame 的完整链路,为后续数据清洗与可视化提供基础。
4.1 MySQL 建表语句与字段设计
监控大屏的数据通常包含时间戳、指标值、设备/业务标识等核心字段。以下是一个典型的服务器性能监控表建表语句:
CREATE TABLE server_monitor (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
server_ip VARCHAR(15) NOT NULL COMMENT '服务器IP',
cpu_usage DECIMAL(5,2) NOT NULL COMMENT 'CPU使用率(%)',
mem_usage DECIMAL(5,2) NOT NULL COMMENT '内存使用率(%)',
disk_io DECIMAL(10,2) NOT NULL COMMENT '磁盘IO (MB/s)',
net_in BIGINT NOT NULL COMMENT '网络入流量 (bytes)',
net_out BIGINT NOT NULL COMMENT '网络出流量 (bytes)',
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1正常 0异常',
record_time DATETIME NOT NULL COMMENT '采集时间',
INDEX idx_time (record_time),
INDEX idx_ip_time (server_ip, record_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务器实时监控数据表';
字段设计要点:
- 使用
DATETIME而非时间戳整数,便于 SQL 直接按时间范围查询。 - 为
record_time和(server_ip, record_time)建立索引,加速大屏按时间/服务器筛选。 - 状态字段使用
TINYINT而非VARCHAR,节省存储且查询更快。
4.2 Python 连接 MySQL:两种主流方式
Python 生态中连接 MySQL 最常用的两个库是 pymysql(纯 Python 实现)和 SQLAlchemy(ORM 框架)。下表对比了它们的核心差异:
| 特性 | pymysql | SQLAlchemy |
|---|---|---|
| 类型 | 纯 Python 数据库驱动 | ORM + 连接池 + SQL 抽象层 |
| 安装 | pip install pymysql |
pip install sqlalchemy |
| 连接方式 | 直接执行原生 SQL | 通过 Engine / Session 操作 |
| 返回结果 | 元组或字典 | ORM 对象或 Row 对象 |
| 与 pandas 集成 | 需手动构建 DataFrame | pd.read_sql() 原生支持 |
| 适用场景 | 轻量脚本、快速查询 | 大型项目、ORM 管理、连接池 |
4.2.1 使用 pymysql 连接
import pymysql
# 建立连接
conn = pymysql.connect(
host='localhost',
port=3306,
user='monitor_user',
password='your_password',
database='monitor_db',
charset='utf8mb4'
)
# 创建游标,返回字典格式
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 执行查询
cursor.execute("SELECT * FROM server_monitor WHERE record_time >= %s", ('2025-01-01 00:00:00',))
rows = cursor.fetchall()
# 关闭连接
cursor.close()
conn.close()
4.2.2 使用 SQLAlchemy 连接
from sqlalchemy import create_engine, text
# 创建引擎(连接池)
engine = create_engine(
'mysql+pymysql://monitor_user:your_password@localhost:3306/monitor_db?charset=utf8mb4',
pool_size=5,
max_overflow=10
)
# 执行原生 SQL
with engine.connect() as conn:
result = conn.execute(
text("SELECT * FROM server_monitor WHERE record_time >= :time"),
{"time": "2025-01-01 00:00:00"}
)
rows = result.fetchall()
安全提示:生产环境中切勿在代码中硬编码数据库密码。建议使用环境变量或密钥管理服务(如 AWS Secrets Manager、Vault)动态获取凭据。
4.3 读取数据并转为 DataFrame
pandas 的 read_sql() 函数可以直接将 SQL 查询结果转换为 DataFrame,是数据集成中最核心的一步。以下展示两种连接方式下的转换方法:
4.3.1 基于 pymysql 连接
import pandas as pd
import pymysql
conn = pymysql.connect(
host='localhost', user='monitor_user',
password='your_password', database='monitor_db',
charset='utf8mb4'
)
df = pd.read_sql(
"SELECT * FROM server_monitor WHERE record_time >= %(time)s",
con=conn,
params={"time": "2025-01-01 00:00:00"}
)
conn.close()
print(df.head())
4.3.2 基于 SQLAlchemy 引擎(推荐)
import pandas as pd
from sqlalchemy import create_engine, text
engine = create_engine(
'mysql+pymysql://monitor_user:your_password@localhost:3306/monitor_db?charset=utf8mb4'
)
query = """
SELECT server_ip, cpu_usage, mem_usage, record_time
FROM server_monitor
WHERE record_time BETWEEN :start AND :end
ORDER BY record_time
"""
df = pd.read_sql(
sql=text(query),
con=engine,
params={"start": "2025-01-01 00:00:00", "end": "2025-01-02 00:00:00"}
)
print(f"读取 {len(df)} 条记录,内存占用约 {df.memory_usage(deep=True).sum() / 1024:.1f} KB")
最佳实践:
- 始终使用 SQLAlchemy 作为连接方式,它天然支持连接池、事务管理和 pandas 原生集成。
- 查询时尽量使用 参数化查询(
:param或%(name)s),避免 SQL 注入风险。 - 对于大表,建议在 SQL 层面先做 时间过滤 和 列裁剪,减少数据传输量。
4.4 数据集成流程架构
下图展示了从 MySQL 到 DataFrame 的完整数据集成链路,包含连接建立、查询执行、结果转换三个核心阶段:
4.5 常见问题与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 防火墙未放通 3306 端口;MySQL 未开启远程访问 | 检查安全组规则;修改 bind-address 为 0.0.0.0 |
| 认证失败 | 密码错误;用户无对应数据库权限 | 使用 GRANT ALL ON monitor_db.* TO 'user'@'%'; 授权 |
| 字符集乱码 | 连接未指定 charset='utf8mb4' |
连接字符串添加 ?charset=utf8mb4 |
| DataFrame 为空 | SQL 条件过滤后无数据;表名或字段名错误 | 先在 MySQL 客户端执行相同 SQL 验证 |
| 内存溢出 | 一次性读取全表数据量过大 | 使用 chunksize 参数分批读取 |
性能优化建议:当监控表数据量超过百万行时,建议使用
pd.read_sql(..., chunksize=10000) 分批读取,避免一次性加载导致内存爆炸。同时确保查询条件命中索引,减少全表扫描。