web-dev-qa-db-fra.com

Connection au serveur MySQL perdue pendant la requête

J'ai une table énorme et je dois traiter toutes les lignes qu'elle contient. Je reçois toujours ce message de connexion perdue et je ne parviens pas à me reconnecter et à rétablir le curseur à la dernière position. Ceci est fondamentalement le code que j'ai ici:

#
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)
#

Mais j'obtiens toujours ceci:

#
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
#

Avez-vous une idée?

47
Otavio

Les documents mysql ont une page entière dédiée à cette erreur: http://dev.mysql.com/doc/refman/5.0/fr/gone-away.html

à noter sont

  • Vous pouvez également obtenir ces erreurs si vous envoyez au serveur une requête incorrecte ou trop volumineuse. Si mysqld reçoit un paquet trop volumineux ou en panne, il suppose que quelque chose ne va pas avec le client et ferme la connexion. Si vous avez besoin de grandes requêtes (par exemple, si vous travaillez avec de grandes colonnes BLOB), vous pouvez augmenter la limite de requête en définissant la variable max_allowed_packet du serveur, dont la valeur par défaut est 1 Mo. Vous devrez peut-être également augmenter la taille de paquet maximale du côté client. Pour plus d'informations sur le réglage de la taille du paquet, reportez-vous à la Section B.5.2.10, «Paquet trop volumineux».

  • Vous pouvez obtenir plus d'informations sur les connexions perdues en démarrant mysqld avec l'option --log-warnings = 2. Cela enregistre certaines des erreurs déconnectées dans le fichier hostname.err

39
Mark Carey

Il y a trois façons d’agrandir le max_allowed_packet du serveur mysql:

  1. Changez max_allowed_packet=64M dans le fichier /etc/mysql/my.cnf sur le serveur mysql et redémarrez le serveur.
  2. Exécutez SQL sur le serveur mysql: set global max_allowed_packet=67108864;
  3. Python exécute SQL après la connexion au mysql: 

connection.execute ('set max_allowed_packet = 67108864')

17
imxylz

Assurez-vous de fermer le curseur avant la connexion. J'ai résolu mon problème avec ceci:

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

Vous devez augmenter le délai d’expiration de votre connexion. Si vous ne pouvez pas ou ne voulez pas faire cela pour une raison quelconque, vous pouvez essayer d'appeler:

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

Tous les résultats seront immédiatement récupérés, puis votre connexion n'expirera pas au milieu de leur itération.

8
Mark Byers

Vous pouvez également rencontrer cette erreur avec des applications créant des processus enfants, qui essaient toutes d'utiliser la même connexion au serveur MySQL. Cela peut être évité en utilisant une connexion distincte pour chaque processus enfant.

Forks pourrait vous frapper. Attention cependant pas dans ce cas.

7
xvga

Je mon cas la raison de la 

ERROR 2013 (HY000): Connexion perdue au serveur MySQL lors d'une requête

l’erreur était que certaines parties de ma table étaient corrompues. Je ne pouvais pas non plus mysqldump ma table car certaines lignes l'avaient cassée . L'erreur n'était liée à aucun problème de mémoire, etc., comme mentionné ci-dessus. 

Le truc sympa, c’est que MySQL m’a renvoyé le numéro de la rangée qui a été le premier à échouer. C'était quelque chose comme

mysqldump: Erreur 2013: Connexion perdue avec le serveur MySQL lors d'une requête lors du vidage de la table

La solution consistait à copier les données dans une nouvelle table. Dans mon cas, j'ai perdu 10 lignes de données parce que je devais ignorer ces lignes corrompues. J'ai d'abord créé une table "tmp" avec le schéma de l'ancien. SHOW CREATE TABLE est votre ami ici. Par exemple.

SHOW CREATE TABLE mydatabase.mytable;

Avec le j'ai créé la nouvelle table. Appelons cela mytabletmp. Ensuite, copiez les lignes que vous pouvez copier via, par exemple,.

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

Après cette suppression de l'ancienne table, renommez tmp-table en l'ancien nom de la table.

Il y a aussi quelques belles informations de Peter concernant ce problème.

5
H6.

Définissez le paramètre 'max_allowed_packet' sur 64 Mo et redémarrez votre serveur MySql. Si cela ne résout pas vos problèmes, le problème peut être ailleurs.

J'ai une application CLI multi-thread PHP qui effectue des requêtes simultanées et j'ai récemment remarqué ce problème. Il est maintenant évident pour moi que le serveur MySql considère toutes les connexions de la même adresse IP comme une connexion "unique" et supprime donc toutes les connexions à la fin d'une requête.

Je me demande cependant qu’il existe un moyen de permettre à MySql d’autoriser 100 connexions à partir du même IP et de considérer chaque connexion comme une connexion individuelle.

2
NiX

Cela peut également arriver si quelqu'un ou quelque chose tue votre connexion à l'aide de la commande KILL .

1
Sam Brightman

J'ai rencontré des problèmes similaires aussi. Dans mon cas, le problème a été résolu en plaçant le curseur de la manière suivante:

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

Cela m'est arrivé lorsque j'ai essayé de mettre à jour une table dont la taille sur le disque était supérieure à l'espace disque disponible. La solution pour moi était simplement d'augmenter l'espace disque disponible.

1
e18r

Cela m’arrivait avec mariadb parce que j’avais fait de la colonne varchar(255) un unique key .. je suppose que c’était trop lourd pour un exemplaire unique, car l’insert arrivait à expiration.

1
Amalgovinus

Dans mon cas, j’ai rencontré ce problème lors de la recherche d’un dump SQL qui avait placé les tables dans le mauvais ordre. CREATE en question incluait un CONSTRAINT ... REFERENCES qui faisait référence à une table qui n'avait pas encore été créée.

J'ai localisé la table en question et déplacé son instruction CREATE au-dessus de celle incriminée, et l'erreur a disparu.

L’autre erreur que j’ai rencontrée à propos de ce dump défectueux est ERROR 1005/errno: 150 - "Can't create table", encore une fois, il s’agit de créer des tables en panne.

0
user3975359

Je rencontrais le même problème. En raison de certains problèmes, j'avais essayé d'ajouter une ligne cnx.close() à mes autres fonctions. Au lieu de cela, j'ai supprimé toutes ces fermetures superflues et configuré ma classe comme ceci:

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()

Toute fonction appelée dans cette classe est connecte, valide et ferme.

0
Mr Panda

J'avais cette erreur avec un "tuyau cassé" quand j'ai essayé de faire des insertions en bloc avec des millions d'enregistrements. J'ai fini par résoudre ce problème en découpant mes données en lots de tailles plus petites, puis en exécutant une commande executemany avec le curseur mysql pour chacune des insertions que je devais effectuer. Cela résout le problème et ne semble pas affecter la performance de manière notable. 

par exemple. 

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)
0
imapotatoe123

Cela m'est arrivé lorsque mon nom CONSTRAINT a le même nom avec un autre nom CONSTRAINT.

Changer mon nom CONSTRAINT a résolu ce problème.

0
tama

Le multitraitement et Django DB ne fonctionnent pas bien ensemble. 

J'ai fini par fermer la connexion à la base de données Django dans le nouveau processus. 

Donc, on n'aura aucune référence à la connexion utilisée par le parent. 

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() appelle une fonction qui commence par

Certains suggèrent d'utiliser 

from multiprocessing.dummy import Pool as ThreadPool

Cela a résolu mon problème (2013, perte de connexion), mais les threads utilisent GIL lors de l'exécution d'E/S pour le libérer lorsque IO se termine.

Comparativement, Process génère un groupe de travailleurs qui se communiquent, ce qui peut être plus lent.

Je vous recommande de le chronométrer . Un conseil supplémentaire est d'utiliser joblib qui est soutenu par scikit-learn project ..__ la responsabilité du codeur de vérifier le coût réel du temps d’exécution.

0
CodeFarmer