Python mysql.connector取影响数据库行数报MemoryError解决方法

本文详细探讨了在使用Python从数据库下载大量数据时遇到MemoryError的问题。通过对比mysql.connector和pymysql库,介绍了如何优化affectedrows的获取,以及采用流式查询避免内存溢出的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前文

  同事反馈执行下载sql时返回500异常,上日志查看报了MemoryError,报错如下图:
在这里插入图片描述  赶紧查了下系统的内存可用,发现只有200M可用,当下载行数超过5w行就GG了,查看报错发现在cursor.fetchall()出错,google了才知道cursor.fetchall()和cursor.fetchone()都是先从数据库读取到内存中,然后再返回,结果就造成MemoryError。

解决cursor.fetchall()

  首先解释下fetchall()取得数据是为了什么,实际上一开始只是为了取affected rows,也就是执行数据库所影响的行数,因为这个需求是先取得影响行数,然后跑工单,审批通过后才能下载。一开始也没想到后面需要下载几万条或者以上的数据,所以并没有针对取影响行数进行优化,另一方面python连接数据库用的是mysql.connector,这个是mysql官方推介的连接python库,结果并没有能直接获取affected rows的方法,查了官网,解释如下:
在这里插入图片描述
  标红框的说明如果不进行fetch操作,则无法获取rowcount,这个就比较尴尬了,而且网上普遍对pymysql的支持偏多,并且pymysql提供了affected_rows=cursor.execute(sql)就能返回影响行数,简直不要太友好,最后重写了mysql.connector的类,当然报了一系列错,不过跟着提示都能完成,这边就提个,mysql的连接游标分为两种形式,默认是取出的数据为元祖,另一种是取出的数据为字典,那一般为了项目取数据方便,用的是字典的方式,下面是mysql.connector和pymysql的写法:

pymysql:
	conn.cursor(cursor=pymysql.cursors.DictCursor)
mysql.connector:
	conn.cursor(dictionary=True)

  ok,affected rows用execute就能拿到,就避免了fetchall来取得,但是真正要下载的时候还是绕不过去。查找网上的解决方法,普遍推介用流式查询避免MemoryError,那基本代码如下:

import pymysql
#config 即是host、port、user、pass、database
conn = pymysql.connect(**config)
cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
cur.execute("sql");
row = cur.fetchone()
while row is not None:
    do something...
    row = cur.fetchone()
 
cur.close()
conn.close(

标准代码如上,那流式查询的好处是:

非流式查询:内存会随着查询记录的增长而近乎直线增长。
流式查询:内存会保持稳定,不会随着记录的增长而增长。其内存大小取决于批处理大小

  最后我也是用了该查询来完成下载,但是因为下载本身用到了StreamingHttpResponse和yield来搭配下载,导致上述代码中的do something很不好处理,不过万幸还是处理好了,这个待下次分享用python来下载数据库的数据并转化成txt、csv、excel时再一并分享,这边就暂时说到这,谢谢观看。

<think>好的,我现在需要回答用户的问题:“可以使用Python去链接SQL数据库,然后用Python的编程语言处理SQL的问题吗”。用户之前已经询问过如何用SQL查询薪资低于部门平均的员工ID,现在转向Python与SQL的交互。 首先,我需要确认用户的需求。他们可能想了解如何将Python与SQL结合使用,可能是在自动化数据处理、数据分析或应用开发中。用户可能已经熟悉SQL,现在想利用Python的灵活性来处理数据库任务,或者希望将数据库操作整合到Python脚本中。 接下来,我需要整理Python连接SQL数据库的基本步骤。常见的方法包括使用不同的库,比如sqlite3(适用于SQLite)、PyMySQLMySQL)、psycopg2(PostgreSQL)等。用户可能需要知道如何安装这些库,建立连接,执行查询,处理结果以及关闭连接。 同时,用户可能关心如何处理参数化查询,避免SQL注入,以及使用ORM(如SQLAlchemy)简化操作。此外,事务管理、错误处理以及性能优化(如使用上下文管理器、连接池)也是重要点。 需要确保回答结构清晰,分步骤说明,并提供示例代码。例如,连接SQLite的示例,执行之前提到的部门平均薪资查询,并将结果用Python处理。还要提到常见库和适用场景,帮助用户根据实际情况选择工具。 另外,用户可能对使用Pandas进行数据分析感兴趣,所以可以提到结合pandas.read_sql_query的方法,方便数据处理。最后,强调安全性和最佳实践,比如使用环境变量存储敏感信息,避免在代码中硬编码密码。 总结回答结构:先肯定回答,然后分步骤介绍连接过程、常用库、示例代码、结合数据处理(如Pandas),以及注意事项。确保语言简洁,示例明确,覆盖用户可能的需求点。</think>可以使用Python连接SQL数据库并处理SQL操作。这是通过数据库驱动库实现的,以下是完整实现方案: **一、连接数据库的通用步骤** 1. 安装对应驱动库(根据数据库类型选择): ```bash # MySQL pip install pymysql # PostgreSQL pip install psycopg2 # SQL Server pip install pyodbc # SQLite(内置无需安装) ``` 2. 基础连接模板: ```python import mysql.connector # 以MySQL为例 # 创建连接 conn = mysql.connector.connect( host='localhost', user='your_username', password='your_password', database='your_database' ) # 创建游标 cursor = conn.cursor() # 执行SQL查询(示例:获部门平均薪资) cursor.execute(""" SELECT 部门, AVG(员工薪资) FROM 员工表 GROUP BY 部门 """) # 获结果 results = cursor.fetchall() for row in results: print(f"部门:{row[0]},平均薪资:{row[1]}") # 关闭连接 cursor.close() conn.close() ``` **二、处理你之前的SQL需求** 实现部门薪资过滤的完整Python方案: ```python import sqlite3 # 使用SQLite示例 def find_low_salary_employees(): # 建立内存数据库连接 conn = sqlite3.connect(':memory:') cursor = conn.cursor() # 创建测试表 cursor.execute('''CREATE TABLE 员工表( 部门 TEXT, 员工ID TEXT, 员工薪资 INTEGER)''') # 插入测试数据 test_data = [ ('技术部', '001', 8000), ('技术部', '002', 10000), ('市场部', '003', 6000) ] cursor.executemany('INSERT INTO 员工表 VALUES (?,?,?)', test_data) # 执行关联查询 query = ''' SELECT e.员工ID FROM 员工表 e INNER JOIN ( SELECT 部门, AVG(员工薪资) as avg_salary FROM 员工表 GROUP BY 部门 ) d ON e.部门 = d.部门 WHERE e.员工薪资 < d.avg_salary''' cursor.execute(query) results = cursor.fetchall() # 输出结果 print("薪资低于部门平均的员工ID:") for emp in results: print(emp[0]) conn.close() find_low_salary_employees() ``` **三、进阶功能实现** 1. **参数化查询(防止SQL注入)**: ```python dept = '技术部' cursor.execute( "SELECT * FROM 员工表 WHERE 部门 = %s", (dept,) # 注意参数必须是元组 ) ``` 2. **使用Pandas处理结果**: ```python import pandas as pd df = pd.read_sql(query, conn) low_salary_df = df[df['员工薪资'] < df.groupby('部门')['员工薪资'].transform('mean')] ``` 3. **事务管理**: ```python try: cursor.execute("UPDATE ...") cursor.execute("INSERT ...") conn.commit() # 提交事务 except: conn.rollback() # 回滚事务 ``` **四、性能优化方案** 1. 使用连接池(以PostgreSQL为例): ```python from psycopg2 import pool connection_pool = pool.SimpleConnectionPool( minconn=1, maxconn=10, host='localhost', # ...其他参数 ) conn = connection_pool.getconn() # 使用后归还连接 connection_pool.putconn(conn) ``` 2. 批量插入优化: ```python data_chunks = [tuple_list1, tuple_list2] # 分块数据 for chunk in data_chunks: cursor.executemany("INSERT ...", chunk) conn.commit() ``` **五、安全注意事项** 1. 敏感信息存储: ```python # 使用环境变量 import os DB_PASSWORD = os.getenv('DB_PASSWORD') ``` 2. 错误日志记录: ```python import logging logging.basicConfig(filename='db_errors.log') try: cursor.execute(query) except sqlite3.DatabaseError as e: logging.error(f"数据库错误:{str(e)}") ``` **六、不同数据库连接对比** | 数据库 | 驱动库 | 连接字符串示例 | |----------|----------------|----------------------------------------| | MySQL | `pymysql` | `mysql+pymysql://user:pass@host/db` | | PostgreSQL | `psycopg2` | `postgresql://user:pass@host/db` | | SQL Server | `pyodbc` | `mssql+pyodbc://user:pass@dsn` | | Oracle | `cx_Oracle` | `oracle+cx_oracle://user:pass@host/db` | **执行效果**(接前面的示例代码): ``` 薪资低于部门平均的员工ID: 001 ``` 通过Python操作SQL数据库,可以实现:自动化表生成、数据清洗流水线、Web应用后端数据处理等复杂场景。建议根据实际需求选择合适驱动库,并注意做好连接管理和异常处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值