목록이 느려서 두 가지를 고쳤다. 인덱스를 넣고 조회 방식도 바꿨다. 빨라졌는데 어느 것 때문인지는 모른다.
Table of contents
Open Table of contents
왜 알아야 하는가
당장은 빨라졌으니 문제가 없어 보였다. 다만 몇 가지가 걸렸다.
다음에 비슷한 상황에서 무엇을 먼저 할지 모른다는 것이 첫째다. 둘 다 하면 되지만 그러면 시간이 두 배로 든다.
둘째로 하나가 불필요할 수 있는데 인덱스 하나를 더 두는 것은 INSERT 와 UPDATE 를 그만큼 느리게 만든다. 효과가 없는데 남아 있으면 비용만 내고 있는 것이다.
셋째로 되돌릴 때 무엇을 되돌릴지도 모르는데 둘 다 빼면 다시 느려지고 하나만 빼려면 어느 것인지 골라야 한다. 판단할 근거가 없는 상태가 됐다.
검증 — 원래대로 두고 하나씩 쟀다
되돌리고 하나씩 적용했다.
원래 4.2초
인덱스만 추가 3.8초
조회 방식만 변경 0.9초
둘 다 0.7초
조회 방식이 대부분을 줄였고 인덱스가 줄인 것은 0.4초뿐이었다. EXPLAIN 의 rows 도 같은 방향으로 움직여서 숫자와 실행 계획이 맞았다.
인덱스는 빼도 될 정도였는데 자료가 늘면 효과가 커질 것이라 남겼다. 알고 두는 것과 모르고 두는 것은 다르고 이제 판단 근거가 생겼다.
재는 방법을 정했다
매번 손으로 재면 조건이 달라진다.
$t = microtime(true);
$rows = $this->model->get_list($cond);
$elapsed = microtime(true) - $t;
log_message('debug', sprintf("get_list %.3f초 %d건", $elapsed, count($rows)));
microtime 으로 재고 건수도 같이 남겼다. 같은 조건으로 세 번 돌려 평균을 봤다.
1회차 1.24초
2회차 0.71초
3회차 0.69초
첫 회차를 빼고 본 이유가 있다. InnoDB 는 필요한 페이지를 버퍼 풀에 올려 놓고 쓰는데 첫 실행은 그것을 디스크에서 읽어 온다. 두 번째부터는 이미 올라와 있으니 같은 쿼리라도 다른 것을 재게 된다.
반대 방향의 함정도 있었다. 쿼리 캐시가 켜져 있으면 두 번째 실행이 결과를 그대로 돌려받아 부당하게 빨라진다. SELECT SQL_NO_CACHE 를 붙여 그것을 끄고 쟀다.
실제 사용에서는 캐시가 있는 상태가 대부분이라 둘 다 기록했다.
자료 상태도 맞춰야 했다. 측정 사이에 자료가 늘면 비교가 안 된다.
CREATE TABLE product_snapshot AS SELECT * FROM product;
측정 전에 원래대로 되돌린다.
TRUNCATE product;
INSERT INTO product SELECT * FROM product_snapshot;
product_snapshot 으로 같은 시점을 고정하고 배치가 안 도는 시간도 골랐다. 조건이 같아야 비교가 된다.
무엇을 바꿨는지 남겼다
측정과 함께 무엇을 바꿨는지 적었다.
2014-10-06 상품 목록 성능
원래 4.2초 / 4.5초 (캐시 없음)
+ idx_category_status 인덱스 3.8초 / 3.9초
+ 조회를 조인으로 변경 0.9초 / 1.1초
둘 다 0.7초 / 0.9초
결론: 조회 방식이 주요 원인. 인덱스는 보조.
자료 증가 시 인덱스 효과가 커질 것으로 보여 유지.
숫자만 남기면 몇 주 뒤에 그 숫자가 무엇의 결과인지 모른다. 행 수와 SQL_NO_CACHE 여부와 변경 내용을 함께 적었다.
다만 한 번에 하나씩 바꾸는 것이 항상 옳지는 않았다. 급할 때는 둘 다 바꾸는 것이 맞고 서비스가 멈춰 있으면 원인 분석보다 복구가 먼저다.
급할 때 전부 적용 → 복구 → 나중에 나눠서 측정
여유 있을 때 하나씩 적용하며 측정
복구와 원인 규명을 나눈 것인데 둘을 같이 하려니 둘 다 늦어졌기 때문이다.
정리
- 동시에 바꾸면 어느 것이 효과였는지 모른다
- 안 쓰는 인덱스는
INSERT비용만 늘린다 - 되돌릴 때 무엇을 되돌릴지가 안 정해진다
- 원래 상태에서 하나씩 적용하며 잰다
EXPLAIN의rows가 숫자와 같은 방향인지 본다- 첫 회차는 InnoDB 버퍼 풀이 비어 있어 느리다
- 쿼리 캐시는 두 번째를 부당하게 빠르게 만든다.
SQL_NO_CACHE로 끈다 - 자료 상태를 고정해야 비교가 된다
- 측정과 함께 무엇을 바꿨는지 기록한다
- 급할 때는 먼저 복구하고 측정은 나중에 한다