현재 python 에서 제공하는 mysql 커넥터로 제일 유명한 pymysql
과MySqldb
가 있습니다. 둘의 쿼리문 차이는 없지만 pymysql
은 파이썬으로 구현되어 있으며 mysqlclient
는 C
로 구현되어 있다는 것이다.
mysqldb
와 mysqlclient
는 같은 툴이며 Linux 계열에서 오류가 발생할 수 있다.
참고: https://m.blog.naver.com/altmshfkgudtjr/221578178061
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 쿼리문을 작성할 차례이다. 간단히 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() 함수를 원한다면 공홈을 찾아보도록 하자
프로젝트를 구성하는데 있어서 위와 같은 오류가 발생하였다. 처음에 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
아래와 같이 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
앞에서 살짝 말한 커넥션 풀을 직접 건드리는 방법이다. 실제로 배포하고 있으며 사용자의 history에 대해 정보가 있다면 스트레스 테스트를 통한 하이퍼 파라미터를 수정하는 것이다. pool_size
를 크게 잡으면 mysql 자체가 메모리를 많이 잡아 먹게 될 것이며 작게 잡으면 TimeoutError
가 날 것이다. 따라서 민감하게 대처해야 하는 부분이다.
참고 : https://spoqa.github.io/2018/01/17/connection-pool-of-sqlalchemy.html
오늘은 mysqlclient
를 사용하면서 어떻게 connection을 관리하면 좋을지 알아보았다. 아직 필자도 사용자가 어느정도로 사용할지에 대해서 정보가 없기 때문에 TimeoutError가 나는 것 보다는 일단 크게 잡을 예정이다.