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

前文

  同事反馈执行下载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时再一并分享,这边就暂时说到这,谢谢观看。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值