여러가지 성능 개선을 위한 차이점이 존재함.
나는 promise 지원 여부에 대한 차이와
준비된 명령문(prepared statements) 지원의 차이
를 확실히 기억하고 넘어가려한다.
import * as mysql from "mysql2";
...
async findById(id: string) {
return new Promise((resolve, reject) => {
connection.query(
`SELECT * FROM student WHERE id = "${id}";`,
function(err, results) {
if (err) reject(err);
resolve(results);
}
);
});
}
지적받은 내 service 함수.
쿼리 결과를 받는 것을 보장한 뒤 return 하기 위해 promise로 커넥션을 관리했다.
mysql2가 아닌 mysql 을 사용해서 쿼리를 실행했다면 적절한 코드 였을 것이라고 생각함.
하지만, promise 를 지원하는 mysql2를 사용했으니 굳이 저럴 필요가 없었음
mysql2 를 사용한 코드로 바꿔보면,
import * as mysql from "mysql2";
...
async findById(id: string) {
return await connection.query(`SELECT * FROM student WHERE id = "${id}";`);
}
또는
import * as mysql from "mysql2";
...
async findById(id: string) {
try {
const result = await connection.execute('SELECT * FROM student WHERE id = ?;', [id]);
return result;
} catch (err) {
return err;
}
}
await 을 사용하기도 했지만
connection.query -> connection.execute 로 바꿔썻다.
execute를 사용한 이유는 mysql2 에서는 prepared statements를 지원하기 때문이다.
MySQL은 statement를 준비하고 쿼리하는 execute helper를 제공한다. 또한 prepare / unprepare 메서드를 통해 직접 statement를 준비하거나 준비하지 않을 수 있다.
execute는 내부적으로 prepare와 query를 호출한다.
만약 같은 statement를 실행(execute)한다면, LRU 캐시로부터 불려올 것이다.
그로 인해 쿼리 준비 시간을 아낄 수 있고 성능도 좋아진다.
Connection을 사용하는 방법:
createConnection >
connection.connect > connection.query > connection.end
이런 경우 사용자 요청이 많아져서 많은 connection이 발생 했을 때 과부하가 올 수 있다.
Connection Pool ?
일정 수의 커넥션을 pool에 보관하여 사용자의 요청이 발생하면 연결을 해주고 연결 종료 시 Pool에 다시 반환하여 보관하는 것.
이해하기에 좋은 그림이 있어서 퍼옴
mysql2에서는 pool을 사용하는 두 가지 방법이 있다.
import * as mysql from "mysql2";
import 'dotenv/config';
const pool = mysql.createPool({
host: process.env.HOST,
password: process.env.PASSWORD,
user: process.env.USERNAME,
database: process.env.DATABASE
});
pool.query("SELECT field FROM atable", function(err, rows, fields) {
})
pool.getConnection(function(err, conn) {
conn.query();
pool.releaseConnection(conn);
});
mysql2 공식 문서에 따른 사용법으로 위의 예시에 promise와 pool을 도입하여 리팩토링 해볼게요
import * as mysql from "mysql2";
import 'dotenv/config';
const pool = mysql.createPool({
host: process.env.HOST,
password: process.env.PASSWORD,
user: process.env.USERNAME,
database: process.env.DATABASE
});
const promisePool = pool.promise();
async findById(id: string) {
try {
const result = await promisePool.query('SELECT * FROM student WHERE id = ?;', [id]);
return result;
} catch (err) {
return err;
}
}
connectionLimit
const pool = mysql.createPool({
host: process.env.HOST,
password: process.env.PASSWORD,
user: process.env.USERNAME,
database: process.env.DATABASE
connectionLimit: 30
});
queue에 담겨서 앞의 커넥션이 release 되는 것을 기다리게 된다고 하는데.
기다리지 않고 에러를 발생 시킬 수 있는 옵션을 추가 할 수도 있따.
waitForConnections: false,
참고)
https://www.npmjs.com/package/mysql2
https://rat2.tistory.com/8
https://cotak.tistory.com/105
아무생각없이 pool 만들어놓고
mydb_pool.getConnection()
이걸로 다시 연결 만들서 사용했더니 8번만에 먹통이 되는군요
이글 보니 고쳤습니다. ㅎㅎ