"아파트명으로 검색" 기능은 검색어로 입력한 아파트 이름을 가지고 있는 전국 아파트 거래 데이터를 조회하여, 가장 최근 거래 데이터 정보를 반환하여 지도 상에 마커로 표시해주는 기능임
기존 API는 Mybatis 환경에서 다음의 쿼리를 수행함
<select id="getAptByName" parameterType="HouseParameterDto" resultType="houseInfoDto">
select hi.aptCode, hi.aptName, hi.buildYear, hi.dongName, hi.roadName, trim('0' from hi.roadNameBonbun) roadNameBonbun,
trim('0' from hi.roadNameBubun) roadNameBubun,
hi.jibun, hi.lng, hi.lat, hi.dongCode,
hd.dealAmount, hd.dealYear, hd.dealMonth, hd.dealDay, hd.area, hd.floor, max(hd.dealDate) dealDate,
d.sidoName, d.gugunName
from housedeal hd, houseinfo hi, dongcode d
where hi.aptName like concat ('%', #{aptName}, '%')
and hd.aptCode = hi.aptCode
and hi.dongCode = d.dongCode
group by hd.aptCode
</select>
문제점은 가장 최근 거래 정보만 가져오는 것이 아니라 해당 아파트의 거래목록, 주소정보를 모두 조회하는 것임
추가로 이 쿼리문 자체에 오류가 있었음
select hi.aptCode, hi.aptName, hi.buildYear, hi.dongName, hi.roadName, trim('0' from hi.roadNameBonbun) roadNameBonbun,
trim('0' from hi.roadNameBubun) roadNameBubun,
hi.jibun, hi.lng, hi.lat, hi.dongCode,
hd.dealAmount, hd.dealYear, hd.dealMonth, hd.dealDay, hd.area, hd.floor, hd.dealDate,
d.sidoName, d.gugunName
from housedeal hd, houseinfo hi, dongcode d
where hi.aptName like concat ('%', "아파트명", '%')
and hd.no in (select no
from ( select max(dealDate) dealDate, max(no) no
from housedeal hd, houseinfo hi
where hi.aptName like concat ('%', "아파트명", '%')
and hi.aptCode = hd.aptCode
group by hi.aptCode)
and hd.aptCode = hi.aptCode
and hi.dongCode = d.dongCode;
select max(no) no, max(dealDate) dealDate
from housedeal hd, houseinfo hi
where hi.aptName like concat ('%', "주공", '%')
and hi.aptCode = hd.aptCode
group by hi.aptCode;
#참고: 쿼리 실행 계획 분석
MySQL의 Optimization에 관한 공식 문서를 읽어보았고, loose index scan과 tight index scan라는 방법이 있었음.
일반적으로 group by는 각 그룹별로 해당 그룹에 속하는 데이터를 찾아 임시테이블에 넣고, 여기서 집계함수를 실행하는 방식으로 동작함.
하지만 최적화 방법을 이용하면 임시테이블을 따로 만들지 않고, 이미 인덱싱을 통해 순서대로 되어 있는 데이터들을 이용해 빠르게 그룹화와 집계함수를 실행함.
이 방법은, group by에 지정하는 각 column이 모두 index로 지정되어 있고, 인덱싱한 순서대로 group by에 지정하거나, 혹은 지정되지 않은 칼럼의 값들을 상수 조건으로 할당해줄 때만 동작함. 나의 쿼리에서는 이 조건을 충족하지 않아서 사용할 수가 없었음.
개발자 커뮤니티 OKKY에 질문도 남기고, 같이 공부하는 사람들과 고민을 해보면서 두 가지 방법을 알게 됐음.
1번: dealDate의 max값을 구할 필요가 없다. 왜냐하면 housedeal 테이블의 pk인 no가 이미 최근 거래일 수록 나중에 삽입되어 큰 값을 가지기 때문에, max(no)을 뽑으면 그게 최근 거래 데이터가 된다. 따라서 pk인 no가 indexing되어 있으므로 이 칼럼만 max값을 뽑으면 된다. 실제로 해보니 매우 빠르게 실행됨.
select max(no)
from housedeal hd, houseinfo hi
where hi.aptName like concat ('%', "주공", '%')
and hi.aptCode = hd.aptCode
group by hi.aptCode;
ALTER TABLE housedeal
ADD INDEX housedeal_aptCode_dealDate_idx (aptCode, dealDate);