2011-03-02 3 views
1

저는 DB 전문가가 아니므로 가능한 한 많이 읽었으며 커뮤니티 응답 덕분에 쿼리 및 쿼리를 여러 번 변경할 수있었습니다. 테이블 구조. 물건을 많이 읽은 후에도 나는 붙어있어 첫 질문을하게되었습니다.큰 쿼리 및 테이블 구조를 최적화하는 데 문제가 있습니다.

나는 사용자가 자신의 이야기를 게시하는 웹 사이트를 운영하고 있습니다. 각 이야기에는 장르, 경고, 다수 저자, 할당 된 복수 문자 등이있을 수 있습니다.

우리는 MySQL 5.x를 실행 중이며 테이블은 PHP로 작성된 InnoDB 웹 사이트입니다. GROUP_CONCAT을 사용하여 결과에 대한 스토리별로 단일 행을 반환합니다. GROUP BY 이야기 ID를 사용하여 이전에 시도했지만 모든 검색어가 완료되기까지 약 16 초가 걸리고 매우 느립니다. 이 새로운 것으로, 그들은 0.175를 취합니다. 그러나 예를 들어, WHERE의 장르가 존재하지 않는다면, 질의는 23 초가 걸립니다! 테스트를 위해 모든 테이블에는 1 백만 개의 레코드가 있고 저자 테이블에는 150 만 개의 테이블이 있습니다. 나는 하나의 MySQL이 사용할 인덱스를 찾기 위해 여분의 인덱스를 배치하려고 시도했다.

일대 다 관계로 정규화 된 것을 얻으려고했습니다. 해결책은 아마 전체 문제를 다루기 때문에 여기서는 약간의 테이블 만 제시 할 것입니다. 어떤 도움을 주셔서 감사합니다, 시간 내 주셔서 감사합니다!

테이블

CREATE TABLE `fanfiction_authors` (
    `uid` int(11) NOT NULL AUTO_INCREMENT, 
    `penname` varchar(100) NOT NULL, 
    `penname_url` varchar(100) NOT NULL, 
    PRIMARY KEY (`uid`), 
    KEY `penname_url` (`penname_url`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ; 

-- -------------------------------------------------------- 

CREATE TABLE `fanfiction_stories` (
    `sid` int(11) NOT NULL AUTO_INCREMENT, 
    `title` varchar(200) NOT NULL, 
    `sinopse` text NOT NULL, 
    PRIMARY KEY (`sid`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ; 

-- -------------------------------------------------------- 

CREATE TABLE `fanfiction_stories_authors` (
    `sid` int(11) NOT NULL, 
    `uid` int(11) NOT NULL, 
    KEY `sid_uid` (`sid`,`uid`), 
    KEY `sid` (`sid`), 
    KEY `uid` (`uid`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

-- -------------------------------------------------------- 

CREATE TABLE `fanfiction_stories_genres` (
    `key_id` int(11) NOT NULL AUTO_INCREMENT, 
    `sid` int(11) NOT NULL, 
    `genre_id` int(11) NOT NULL, 
    PRIMARY KEY (`key_id`), 
    KEY `sid` (`sid`), 
    KEY `genre_id` (`genre_id`), 
    KEY `sid_genreid` (`sid`,`genre_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ; 

-- -------------------------------------------------------- 

CREATE TABLE `fanfiction_stories_stats` (
    `sid` int(11) NOT NULL, 
    `reviews` int(11) NOT NULL, 
    `recomendacoes` int(11) NOT NULL, 
    PRIMARY KEY (`sid`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

-- -------------------------------------------------------- 

CREATE TABLE `fanfiction_stories_warnings` (
    `key_id` int(11) NOT NULL AUTO_INCREMENT, 
    `sid` int(11) NOT NULL, 
    `warning_id` int(11) NOT NULL, 
    PRIMARY KEY (`key_id`), 
    KEY `sid` (`sid`), 
    KEY `warning_id` (`warning_id`), 
    KEY `warningid_sid` (`sid`,`warning_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1000000 ; 

---- 

쿼리

SELECT 
    st.sid, st.title, st.sinopse, 
    (SELECT GROUP_CONCAT(CAST(genre_id AS CHAR)) FROM fanfiction_stories_genres WHERE sid = st.sid) as genres, 
    stats.reviews, stats.recomendacoes, 
    (SELECT GROUP_CONCAT(CAST(warning_id AS CHAR)) FROM fanfiction_stories_warnings WHERE sid = st.sid) as warnings_ids 
FROM 
    fanfiction_stories AS st 
    LEFT JOIN fanfiction_stories_stats AS stats ON st.sid = stats.sid 
WHERE 
    st.sid IN (SELECT sid FROM fanfiction_stories_warnings WHERE warning_id = 5) AND 
    st.sid IN (SELECT sid FROM fanfiction_stories_genres WHERE genre_id = 300) 
ORDER BY 
    st.sid ASC 
LIMIT 20 

내가 여기 읽을 수 설명 할 수없는, 그래서 드롭 박스에 PRINTSCREEN을 업로드했습니다. 내가 멍청이이기 때문에 이미지를 삽입 할 수 없습니다. 죄송합니다.

유효한 장르가있는 경우 설명입니다 (장르가 300 인 이야기를 찾을 수 있습니다).

explain http://dl.dropbox.com/u/14508898/Printscreen/stackoverflow_explain_print_001.PNG

이것은 우리가 (당신은 장르 번호 (900)와 이야기를 찾을 수 없습니다) 유효하지 않은 장르가있을 때 확장 설명합니다.

invalid genre explain http://dl.dropbox.com/u/14508898/Printscreen/stackoverflow_explain_print_002.PNG

너희들은, 제발 도와 드릴까요? 내 정규화가 올바 릅니까? 내가 도대체 ​​뭘 잘못하고있는 겁니까?

미리 감사드립니다.

답변

1

대신 JOIN을 사용하여 내부 선택 물 중 2 개를 저장할 수 있습니다. 두 경우 (genre_id = 300genre_id = 900)에서 속도가 빨라질 것입니다.

SELECT 
    st.sid, st.title, st.sinopse, 
    (SELECT GROUP_CONCAT(CAST(genre_id AS CHAR)) FROM fanfiction_stories_genres WHERE sid = st.sid) as genres, 
    stats.reviews, stats.recomendacoes, 
    (SELECT GROUP_CONCAT(CAST(warning_id AS CHAR)) FROM fanfiction_stories_warnings WHERE sid = st.sid) as warnings_ids 
FROM 
    fanfiction_stories AS st 
    LEFT JOIN fanfiction_stories_stats AS stats ON st.sid = stats.sid 
    JOIN fanfiction_stories_warnings w ON st.sid = w.sid AND w.warning_id = 5 
    JOIN fanfiction_stories_genres g ON st.sid = g.sid AND g.genre_id = 300 
GROUP BY st.sid 
ORDER BY st.sid ASC 
LIMIT 20 
+0

입력 해 주셔서 감사합니다. Galz! 나는 그것을 시도한 결과가 비어있는 경우 속도가 빨라지지만 (0.007), 결과가 나오면 20 초가 걸린다. 설명 : filesort를 사용하여 임시 사용. 나는 GROUP BY –

+0

에 의한 것 같아요. @Michael - 같은 GROUP BY를 버리고 동일한 결과를 얻는다고 생각합니다. fanfiction_stories_warnings에 하나의 레코드가 있고 동일한 sid 및 warning_id를 갖고 있고 fanfiction_stories_genres에 하나의 레코드 만 있으면 동일한 시드 및 genre_id와 함께 ... – Galz

+0

예, GROUP BY가없는 벤치마킹 이었지만 완벽합니다. 결과는 평균 0.08이며 표시 할 결과가없는 경우 평균 0.002입니다. 고마워요, 갈쯔! 너 정말로 나를 구했어. :) –