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?
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
Il y a trois façons d’agrandir le max_allowed_packet du serveur mysql:
max_allowed_packet=64M
dans le fichier /etc/mysql/my.cnf
sur le serveur mysql et redémarrez le serveur.set global max_allowed_packet=67108864;
connection.execute ('set max_allowed_packet = 67108864')
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()
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.
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.
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.
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.
Cela peut également arriver si quelqu'un ou quelque chose tue votre connexion à l'aide de la commande KILL .
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)
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.
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.
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.
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.
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)
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.
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.