Потерянное соединение с сервером 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
#
Есть ли у вас идеи?
Ответы
Ответ 1
В документах mysql есть целая страница, посвященная этой ошибке:
http://dev.mysql.com/doc/refman/5.0/en/gone-away.html
примечания
-
Вы также можете получить эти ошибки, если вы отправляете запрос на сервер, который является неправильным или слишком большим. Если mysqld получает слишком большой или неправильный пакет, он предполагает, что что-то пошло не так с клиентом и закрывает соединение. Если вам нужны большие запросы (например, если вы работаете с большими столбцами BLOB), вы можете увеличить лимит запроса, установив переменную server max_allowed_packet, которая имеет значение по умолчанию 1 МБ. Вам также может потребоваться увеличить максимальный размер пакета на стороне клиента. Более подробная информация об установке размера пакета приведена в разделе B.5.2.10 "Слишком большой пакет".
-
Вы можете получить дополнительную информацию о потерянных подключениях, запустив mysqld с опцией -log-warnings = 2. Это регистрирует некоторые из отключенных ошибок в файле hostname.err
Ответ 2
Существует три способа увеличить max_allowed_packet сервера mysql:
- Измените
max_allowed_packet=64M
в файле /etc/mysql/my.cnf
на машине сервера mysql и перезапустите сервер
- Выполните sql на сервере mysql:
set global max_allowed_packet=67108864;
- Python выполняет sql после подключения к mysql:
connection.execute('set max_allowed_packet = 67108864')
Ответ 3
Перед подключением убедитесь, что вы закрыли курсор. Я решил проблему с этим:
if cur and con:
cur.close()
con.close()
Ответ 4
Вам нужно увеличить таймаут при подключении. Если вы не можете или не хотите делать это по какой-либо причине, вы можете попробовать позвонить:
data = db.query(sql).store_result()
Это приведет к немедленному отображению всех результатов, тогда ваше соединение не будет выходить на полпути через итерацию по ним.
Ответ 5
Вы также можете столкнуться с этой ошибкой с приложениями, которые выполняют дочерние процессы fork, все из которых пытаются использовать одно и то же соединение с сервером MySQL. Этого можно избежать, используя отдельное соединение для каждого дочернего процесса.
Форки могут поразить вас. Остерегайтесь не в этом случае.
Ответ 6
В моем случае причина для
ОШИБКА 2013 (HY000): Потерянное соединение с сервером MySQL во время запроса
Ошибка заключалась в том, что части моей таблицы были повреждены. Я также не смог mysqldump
мой стол, потому что некоторые строки сломали его.
Ошибка не связана с проблемами памяти и т.д., Как указано выше.
Хорошо, что MySQL вернул мне номер строки, который был первым, что не удалось. Это было что-то вроде
mysqldump: Ошибка 2013: потерянное соединение с сервером MySQL во время запроса при отправке таблицы mytable в строке: 12723
Решением было скопировать данные в новую таблицу. В моем случае я потерял 10 строк данных, потому что мне пришлось пропустить эти поврежденные строки. Сначала я создал таблицу "tmp" со схемой старого. SHOW CREATE TABLE
- ваш друг здесь. Например.
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-таблицу в имя старой таблицы.
Есть также некоторая хорошая информация из Peter относительно этой проблемы.
Ответ 7
Установите для параметра 'max_allowed_packet' значение 64M и перезапустите сервер MySql. Если это не устранило ваши проблемы, проблема может быть в другом месте.
У меня многопоточное приложение CLI для PHP, которое выполняет одновременные запросы, и я недавно заметил эту проблему. Теперь мне кажется очевидным, что сервер MySql рассматривает все подключения с одного и того же IP-адреса как "единственное" соединение и, следовательно, отбрасывает все соединения всякий раз, когда заканчивается один запрос.
Интересно, однако, что есть способ заставить MySql разрешить 100 подключений от одного и того же IP-адреса и рассматривать каждое соединение как индивидуальное соединение.
Ответ 8
Это происходило со мной с mariadb, потому что я сделал столбец varchar(255)
a unique key
.. предположил, что слишком тяжелый для уникального, так как вставка была отключена.
Ответ 9
Это также может произойти, если кто-то или что-то убивает ваше соединение, используя команду KILL.
Ответ 10
Это случилось со мной, когда я попытался обновить таблицу, размер которой на диске был больше, чем доступное дисковое пространство. Решение для меня было просто увеличить доступное дисковое пространство.
Ответ 11
Я тоже сталкивался с подобными проблемами. В моем случае это было решено, получив курсор таким образом:
cursor = self.conn.cursor(buffered=True)
Ответ 12
В моем случае я столкнулся с этой проблемой при поиске дампа SQL, который поместил таблицы в неправильном порядке. В вопросе CREATE включен CONSTRAINT... ССЫЛКИ, которые ссылаются на таблицу, которая еще не была создана.
Я нашел эту таблицу и переместил ее инструкцию CREATE выше оскорбительной, и ошибка исчезла.
Другая ошибка, с которой я столкнулся в этой неисправной дампе, была ERROR 1005/errno: 150 - "Невозможно создать таблицу", опять же вопрос о создании таблиц не в порядке.
Ответ 13
Это происходит со мной, когда мое имя CONSTRAINT
имеет одно и то же имя с другим именем CONSTRAINT
.
Изменение моего имени CONSTRAINT
решило это.
Ответ 14
Многопроцессорность и Django DB не работают хорошо.
В конечном итоге я закрыл соединение Django DB первым в новом процессе.
Таким образом, у вас не будет ссылок на соединение, используемое родителем.
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)
ИЛИ
Process.start()
вызывает функцию, начинающуюся с
Некоторые другие предлагают использовать
from multiprocessing.dummy import Pool as ThreadPool
Это решило мою проблему (2013, потерянное соединение), но поток использует GIL, делая IO, чтобы освободить его при завершении ввода-вывода.
Сравнительно, Process порождает группу работников, которые обмениваются друг с другом, что может быть медленнее.
Я рекомендую вам время.
Боковые подсказки - использовать joblib, который поддерживается проектом scikit-learn.
некоторые результаты производительности показывают, что он выполняет собственный пул().. хотя он оставляет ответственность за кодер, чтобы проверить истинную стоимость времени выполнения.
Ответ 15
Я столкнулся с той же проблемой. Из-за некоторых других проблем я попытался добавить строку 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()
Любая функция, вызываемая в этом классе, соединяется, совершает и закрывает.
Ответ 16
Я получал эту ошибку с "сломанным каналом", когда пытался выполнить массовые вставки с миллионами записей. В итоге я решил эту проблему, разбив данные на части меньшего размера, а затем запустив команду executemany с курсором mysql для каждой вставки, которую мне нужно было сделать. Это решило проблему и не оказало заметного влияния на производительность.
например.
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)
Ответ 17
Так же, как @imxylz, но мне пришлось использовать mycursor.execute('set GLOBAL max_allowed_packet=67108864')
поскольку я получил ошибку только для чтения без использования параметра GLOBAL.
mysql.connector.__version__
8.0.16
Ответ 18
очень просто решить, перейдите на панель управления вашего phpadmin и нажмите на config/, а затем отредактируйте INI файл, который вы видите. ищите порт 3306, если это не тот порт, который вы используете для подключения, измените 3306 на используемый вами порт. на экране входа в систему просто укажите localhost для вашего сервера, ваш порт, если он не используется по умолчанию или если вы не изменили имя файла my.ini в конфигурации sql, оставьте его как есть. затем введите свое имя пользователя: root или тот, который вы создали, затем пароль: 1234 или тот, который вы назначили. если вы подключаетесь локально, не проверяйте опцию url. затем введите имя базы данных, которую вы хотите редактировать. примечание: после подключения вы увидите список баз данных, которые есть на вашем сервере или на сервере, к которому вы подключаетесь.