다음 쿼리는 매우 간단합니다. 페이징 시나리오에서 사용하기 위해 메시지 테이블의 마지막 20 개 레코드를 선택합니다. 처음으로이 쿼리를 실행하면 15-30 초가 걸립니다. 이후의 실행에는 1 초도 채 걸리지 않습니다 (일부 캐싱이 필요합니다). 처음으로 왜 그렇게 오래 걸리는지 알아 내려고합니다. 테이블 여기간단한 쿼리는 15-30 초 걸림
을 4.0.26이-로그 것 :
table type possible_keys key key_len ref rows Extra
------ ------ ------------- -------- ------- ------ ------ --------------------------------------------
m ref List,ListOnly ListOnly 10 const 18002 Using where; Using temporary; Using filesort
이유 :
여기messages CREATE TABLE `messages` (
`ID` int(10) unsigned NOT NULL auto_increment,
`List` varchar(10) NOT NULL default '',
`MessageId` varchar(128) NOT NULL default '',
`From` varchar(128) NOT NULL default '',
`Subject` varchar(128) NOT NULL default '',
`MsgDate` datetime NOT NULL default '0000-00-00 00:00:00',
`TextBody` longtext NOT NULL,
`HtmlBody` longtext NOT NULL,
`Headers` text NOT NULL,
`UserID` int(10) unsigned default NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `List` (`List`,`MsgDate`,`MessageId`),
KEY `From` (`From`),
KEY `UserID` (`UserID`,`List`,`MsgDate`),
KEY `MsgDate` (`MsgDate`),
KEY `ListOnly` (`List`)
) TYPE=MyISAM ROW_FORMAT=DYNAMIC
는 설명이있어
SELECT DISTINCT ID,List,`From`,Subject, UNIX_TIMESTAMP(MsgDate) AS FmtDate
FROM messages
WHERE List='general'
ORDER BY MsgDate
LIMIT 17290,20;
MySQL 버전 : 여기
는 쿼리의 filesort를 사용할 때 모든 관련 열에 대한 색인이 있습니까? ListOnly 인덱스를 추가하여 도움이되는지 확인했습니다. 나는 원래 목록 인덱스가 목록 선택과 MsgDate에서의 정렬을 처리 할 것이라고 생각했지만 그렇지 않았습니다. 이제는 ListOnly 인덱스를 추가 했으므로 MsgDate에서 여전히 파일롯을 수행합니다. MsgDate는 오래 걸리는 것으로 의심됩니다. 이 인덱스를 사용하는 MySQL을 강제로 보인다, 그러나 모든 쿼리 속도를하지 않습니다SELECT DISTINCT ID,List,`From`,Subject, UNIX_TIMESTAMP(MsgDate) AS FmtDate
FROM messages
FORCE INDEX (List)
WHERE List='general'
ORDER BY MsgDate
LIMIT 17290,20;
:
나는 다음과 같이 FORCE의 INDEX를 사용했습니다.다음은이 쿼리에 대한 설명입니다 :
table type possible_keys key key_len ref rows Extra
------ ------ ------------- ------ ------- ------ ------ ----------------------------
m ref List List 10 const 18002 Using where; Using temporary
업데이트합니다
내가 쿼리에서 DISTINCT 제거. 그것은 성능에 전혀 도움이되지 못했습니다.
UNIX_TIMESTAMP 호출을 제거했습니다. 또한 성능에 영향을주지 않았습니다.
SELECT m.ID,List,From,Subject,MsgDate
FROM messages
WHERE MsgDate>='2009-11-15'
ORDER BY MsgDate DESC
LIMIT 20
: 나는 사용자가 결과의 마지막 페이지를 찾고 검색 할 경우, 나는 결과의 마지막 7 일 반환하는 WHERE 절을 추가하도록
나는 내 PHP 코드에 특별한 경우를 만들어
이것은 훨씬 빠릅니다. 그러나 결과의 다른 페이지로 이동하자마자 이전 SQL을 사용해야하고 실행하는 데 오랜 시간이 걸립니다. 나는 모든 페이지에서 이것을 할 수있는 실용적이고 현실적인 방법을 생각할 수 없다. 또한이 특별한 경우를 수행하면 PHP 코드가 더 복잡해집니다.
이상하게도 최초 쿼리가 처음 실행될 때만 시간이 오래 걸립니다. 동일한 쿼리 또는 결과의 다른 페이지를 나타내는 쿼리 (즉, LIMIT 절만 변경)의 후속 실행은 매우 빠릅니다. 약 5 분 동안 실행하지 않으면 쿼리가 다시 느려집니다.
해결책 :
제이슨 Orendorff와 줄리엣의 아이디어를 기반으로 해낸 가장 좋은 솔루션입니다.
먼저 현재 페이지가 총 페이지 수의 시작 또는 끝에 더 가까운 지 확인합니다.마지막에 가까울 경우 ORDER BY MsgDate DESC를 사용하여 적절한 제한을 적용한 다음 반환 된 레코드의 순서를 반대로 변경합니다.
이렇게하면 결과 집합의 처음 또는 끝에 가까운 페이지를 훨씬 빠르게 검색 할 수 있습니다 (처음에는 15-30 대신 4-5 초 걸립니다). 사용자가 가운데 근처의 페이지 (현재 430 번째 페이지 부근)로 이동하려는 경우 속도가 다시 내려갈 수 있습니다. 하지만 드문 경우입니다.
완벽한 해결책이없는 것처럼 보이지만 대부분의 경우보다 훨씬 좋습니다.
감사합니다. 제이슨과 줄리엣.
좋은 점, shylent. 나는 DISTINCT없이 그것을 시도 할 것이다. – elmonty
DISTINCT를 제거해도 성능이 향상되지 않았습니다. – elmonty
"LIMIT 17290,20"는 검색어의 865 번째 페이지에 해당하지 않습니까? 사용자가 실제로 데이터 세트를 탐색하고 있습니까? – Juliet