Подтвердить что ты не робот

Потерянное соединение с сервером 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
#

Есть ли у вас идеи?

4b9b3361

Ответ 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. затем введите имя базы данных, которую вы хотите редактировать. примечание: после подключения вы увидите список баз данных, которые есть на вашем сервере или на сервере, к которому вы подключаетесь.