【问题标题】:MySql FetchMany Memory IssuesMySql FetchMany 内存问题
【发布时间】:2015-02-20 17:04:30
【问题描述】:

我正在将数据从 Mysql 移动到 Postgres,我的代码如下 -

import os, re, time, codecs, glob, sqlite3
from StringIO import StringIO
import psycopg2, MySQLdb, datetime, decimal
from datetime  import date
import gc

tables = (['table1' , 27],)
conn = psycopg2.connect("dbname='xxx' user='xxx' host='localhost' password='xxx' ")
curpost = conn.cursor()
db = MySQLdb.connect(host="127.0.0.1", user="root", passwd="root" , unix_socket='/var/mysql/mysql.sock', port=3306 )
cur = db.cursor() 
cur.execute('use xxx;')

for t in tables:
    print t
    curpost.execute( "truncate table " + t[0] )
    cur.execute("select * from "+ t[0] )
    a = ','.join( '%s' for i in range(t[1]) )
    qry = "insert into " + t[0]  + " values ( " + a +" )" 
    print qry
    i = 0
    while True:
        rows = cur.fetchmany(5000)
        if not rows: break
        string = ''
        for row in rows:
            string = string +  ('|'.join([str(x) for x in row])) + "\n"                
        curpost.copy_from(StringIO(string),  t[0], sep="|", null="None" )
        i += curpost.rowcount
        print i  , " loaded"
        curpost.connection.commit()        
        del string, row, rows
        gc.collect()        

curpost.close()
cur.close()

对于小表,代码运行良好。然而,较大的记录(360 万条记录),当 mysql 执行 (cur.execute("select * from "+ t[0] )) 运行时,机器上的内存利用率会增加。即使我使用了 fetchmany 并且记录应该只分批 5000 条。我也尝试过 500 条记录,它是一样的。对于大表来说,fetchmany 似乎没有像记录的那样工作..

编辑 - 我添加了垃圾收集和 del 语句。直到所有记录都没有被处理,内存仍然会一直膨胀。

有什么想法吗?

【问题讨论】:

  • 现在 20 分钟,RAM 使用量约为 4 GB,甚至没有处理 5000 条记录 :-(
  • 你说的没有按文档工作是什么意思你能给我一个链接吗?
  • 我所说的记录的意思是内存只能用于 5000 条记录的批次中。 Python 进程不断累积内存.. 似乎它获取了所有 360 万条记录而不是进行 fetchmany
  • 所以我之前看到了那个链接 - 没有关于内存使用的内容 - 函数只返回询问的行数。因此,如果您关心内存使用并且发现了这个错误,最好将查询更改为使用LIMIT 语句

标签: python mysql mysql-python


【解决方案1】:

对不起,如果我错了,你说过你不想改变查询

但万一你别无选择,你可以试试:

替换这个片段:

cur.execute("select * from "+ t[0] )
a = ','.join( '%s' for i in range(t[1]) )
qry = "insert into " + t[0]  + " values ( " + a +" )" 
print qry
i = 0
while True:
        rows = cur.fetchmany(5000)

到这个:

a = ','.join( '%s' for i in range(t[1]) )
qry = "insert into " + t[0]  + " values ( " + a +" )" 
print qry
i = 0
while True:
    cur.execute("select * from "+ t[0]+" LIMIT "+i+", 5000")
    rows = cur.fetchall()

【讨论】:

  • MySql 会维护行号的神圣性吗?我之前做过很多 oracle,从不依赖 db 提供的任何排序。否则我会转移骗子。
  • 为确保您自己可以添加“ORDER BY”,但如果您的表格内容在其他用户循环期间没有更改,则通常不需要。如果需要,您可以先开始事务...但是查看您的代码,我认为您正在尝试转换一些数据,因此数据源几乎是静态的。试试我的方法
  • 刚刚得到结果。限制工作.. 我得到了 5000 条记录,平均内存约为 100MB。并且它达到了 45000 条具有相同内存的已提交记录
  • 一个问题 - 为什么 Python 在处理完 fetchmany 记录后不释放它们。旧方式的记忆不断膨胀。此外,Order by 只能与 fetchmany 一起使用。如果它是像 DB 一样的 Oracle,并且如果我使用了 50 个 Order by 查询,每个查询中都带有行号过滤器,那么 DBA 会打我的头。
  • 我不是 100% 理解你想说的话。 LIMIT,ORDER BY是sql的常规语句,我对oracle不是很熟悉。但我很确定——根据需要使用这些语句并没有错。如果我们谈论fetchmany 低级内存使用。我猜你的内存不是fetchmany使用的,而是cur.execute在mysql将所有数据返回给python时使用的。检查 - 尝试 sleep 或在 .execute 之后循环 10000000 并检查您的内存使用情况
猜你喜欢
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 2014-08-21
  • 1970-01-01
相关资源
最近更新 更多