Skip to content
isdnetworks
Go back

한 줄에 너무 많이 담겨 있었다

목록 화면이 느렸다. 쿼리는 20건만 가져오는데도 느렸다.

Table of contents

Open Table of contents

무엇을 가져오는지 봤다

iBATIS sqlmap 을 열어 보니 SELECT * 였다. DESC 로 보니 본문과 첨부 정보와 미리 그려 둔 HTML 이 같은 행에 들어 있었다.

no          int
title       varchar(200)
content     text            ← 본문
attach_meta text            ← 첨부 정보
html_cache  mediumtext      ← 그려 둔 HTML

목록에서는 제목과 날짜만 쓴다. 한 건에 본문이 수만 자면 20건에 수십만 자를 가져온다.

SELECT no, title, reg_date 로 바꾸니 목록이 빨라졌다. SELECT * 는 편한데 컬럼이 늘면 그때부터 느려진다. 지금 당장은 안 드러나는 종류의 문제였다.

큰 것을 따로 뒀다

InnoDB 는 TEXT 의 앞 768바이트를 클러스터드 인덱스 행에 두고 나머지를 오버플로 페이지로 뺀다. 큰 컬럼이 많으면 B-tree 노드에 데이터가 차서 한 페이지에 담기는 행 수가 줄어든다. 그래서 html_cache 를 다른 테이블로 뺐다.

CREATE TABLE board_content (
  board_no    int  NOT NULL,
  content     text,
  html_cache  mediumtext,
  PRIMARY KEY (board_no)
);

상세 화면에서만 JOIN 하고 목록과 검색은 board 만 본다.

검색이 특히 심했다. LIKE '%키워드%' 로 본문까지 뒤지는데 앞에 % 가 붙으면 인덱스를 못 쓰고 전부 읽는다. 게다가 본문이 크니 읽는 양도 크다. 제목만 먼저 찾게 하고 본문 검색은 조건을 좁힌 뒤에 하게 나눴다. 뒤에만 % 가 붙으면 인덱스를 쓴다.

얼마나 큰지 재 봤다

짐작하지 말고 MySQL 에서 AVG(LENGTH(content))MAX(LENGTH(content)) 를 같이 뽑았다.

avg_len  4,218
max_len  1,842,003

평균은 4천 자인데 최대가 180만 자다. 긴 순으로 뽑아 보니 이미지를 본문에 통째로 넣은 글이었다. 그 한 건 때문에 목록 전체가 느려질 수 있다.

평균만 봤으면 문제가 없어 보였을 것이다. 최대를 같이 봐야 이런 것이 드러난다.

넣을 때와 자를 때

읽는 쪽만 고쳐서는 계속 감당해야 한다. 넣을 때 본문 길이에 상한을 두고 이미지는 본문에 넣지 말고 파일로 올리게 했다.

화면 쪽도 고칠 것이 있었다. 목록에서 본문 앞 50자를 미리 보여 주고 있었는데, 앞부분만 쓰면서 전부 가져오고 있었다. 자르는 것을 쿼리로 옮기니 가져오는 양 자체가 준다. 화면에서 자르는 것은 이미 가져온 뒤라 늦다.

정리


Share this post on:

Previous Post
처음 세운 리눅스 웹 서버
Next Post
연결을 계속 잡고 있었다