IT이야기

쿼리 중 MySQL 서버와의 연결이 끊어졌습니다.

cyworld 2021. 4. 10. 09:43
반응형

쿼리 중 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
#

당신은 어떤 생각이 있습니까?


mysql 문서에는이 오류 전용 페이지가 있습니다 : http://dev.mysql.com/doc/refman/5.0/en/gone-away.html

주목할 점은

  • 올바르지 않거나 너무 큰 쿼리를 서버에 보내는 경우에도 이러한 오류가 발생할 수 있습니다. mysqld가 너무 크거나 순서가 잘못된 패킷을 수신하면 클라이언트에 문제가있는 것으로 간주하고 연결을 닫습니다. 큰 쿼리가 필요한 경우 (예 : 큰 BLOB 열로 작업하는 경우) 기본값이 1MB 인 서버의 max_allowed_packet 변수를 설정하여 쿼리 제한을 늘릴 수 있습니다. 클라이언트 측에서 최대 패킷 크기를 늘려야 할 수도 있습니다. 패킷 크기 설정에 대한 자세한 내용은 B.5.2.10 절.“패킷이 너무 큼”에 나와 있습니다.

  • --log-warnings = 2 옵션으로 mysqld를 시작하면 끊어진 연결에 대한 자세한 정보를 얻을 수 있습니다. 이것은 hostname.err 파일에 연결이 끊어진 오류 중 일부를 기록합니다.


mysql 서버의 max_allowed_packet을 확대하는 세 가지 방법이 있습니다.

  1. mysql 서버 시스템 max_allowed_packet=64M에서 파일 /etc/mysql/my.cnf변경 하고 서버를 다시 시작하십시오.
  2. mysql 서버에서 SQL을 실행합니다. set global max_allowed_packet=67108864;
  3. Python은 mysql에 연결 한 후 sql을 실행합니다.

connection.execute ( 'set max_allowed_packet = 67108864')


연결하기 전에 커서를 닫아야합니다. 이 문제를 해결했습니다.

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

연결 시간 제한을 늘려야합니다. 어떤 이유로 그렇게 할 수 없거나 원하지 않는 경우 다음과 같이 전화 해보십시오.

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

이렇게하면 모든 결과를 즉시 가져 오며 연결이 반복되는 도중에 시간 초과되지 않습니다.


자식 프로세스를 분기하는 응용 프로그램에서도이 오류가 발생할 수 있습니다.이 응용 프로그램은 모두 MySQL 서버에 동일한 연결을 사용하려고합니다. 이는 각 하위 프로세스에 대해 별도의 연결을 사용하여 피할 수 있습니다.

포크가 당신을 때릴 수 있습니다. 이 경우에는 조심하십시오.


나는 나의 경우에 대한 이유

ERROR 2013 (HY000) : 쿼리 중 MySQL 서버 연결이 끊어졌습니다.

오류는 내 테이블의 일부가 손상 되었다는 것 입니다. mysqldump일부 행이 깨져서 내 테이블 을 사용할 수 없었 습니다. 오류는 위에서 언급 한 메모리 문제 등과 관련이 없습니다.

좋은 점은 MySQL이 실패한 첫 번째 행 번호를 반환했다는 것입니다. 마치

mysqldump : 오류 2013 : 행에서 mytable 테이블을 덤프 할 때 쿼리 중 MySQL 서버에 대한 연결이 끊겼습니다 : 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-table의 이름을 이전 테이블 이름으로 바꿉니다.

이 문제에 대한 Peter의 멋진 정보있습니다.


'max_allowed_packet'설정을 64M으로 설정하고 MySql 서버를 다시 시작하십시오. 그래도 문제가 해결되지 않았다면 문제가 다른 곳에있을 수 있습니다.

동시 쿼리를 수행하는 다중 스레드 PHP CLI 응용 프로그램이 있는데 최근에이 문제를 발견했습니다. 이제 MySql 서버는 동일한 IP의 모든 연결을 '단일'연결로 간주하므로 단일 쿼리가 완료 될 때마다 모든 연결을 삭제한다는 것이 분명합니다.

MySql이 동일한 IP에서 100 개의 연결을 허용하고 각 연결을 개별 연결로 간주하는 방법이 있는지 궁금합니다.


이것은 삽입이 시간 초과 되었기 때문에 varchar(255)열을 unique key.. 추측하기에는 너무 무겁게 만들었 기 때문에 mariadb와 함께 나에게 일어 났습니다.


누군가 또는 무언가가 KILL 명령을 사용하여 연결을 끊는 경우에도 발생할 수 있습니다 .


디스크의 크기가 사용 가능한 디스크 공간보다 큰 테이블을 업데이트하려고 할 때 이런 일이 발생했습니다. 저에게 해결책은 단순히 사용 가능한 디스크 공간을 늘리는 것입니다.


나도 비슷한 문제가 발생했습니다. 제 경우에는 다음과 같이 커서를 가져 와서 해결되었습니다.

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

제 경우에는 테이블을 잘못된 순서로 배치 한 SQL 덤프를 소싱 할 때이 문제가 발생했습니다. 문제의 CREATE에는 아직 생성되지 않은 테이블을 참조하는 CONSTRAINT ... REFERENCES가 포함되었습니다.

문제의 테이블을 찾아 CREATE 문을 문제가되는 문 위로 이동했고 오류가 사라졌습니다.

이 잘못된 덤프와 관련하여 내가 만난 다른 오류는 ERROR 1005 / errno : 150- "Ca n't create table"이며, 다시 순서가 잘못 생성되는 테이블 문제입니다.


CONSTRAINT이름이 다른 CONSTRAINT이름 과 같은 이름 일 때 이런 일이 발생했습니다 .

CONSTRAINT이름을 바꾸면 문제가 해결되었습니다.


다중 처리와 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, 연결 끊김) 문제를 해결했지만 스레드는 IO를 수행 할 때 GIL을 사용하여 IO가 완료되면 해제합니다.

상대적으로 Process는 서로 통신하는 작업자 그룹을 생성하므로 속도가 느릴 수 있습니다.

시간을 정하는 것이 좋습니다. 측면 팁을 사용하는 것입니다 JOBLIB scikit 배우기 프로젝트에 의해 백업됩니다. 일부 성능 결과는 네이티브 Pool ()을 수행하는 것으로 나타났습니다. 실제 런타임 비용을 확인하는 것은 코더에게 책임이 있습니다.


나는 같은 문제에 봉착했다. 다른 문제 때문에 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()

이 클래스 내에서 호출되는 모든 함수는 연결, 커밋 및 닫힘입니다.


수백만 개의 레코드로 대량 삽입을 시도 할 때 "깨진 파이프"와 함께이 오류가 발생했습니다. 나는 데이터를 더 작은 배치 크기로 덩어리로 만든 다음 필요한 각 삽입에 대해 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)

@imxylz와 동일하지만 mycursor.execute('set GLOBAL max_allowed_packet=67108864')GLOBAL 매개 변수를 사용하지 않고 읽기 전용 오류가 발생 하여 사용해야 했습니다.

mysql.connector.__version__ 

8.0.16


해결하기 매우 간단합니다. phpadmin의 제어판으로 이동하여 config를 클릭 한 다음 표시되는 .ini 파일을 편집합니다. 연결에 사용중인 포트가 아닌 경우 포트 3306을 찾아 3306을 사용중인 포트로 변경합니다. 로그인 화면에서 서버의 localhost, 기본값이 아닌 경우 포트를 입력하거나 SQL 구성 leavit에서 파일 이름 my.ini를 그대로 변경하지 않은 경우 포트를 넣으십시오. 그런 다음 사용자 이름 : root 또는 만든 암호를 입력 한 다음 암호 : 1234 또는 할당 한 암호를 입력하십시오. localy를 연결하는 경우 url 옵션을 확인하지 마십시오. 그런 다음 편집 할 데이터베이스의 이름을 입력하십시오. 참고 : 연결되면 서버에있는 데이터베이스 목록이나 연결중인 서버가 표시됩니다.

참조 URL : https://stackoverflow.com/questions/1884859/lost-connection-to-mysql-server-during-query

반응형