查询期间与MySQL服务器的连接丢失

时间:2009-12-10 23:29:47

标签: python mysql

我有一个庞大的表,我需要处理其中的所有行。我总是得到这个丢失的连接消息,我无法重新连接并将光标恢复到它的最后位置。这基本上就是我在这里的代码:

#
import MySQLdb

class DB:
  conn = None

  def connect(self):
    self.conn = MySQLdb.connect('hostname', 'user', '*****', 'some_table', cursorclass=MySQLdb.cursors.SSCursor)

  def query(self, sql):
    try:
     cursor = self.conn.cursor()
     cursor.execute(sql)
   except (AttributeError, MySQLdb.OperationalError):
     self.connect()
     cursor = self.conn.cursor()
     cursor.execute(sql)
   return cursor
#

#
db = DB()
sql = "SELECT bla FROM foo"
data = db.query(sql)

for row in data:
    do_something(row)
#

但我总是得到这个:

#
Traceback (most recent call last):
  File "teste.py", line 124, in <module>
   run()
 File "teste.py", line 109, in run
   for row in data:
 File "/usr/lib64/python2.5/site-packages/MySQLdb/cursors.py", line 417, in next
   row = self.fetchone()
 File "/usr/lib64/python2.5/site-packages/MySQLdb/cursors.py", line 388, in fetchone
   r = self._fetch_row(1)
 File "/usr/lib64/python2.5/site-packages/MySQLdb/cursors.py", line 285, in _fetch_row
   return self._result.fetch_row(size, self._fetch_type)
   _mysql_exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query')
    Exception _mysql_exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query') in <bound method SSCursor.__del__ of <MySQLdb.cursors.SSCursor object at 0x7f7e3c8da410>> ignored
#

你有什么想法吗?

19 个答案:

答案 0 :(得分:39)

mysql文档有一整页专用于此错误: http://dev.mysql.com/doc/refman/5.0/en/gone-away.html

值得注意的是

  • 如果向服务器发送不正确或过大的查询,也可能会出现这些错误。如果mysqld收到的数据包太大或无序,则会假定客户端出现问题并关闭连接。如果需要大查询(例如,如果使用大型BLOB列),则可以通过设置服务器的max_allowed_pa​​cket变量来增加查询限制,该变量的默认值为1MB。您可能还需要增加客户端的最大数据包大小。有关设置数据包大小的更多信息,请参见第B.5.2.10节“数据包太大”。

  • 您可以通过使用--log-warnings = 2选项启动mysqld来获取有关丢失连接的更多信息。这会记录hostname.err文件中的一些断开连接的错误

答案 1 :(得分:18)

有三种方法可以放大mysql服务器的max_allowed_pa​​cket:

  1. 更改mysql服务器计算机上文件max_allowed_packet=64M中的/etc/mysql/my.cnf并重新启动服务器
  2. 在mysql服务器上执行sql:set global max_allowed_packet=67108864;
  3. Python在连接到mysql后执行sql:
  4.   

    connection.execute('set max_allowed_pa​​cket = 67108864')

答案 2 :(得分:12)

确保在连接前关闭光标。我用这个解决了我的问题:

if cur and con:                        
    cur.close() 
    con.close() 

答案 3 :(得分:8)

您需要增加连接的超时。如果您出于某种原因不能或不想这样做,可以尝试致电:

data = db.query(sql).store_result()

这将立即获取所有结果,然后您的连接将不会超时迭代它们。

答案 4 :(得分:7)

  

您也可以在分叉子进程的应用程序中遇到此错误,所有这些应用程序都尝试使用与MySQL服务器相同的连接。通过为每个子进程使用单独的连接可以避免这种情况。

福克斯可能会打你。但请注意不要在这种情况下。

答案 5 :(得分:5)

我的情况是

的原因
  

错误2013(HY000):查询期间与MySQL服务器的连接丢失

错误是我的表格部分已损坏。我也无法mysqldump我的桌子,因为有些行打破了它。 该错误与如上所述的任何存储器问题等无关。

好消息是,MySQL向我返回了行号,这是第一个失败的行号。这就像

  

mysqldump:错误2013:在行中转储表mytable时查询期间与MySQL服务器的连接丢失:12723

解决方案是将数据复制到新表中。在我的情况下,我丢失了10行数据,因为我不得不跳过这些损坏的行。首先,我创建了一个“tmp”表,其中包含旧表的模式。 SHOW CREATE TABLE是你的朋友。 E.g。

SHOW CREATE TABLE mydatabase.mytable;

随着我创建了新表。我们称之为 mytabletmp 。然后通过例如复制您能够复制的行。

insert into mysqltabletmp select * from mytable where id < 12723;
insert into mysqltabletmp select * from mytable where id > 12733;

在删除旧表之后,将tmp-table重命名为旧表名。

此问题也有some nice Information from Peter

答案 6 :(得分:2)

将“max_allowed_pa​​cket”设置为64M并重新启动MySql服务器。如果这没有解决您的问题,问题可能在其他地方。

我有一个多线程PHP CLI应用程序,可以同时进行查询,我最近注意到了这个问题。现在很明显,MySql服务器将来自同一IP的所有连接视为“单个”连接,因此只要单个查询完成就会丢弃所有连接。

我想知道有没有办法让MySql允许来自同一IP的100个连接,并将每个连接视为单独的连接。

答案 7 :(得分:1)

当我尝试更新磁盘大小超过可用磁盘空间的表时,发生了这种情况。对我来说,解决方案只是增加可用磁盘空间。

答案 8 :(得分:1)

我也遇到过类似的问题。在我的情况下,它通过以这种方式获取光标来解决:

cursor = self.conn.cursor(buffered=True)

答案 9 :(得分:1)

如果有人或某事使用KILL command终止你的连接,也会发生这种情况。

答案 10 :(得分:1)

我和mariadb发生了这种情况,因为我将一个varchar(255)列设为unique key ..猜测这个列太重了,因为插页已超时。

答案 11 :(得分:0)

在我的情况下,我在采购SQL转储时遇到了这个问题,该转储将表放在错误的顺序中。有问题的CREATE包括一个CONSTRAINT ... REFERENCES引用了尚未创建的表。

我找到了有问题的表,并将其CREATE语句移到了违规表上方,错误消失了。

我遇到的与此错误转储有关的另一个错误是ERROR 1005 / errno:150 - “无法创建表”,再次表示无序创建表。

答案 12 :(得分:0)

当我的hasSSE名称与其他CONSTRAINT名称具有相同名称时,就会发生这种情况。

更改我的CONSTRAINT名称解决了这个问题。

答案 13 :(得分:0)

多处理和Django DB不能很好地协同工作。

我最终在新进程中关闭了Django数据库连接。

这样一个人就不会引用父级使用的连接。

from multiprocessing import Pool

multi_core_arg = [[1,2,3], [4,5,6], [7,8,9]]
n_cpu = 4
pool = Pool(n_cpu)
pool.map(_etl_, multi_core_arg)
pool.close()
pool.join()

def _etl_(x):
    from django.db import connection 
    connection.close() 
    print(x)

OR

Process.start()调用以

开头的函数

其他一些建议使用

from multiprocessing.dummy import Pool as ThreadPool

它解决了我的(2013年,Lost连接)问题,但线程使用GIL,在执行IO时,将在IO完成时释放它。

相比之下,Process产生了一组彼此沟通的工作者,这可能会更慢。

我建议你定时。 侧面提示是使用由scikit-learn项目支持的joblib。 一些性能结果显示它执行本机Pool()..虽然它让编码人员有责任验证真正的运行时间成本。

答案 14 :(得分:0)

我遇到了同样的问题。由于其他一些问题,我试图在其他函数中添加cnx.close()行。相反,我删除了所有这些无关的关闭并设置我的类:

class DBase:

config = {
      'user': 'root',
      'password': '',
      'host': '127.0.0.1',
      'database': 'bio',
      'raise_on_warnings': True,
      'use_pure': False,
      }

def __init__(self):
    import mysql.connector
    self.cnx = mysql.connector.connect(**self.config)
    self.cur = self.cnx.cursor(buffered=True)
    print(self.cnx)
def __enter__(self):
    return DBase()

def __exit__(self, exc_type, exc_val, exc_tb):
    self.cnx.commit()
    if self.cnx:
        self.cnx.close()

在此类中调用的任何函数都是连接,提交和关闭。

答案 15 :(得分:0)

当我尝试对数百万条记录进行批量插入时,出现“断线”错误。我最终解决了此问题,方法是将数据分成较小的批处理大小,然后针对需要执行的每个插入操作,使用mysql游标运行executemany命令。这解决了问题,并且似乎没有以任何明显的方式影响性能。

例如

def chunks(data):
    for i in range(0, len(data), CHUNK_SIZE):
        yield data[i:i + CHUNK_SIZE]


def bulk_import(update_list):
    new_list = list(chunks(update_list))
    for batch in new_list:
         cursor.execute(#SQL STATEMENT HERE)

答案 16 :(得分:0)

与@imxylz相同,但是我不得不使用[3, 7, 11, 15, 19, ... ],因为我收到一个只读错误,没有使用GLOBAL参数。

mycursor.execute('set GLOBAL max_allowed_packet=67108864')

8.0.16

答案 17 :(得分:-1)

非常简单的解决方法,转到您的phpadmin的控制面板,然后单击config /,然后编辑您看到的.ini文件。如果不是用于连接的端口,请查找端口3306,将3306更改为正在使用的端口。在登录屏幕上,只需将localhost作为服务器,将端口(如果不是默认端口),或者未按原样在sql配置leavit中更改文件名my.ini。然后输入您的用户名:root或您创建的用户名,然后输入密码:1234或您分配的用户名。如果您正在连接本地,请不要检查url选项。然后输入您要编辑的数据库的名称。注意:建立连接后,您将看到服务器或要连接到的服务器上的数据库列表。

答案 18 :(得分:-1)

我在使用 mariadb sqlalchemypandas 时遇到了同样的情况,就像上面的 @iamapotatoe 一样,我还创建了一个函数来将数据帧分解为块并一点一点地将它们移植到 sql 数据库中。 这可以在更改 mysql 配置选项中的 max_allowed_packet 对您不起作用时特别有用。

def load_large_df(table_name,df_to_load,batch_size,engine):
    df_to_load = df_to_load.dropna(how='all')
    with engine.connect() as conn:
        conn.execute(f"DROP TABLE IF EXISTS {table_name}")
        rows = df_to_load.shape[0]
        batch = int(rows/batch_size)
        

        strt = 0
        while strt < rows:
            df = df_to_load[strt:].head(batch)
            df.to_sql(table_name,con=conn,if_exists='append')
            strt += batch