SELECT * 과 SELECT COUNT(*) 쿼리 비교 시 뭐가 더 성능이 좋을까??
-> 일반적으로 두 쿼리 중 SELECT * 쿼리가 더 좋은 성능을 보여준다.
SELECT * 쿼리는 리미트 조건이 일반적으로 있지만, SELECT COUNT(*) 쿼리의 경우 리미트 조건이 없기 때문이다. 만약 리미트 조건이 없는 경우라면 다를 수 있다.
또한 COUNT(*)의 경우 테이블 내 모든 레코드의 건수를 확인해야 하므로 상황에 따라 쿼리 실행 시간이 상이하다.
SELECT * FROM TMP_TB; SELECT COUNT(*) FROM TMP_TB;
SELECT COUNT(*) 쿼리의 가장 이상적인 성능 개선은 Covering Index를 사용하는 방식이다.
이러한 Covering Index를 통하여 인덱스 컬럼만으로 쿼리가 처리되기 때문에 높은 성능을 자랑할 수 있다.
하지만 모든 쿼리를 Covering Index로 튜닝하는 것은 매우 부적절한 방법이다.
ORM을 통해 레코드의 건수를 확인하려 할 때 MySQL 서버 내부에서 SELECT COUNT(DISTINCT id) 쿼리로 동작되는 경우가 있다.
(위 쿼리에서 "id" Primary key를 의미)
SELECT COUNT(DISTINCT id) 쿼리는 SELECT COUNT(*)보다 성능이 좋지 않다.
MySQL 내부에서 중복 제거(DISTINCT)를 위해 중복 제거용 임시 테이블을 생성한다.
임시 테이블에는 조건에 맞는 레코드를 삽입(INSERT 또는 UPDATE) 작업을 하는데, 이 과정에서 임시 테이블의 레코드를 검색(SELECT)하여 중복되는 값이 있으면 넘어간다.
해당 과정이 끝난 이후 중복 제거용 임시 테이블의 건수를 확인하여 반환한다.
이처럼 DISTINCT을 통한 레코드 건수는 다수의 SELECT-INSERT/UPDATE가 발행되기 때문에 2~3배 이상 성능이 좋지 않다.
SELECT COUNT(*) 쿼리문의 튜닝은 Covering Index를 사용하는 방법이 사실 유일한 방법으로 보인다...
하지만 Covering Index로 튜닝하는것은 현실적으로 어려운 경우가 있으므로 다른 방법을 고안해야 한다.
SELECT COUNT(*) 쿼리 자체를 삭제하는 방법이다. 해당 쿼리문을 사용하지 않고 다른 방법을 통해 비즈니스 로직을 해결하는 방법이 있을 수도 있다.SELECT COUNT(*) 쿼리를 삭제하는 것이 불가능한 경우, 표시할 페이지 번호만큼만 레코드 건수를 확인하는 방법과 임의로 페이지 번호를 표기하는 방법, 통계정보를 활용하는 방법 등을 고려해 봐야 한다.이처럼 SELECT COUNT(*) 쿼리 성능 튜닝은 다양한 방법을 통해 진행할 수 있다. 여기서 쿼리 튜닝의 대상을 둘로 나누어 고민해 볼 필요가 있다.
SELECT COUNT(*) 쿼리 삭제 대상