pymysql 과 MySQLdb 이해하기

허준현·2021년 8월 21일
0
post-thumbnail

현재 python 에서 제공하는 mysql 커넥터로 제일 유명한 pymysqlMySqldb 가 있습니다. 둘의 쿼리문 차이는 없지만 pymysql은 파이썬으로 구현되어 있으며 mysqlclientC로 구현되어 있다는 것이다.
mysqldbmysqlclient는 같은 툴이며 Linux 계열에서 오류가 발생할 수 있다.
참고: https://m.blog.naver.com/altmshfkgudtjr/221578178061

DB 연결하기

import pymysql

connection = pymysql.connect(
	user    = 'root',
        passwd  = 'pw',
    	host    = '127.0.0.1',
    	db      = 'example_db',
    	charset = 'utf8'
)

cursor = db.cursor()

위의 코드처럼 mysql에 연결하기 위한 커넥션을 제공한다.
db에 연결하는 작업을 자바나 다른곳에서도 사용해본 사람은 커넥션만 필요한 것이 아닌 데이터베이스와 상호작용을 위한 cursor 객체를 생성해야 한다는 것을 알 것이다.
여기서 튜플로 가져오는 가장 기본 db.cursor() 가 있으며
자주 사용하는 Dict 형태로 사용하기 위해서는 아래와 같이 매개변수에 추가해 주면 된다.

cursor = db.cursor(pymysql.cursors.DictCursor)

DB 쿼리문 작성하기

이제 DB 쿼리문을 작성할 차례이다. 간단히 mysql을 workbanch로 돌려보았다면 기본적인 select문을 작성 할 수 있을것이다. 아래는 그 예시이다.

db = db_connection()
cursor = db.cursor()
cursor.execute("SELECT * FROM stuent")
result = cursor.fetchall()
db.close()
return result

cursor 객체에서 제공하는 여러가지 함수가 있는데 그중에서 실행 하는 excute() 와 해당 하는 데이터를 모두 가져오는 fetchall() 이 있으며 다른 fetch() 함수를 원한다면 공홈을 찾아보도록 하자

MySQLdb._exceptions.OperationalError: (2006, '') 오류 해결하기


프로젝트를 구성하는데 있어서 위와 같은 오류가 발생하였다. 처음에 stackoverflow에 검색하였지만 패킷의 크기를 늘리면 해결된다고 하였지만 이미 서버의 패킷의 크기는 큰 상태였다. 그래서 코드를 보면서 하나의 결과를 유추 할 수 있었다.

db = db_connection()
cursor = db.cursor()
cursor.execute("SELECT * FROM stuent")
result = cursor.fetchall()
db.close()
cursor = db.cursor()
cursor.execute("SELECT id FROM stuent")

위와 같은 코드가 있다면 현재 db 커넥션을 close() 한 상태로 연결을 시도하기 때문에 오류가 발생하는 것이다. 물론 초보적인 실수 일수도 있지만 쿼리문을 실행하고 나서 커넥션을 계속 붙잡고 있는 것은 메모리적으로 낭비가 심할 것이며 또한 .py 파일마다 하나씩의 connection을 설정하는 것도 낭비가 심하다.

어떻게 하면 메모리를 효율적으로 관리할 수 있을까?

효율적으로 연결하기

기존에 학교 졸업작품을 구성하는데 있어서 nodejs-mysql 에서 커넥션 풀에서 연결을 default로 100개의 연결을 잡아두도록 구현하였지만 현재 효율적으로 연결하고 해제하는 방식을 알기 위해서 stackoverflow를 찾아보았다.
참고 : https://stackoverflow.com/questions/47711689/error-while-using-pymysql-in-flask
https://stackoverflow.com/questions/40433271/connection-object-not-callable-sqlalchemy-pymysql

1번째 연결하고 나서 작업 후 바로 해제 하기

아래와 같이 connection 객체와 cur객체를 생성하고 역할을 하고 나서 바로 할당을 취소해주는 방식이다. 물론 connection 하는 작업이 시간도 걸리고 리소스도 먹는 편이지만 가장 무식한 방법이면서 메모리 릭이 날 확률이 적다.

def db_execute(query):
     conn = MySQLdb.connect(*)
     cur = conn.cursor()
     cur.execute(query)
     res = cur.fetchall()
     cur.close()
     conn.close()
     return res

2번째 SqlAlchemy.pool 와 pool_pre_ping 사용하기

앞에서 살짝 말한 커넥션 풀을 직접 건드리는 방법이다. 실제로 배포하고 있으며 사용자의 history에 대해 정보가 있다면 스트레스 테스트를 통한 하이퍼 파라미터를 수정하는 것이다. pool_size 를 크게 잡으면 mysql 자체가 메모리를 많이 잡아 먹게 될 것이며 작게 잡으면 TimeoutError 가 날 것이다. 따라서 민감하게 대처해야 하는 부분이다.
참고 : https://spoqa.github.io/2018/01/17/connection-pool-of-sqlalchemy.html

오늘은 mysqlclient를 사용하면서 어떻게 connection을 관리하면 좋을지 알아보았다. 아직 필자도 사용자가 어느정도로 사용할지에 대해서 정보가 없기 때문에 TimeoutError가 나는 것 보다는 일단 크게 잡을 예정이다.

profile
best of best

0개의 댓글