PyMySQL执行大表关联查询远慢于Navicat,有什么优化方法?
PyMySQL关联查询耗时过高优化方案
更换服务端游标避免全量结果拉取
PyMySQL默认使用客户端缓冲游标,执行execute时会将SQL的全部查询结果一次性拉取到客户端内存。你的两张表关联后结果集量级接近300万条,全量拉取自然会导致execute阶段耗时极高。而Navicat默认采用分页拉取逻辑,仅加载当前需要展示的少量数据,所以执行速度更快。
解决方案是使用PyMySQL内置的SSCursor(服务端游标),结果集将按需分批从服务端拉取,不会一次性加载全量数据:
import pymysql from pymysql.cursors import SSCursor # 建立连接时指定游标类,同时可开启compress压缩减少传输耗时 conn = pymysql.connect( host='你的数据库地址', user='用户名', password='密码', database='库名', cursorclass=SSCursor, compress=True ) self.cursor = conn.cursor()
注意:SSCursor要求当前结果集完全遍历前不能执行新的SQL,且连接需保持活跃状态。
新增覆盖索引避免全表扫描
如果关联字段没有索引会触发全表扫描,进一步拉高查询耗时。你可以给关联字段加索引,同时建立联合索引覆盖查询字段,避免回表查询:
-- 确认employees表的emp_no为主键,如未设置先添加主键 ALTER TABLE employees ADD PRIMARY KEY (emp_no); -- 给salaries表添加联合索引,直接覆盖关联字段和查询字段 ALTER TABLE salaries ADD INDEX idx_emp_salary (emp_no, salary);
添加完成后可执行EXPLAIN语句确认执行计划已经走索引:
EXPLAIN SELECT e.emp_no, first_name,last_name, salary from employees e JOIN salaries s on e.emp_no=s.emp_no;
按需查询避免加载冗余数据
你当前的逻辑是执行全量查询后再用fetchmany(100)取前100条,属于无效资源浪费。如果仅需要100条数据,直接在SQL中添加LIMIT 100,数据库仅返回100条结果,耗时可直接降到毫秒级:
self.cursor.execute("SELECT e.emp_no, first_name,last_name, salary from employees e JOIN salaries s on e.emp_no=s.emp_no LIMIT 100") page_data = self.cursor.fetchall()
如果是分页查询场景,可使用LIMIT 偏移量, 分页大小语法,偏移量过大时可改用基于上一页最后一条记录的游标分页方案进一步优化。
升级驱动提升性能
你当前使用的PyMySQL 0.10.1为较老的纯Python实现版本,本身性能存在优化空间,可先升级到最新稳定版。如果对性能要求更高,可替换为C语言实现的mysqlclient驱动,同场景下性能比PyMySQL高3~5倍。
内容的提问来源于stack exchange,提问作者caiyi0923
相关产品推荐
相关产品推荐

