2016-11-19 1 views
0

다음 쿼리에 문제가 있습니다. 데이터베이스 테이블에서 로그 레코드를 선택합니다.매우 느린 MySQL 쿼리 (20 ~ 60 초!) - 왜?

SELECT paymentslog.*, user.username, user.usergroupid, user.displaygroupid, 
     purchase_temp.threadid 
    FROM " . TABLE_PREFIX . "paymentslog AS paymentslog 
    LEFT JOIN " . TABLE_PREFIX . "user AS user 
     ON (paymentslog.userid = user.userid) 
    LEFT JOIN " . TABLE_PREFIX . "paymenttransaction AS paymenttransaction 
     ON (paymentslog.transactionid = paymenttransaction.transactionid) 
    LEFT JOIN " . TABLE_PREFIX . "paymentinfo AS paymentinfo 
     ON (paymenttransaction.paymentinfoid = paymentinfo.paymentinfoid) 
    LEFT JOIN " . TABLE_PREFIX . "purchase_temp AS purchase_temp 
     ON (paymentinfo.hash = purchase_temp.hash) $filterlogs_where 
    GROUP BY paymentslog.logid 
    ORDER BY paymentslog.dateline DESC 
    LIMIT $startat, $perpage 
  • 모든 사용자 이름, usergroupid에 액세스하는 사용자 테이블과 조인을 제외하고 SELECT에 threadid에 액세스하는 데 필요한 및 displaygroupid 조인
  • 이 (!)를 실행하기 위해 20 초 필요, 내 시도하는 동안 한 그것을 해결하기 위해 (테이블 paymentlog의) transactionid 열에 대한 INDEX를 추가 한 후, 이제 60 초가 필요합니다! 어떤 이유로
  • , 그것은 특정 행를 여러 번 돌려, 그리고 이런 이유로 나는 그 통지해야 그것이하여

"paymentslog.logid에 의해 GROUP"는 추가 수정 :
- $ filterlogs_where PHP 변수에는 쿼리의 WHERE가 있습니다 (저는 paymentslog에 대해 php 다른 필터를 통해 빌드합니다). 기본적으로 $ filterlogs_where의 값은 "1 = 1"이며, 필터를 적용해야한다면. = "AND paymentslog.userid = X"등을 추가합니다.

너무 느린가요?
필자는 몇 초 또는 밀리 초 내에 실행되는 더 복잡한 쿼리를보고 작성했다고 생각합니다. 위 질문에 왜이 문제가 있습니까?

+0

해시에 참여할 수 있지만 정수에 가입하는 것이 훨씬 빠릅니다. 우리가 얼마나 많은 데이터를 말하고 있는지, 당신은 그 사실을 우리에게 말하지 않았습니다. – Xorifelse

+5

정수 결합은 부분적으로 빠를 수도 있지만 그게 전부입니다. 모든 관련 테이블에 대한 CREATE TABLE 문과 위의 쿼리에 대한 EXPLAIN이 없으면이 문제를 해결하는 것이 불가능합니다. – Strawberry

+0

@ Xorifelse - 'HASH'인덱스가 없습니다. 어쨌든 해시는 BTree보다 약간 빠릅니다. –

답변

0

먼저 동일한 스키마를 가진 여러 개의 테이블을 사용하지 말 것을 권한다. 그것은 대개 나쁜 디자인입니다.

LEFT이 정말로 필요합니까? 즉, '오른쪽'테이블에 아무것도없는 경우에도 행이 반환되기를 원하십니까? 그렇지 않은 경우 JOIN을 사용하십시오.

LEFTs을 제거하면 GROUP BY이 제거 될 수 있습니다. 조인 다음에 GROUP BY은 일반적으로 "행 수를 늘린 다음" "그룹을 통해 수축"을 발생시킵니다. 이렇게하면 프로세스에 거대한 임시 테이블이 만들어져 작업 속도가 느려집니다.

그렇다면 Pagination via Offset은 문제가 많음을 지적해야합니다. 종종 긴 쿼리 시간이 필요합니다. 그러나이 기술을 사용하려면 GROUP BY을 제거해야합니다.

짧은 별명을 사용하십시오.

이제 귀하의 세부 사항으로 돌아가십시오 ... 음, 먼저 위의 작업을 수행하십시오. 그리고 SHOW CREATE TABLE을 제공하십시오. 그러면 다음과 같은 일들이 빨라질 것입니다 :

SELECT ... 
    FROM (SELECT id 
       ORDER BY dateline DESC 
       LIMIT $startat, $perpage) AS pl 
    JOIN user ON ... 
    JOIN ... 
    ORDER BY dateline DESC; -- yes, needs repeating 
+0

안녕하세요 Ricky와 분석 답변에 대해 매우 감사드립니다! 귀하의 예를 통해 알 수 있듯이 다음 쿼리를 작성했습니다. http://pastebin.com/GQAWe9AZ 맞습니까? 그것은 많은 레코드를 반환 올바른 결과를 보인다지만, 2 레코드와 테스트와 아무도 나타납니다. 긴 별칭을 유감스럽게 생각하고 곧 수정합니다. – user3594130

+0

아마도 '왼쪽'이 필요합니다. (나는 쿼리의 _intent_을 이해하지 못한다.) –

+0

ok done! 쿼리가 완벽하게 작동합니다. – user3594130