database.sarang.net
UserID
Passwd
Database
DBMS
ㆍMySQL
PostgreSQL
Firebird
Oracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
MySQL Q&A 27905 게시물 읽기
No. 27905
LEFT JOIN을 사용한 쿼리의 튜닝에 대해
작성자
이주헌(kirrie)
작성일
2008-12-05 00:11
조회수
4,850

사용환경 :

1. mysql 5.0 innodb 사용

2. 게시판 5개 생성 됨

3. 각 게시판마다 약 1000개에서 2000개 정도의 글이 있음.


내용 :

간단한 포럼형 게시판을 만들어 보고 있습니다. 각 게시판의 목록을 나열 할 때 게시판 별로 가장 최근의 article 하나를 함께

보여주기 위해서 LEFT JOIN과 GROUP BY를 함께 사용했습니다만, 질의 후 결과를 받아오기 까지 약 1.8초가 걸리네요.

튜닝에 관한 조언을 부탁드립니다.


테이블 관계도 :


*mysql work bench로 작성하였습니다.


사용한 쿼리 :

SELECT forums.id, forums.name, forums.description, forums.articlecounts, articles.id, articles.title, users.name, articles.created

FROM forums

LEFT JOIN articles ON forums.id = articles.forums_id

LEFT JOIN users ON users.id = articles.users_id

GROUP BY forums.id

ORDER BY forums.id ASC


explain 결과 :

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE forums index (NULL) PRIMARY 4 (NULL) 5  
1 SIMPLE articles ref fk_articles_forums fk_articles_forums 5 forum.forums.id 530  
1 SIMPLE users eq_ref PRIMARY PRIMARY 4 forum.articles.users_id 1  


설정된 인덱스들 :

forums -> id (PRIMARY)

articles -> forums_id, articles_id, users_id

users -> id (PRIMARY)


기타 :

각 키들은 foreign key로 설정해두었습니다.

이 글에 대한 댓글이 총 3건 있습니다.

1. 일단 각각의 테이블에 데이타가 어느정도씩 있는지 알려주셔야 정확한 판단이 가능하겠군요.


2. where 구문을 사용하세요. where forums.id > 0


3. ORDER BY forums.id ASC 를 빼고 쿼리를 날려보세요.

속도가 만족할 만하면 이 부분을 빼고 쿼리문을 날려도 원하는 결과값이 나올 수 있게 DB구조를 변경하는 것이 좋습니다.


4. 혹시 필드들에서 NULL 값을 받는 것은 아니겠죠? 해당 필드에 NULL 값이 있으면 인덱싱을 타지 않습니다.

크리스나(krisna)님이 2008-12-05 09:21에 작성한 댓글입니다.

ALTER TABLE articles ADD KEY `forum_article` ( `forums_id`, `id` );

-- 아래의 select 쿼리에서 다음의 부분이 covered query가 되도록 색인 추가

-- SELECT forums_id, MAX( id ) AS lastArticleId

-- FROM articles

-- GROUP BY forums_id

 

 

 

SELECT forums.id, forums.name, forums.description, forums.articlecounts, bb.lastArticleId, bb.title, users.id, users.name, bb.created

FROM forums

LEFT JOIN (

SELECT aa.forums_id, aa.lastArticleId, articles.title, articles.users_id, articles.created

FROM (

SELECT forums_id, MAX( id ) AS lastArticleId

FROM articles

GROUP BY forums_id

) AS aa

INNER JOIN articles ON aa.lastArticleId = articles.id

) AS drv_articles ON forums.id = drv_articles.forums_id

LEFT JOIN users ON bb.users_id = users.id;

-- data를 들이부어서 돌려보진 않아서 그냥 저정도면 속도가 조금 나오지 않을까 싶은데, test해보시고 댓글 좀 부탁드릴께요.

우욱님이 2008-12-07 11:16에 작성한 댓글입니다. Edit

크리스나//

도움 주셔서 감사합니다. 데이터의 크기는

현재 10개의 포럼을 만들어 놓았고 각 포럼마다 1400개씩 총 14000개의 게시물이 존재하도록 더미 데이터를 삽입했습니다.

그리고 필드에서 인덱스를 걸어 놓은 필드들은 not null입니다.


우욱//

일단 bb 알리아스가 없던데 이렇게 수정했습니다.


SELECT forums.id, forums.name, forums.description, forums.articlecounts, drv_articles.lastArticleId, drv_articles.title, users.id, users.name, drv_articles.created

FROM forums

LEFT JOIN

    (

    SELECT aa.forums_id, aa.lastArticleId, articles.title, articles.users_id, articles.created

    FROM

        (

        SELECT forums_id, MAX( id ) AS lastArticleId

        FROM articles

        GROUP BY forums_id

        ) AS aa

    INNER JOIN articles ON aa.lastArticleId = articles.id

    ) AS drv_articles ON forums.id = drv_articles.forums_id

LEFT JOIN users ON drv_articles.users_id = users.id;


말씀하신대로 forums_id와 id를 묶어서 인덱스를 걸었구요 (걸지 않아도 그다지 느리진 않더군요.)

그야말로 번개같은 속력입니다. +_+

게다가 제가 처음 작성한 쿼리를 다시 찬찬히 살펴보니 원하는대로 결과가 나오지도 않더군요.

우욱님께서 작성하신 쿼리가 더 정확하게 결과가 나옵니다.


explain 결과도 첨부합니다.


id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY forums ALL (NULL) (NULL) (NULL) (NULL) 10  
1 PRIMARY <derived2> ALL (NULL) (NULL) (NULL) (NULL) 10  
1 PRIMARY users eq_ref PRIMARY PRIMARY 4 drv_articles.users_id 1  
2 DERIVED <derived3> ALL (NULL) (NULL) (NULL) (NULL) 10  
2 DERIVED articles eq_ref PRIMARY,forums_articles PRIMARY 4 aa.lastArticleId 1  
3 DERIVED articles index (NULL) fk_articles_forums 4 (NULL) 14839 Using index


제가 explain 내용을 자세히 볼 줄은 몰라서 대충 짐작만 하지만 일단 articles에 대한 내용은 인덱스를 잘 타고 있고

나머지 경우에 대해서는 타겟팅 되는 row가 적기 때문에 이렇게 결과가 나오는 것일까요?


아무튼 너무 멋진 쿼리였습니다. ^^ 감사합니다!

이주헌(kirrie)님이 2008-12-07 20:43에 작성한 댓글입니다.
[Top]
No.
제목
작성자
작성일
조회
27908프로시저 질문 할께요...
알고싶습니다.
2008-12-08
4045
27907엑셀파일 다운로드
초보ㅠ
2008-12-08
5291
27906mysql 혼자 공부하고 있는 초보입니다.
김동영
2008-12-06
3978
27905LEFT JOIN을 사용한 쿼리의 튜닝에 대해 [3]
이주헌
2008-12-05
4850
27903디비별 디렉토리 안에서 테이블별로 디렉토리를 생성하여 저장하고 싶습니다. [1]
kino
2008-12-03
3597
27902분류별 count 는 어떻게 하나요?
임시손님
2008-12-03
4620
27901[MySql] 간단한 update 구문 작성에 대하여...
김종철
2008-12-03
4069
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.018초, 이곳 서비스는
	PostgreSQL v16.2로 자료를 관리합니다