2012-10-12 3 views
0

저는 오랫동안 공유 호스팅을 사용 해왔고 문제없이 몇 달 동안 동일한 쿼리를 실행했습니다. 갑자기 나는 "데이터베이스가 과도한 양의 프로세서 시간을 소비하고있는 것으로 밝혀 졌기 때문에 데이터베이스에 블록을 넣는다는 전자 메일을 내 호스트에서받습니다. 왜 이해가 안가는거야? 그래서 어쨌든 나는 VPS에 갈 필요가 있다고 생각했다. VPS에서 내 사이트를 얻으려고 시도하자마자 전체 사이트에 메모리 부족 오류가 발생하여 오류가 발생했습니다. 잠시 동안 사이트에가는 동안 연결이 시간 초과되었습니다.서버 크래시 - 최적화 MySQL 쿼리

내 테이블 중 아무 것도 10,000 행을 넘지 않습니다. 내 원래 호스트가 보낸 몇 가지 사항은 다음과 같습니다.

DB_USER: my_user -- TOTAL_CONNECTIONS: 37 -- CONNECTED_TIME: 4906 -- 
CPU_TIME: 1920 -- TABLE_ROW_READS: 79999077 -- SELECT_COMMANDS: 214 -- 
UPDATE_COMMANDS: -- BUSY_TIME: 4879 -- BYTES_SENT: 252225 -- 
BYTES_RECEIVED: 105418 -- WAIT_TIME (IO): 2959 

테이블 행은 79,999,077 ?? 진심으로 그게 어떻게 작동하는지. 내 테이블은 모두 작다. 나는 많은 교통량을 얻지 못한다. 어쩌면 100-150 명. 그러나 사이트가 완전히 새 서버에 올려 졌을 때 사이트가 완전히 죽어서 문제가되지는 않습니다. 다음은 내 데이터베이스가 다운되었다는 전자 메일의 쿼리입니다. 정말로이 쿼리 하나만으로 나를 죽일 수 있습니까? 랜드로

SELECT `Person`.`first_name`, `Person`.`last_name`,`Person`.`id`,`Upload`.`path`,`TeacherBiography`.`final_biography`, `TeacherPhilosophy`.`final_philosophy` 
FROM `my_database`.`people` AS `Person` 
LEFT JOIN `my_database`.`teacher_drive_cities` AS `TeacherDriveCity` 
    ON (`TeacherDriveCity`.`person_id` = `Person`.`id`) 
LEFT JOIN `my_database`.`instruments_people` AS `InstrumentsPerson` 
    ON (`InstrumentsPerson`.`person_id` = `Person`.`id`) 
LEFT JOIN `my_database`.`instruments` AS `Instrument` 
    ON (`Instrument`.`id` = `InstrumentsPerson`.`instrument_id`) 
LEFT JOIN `my_database`.`teachers` AS `Teacher` 
    ON (`Teacher`.`person_id` = `Person`.`id`) 
LEFT JOIN `my_database`.`uploads` AS `Upload` 
    ON (`Upload`.`person_id` = `Person`.`id`) 
LEFT JOIN `my_database`.`teacher_biographies` AS `TeacherBiography` 
    ON (`TeacherBiography`.`person_id` = `Person`.`id`) 
LEFT JOIN `my_database`.`teacher_philosophies` AS `TeacherPhilosophy` 
    ON (`TeacherPhilosophy`.`person_id` = `Person`.`id`) 
WHERE `TeacherDriveCit! y`.`city` = 'Dana Point' 
    AND `TeacherDriveCity`.`state` = 'ca' 
    AND `Instrument`.`instrument` = 'saxophone' 
    AND `Teacher`.`status` = 6 
    AND `Upload`.`description` = 'profile_picture' 
    AND `TeacherBiography`.`final_biography` IS NOT NULL 
    AND `TeacherPhilosophy`.`final_philosophy` IS NOT NULL 
GROUP BY `Person`.`id` 
ORDER BY RAND() ASC 
LIMIT 3 

내가 들어 위하여() 천천히,하지만 난 그게 하나의 호출에 전체 서버를 충돌 것이라고 생각하지 않았다 : 그것은 문제없이 그대로 개월까지있었습니다. 내가 여기서 뭔가를 놓치고 있니? 어떤 도움을 주시면 감사하겠습니다! 내 사이트는 24 시간 동안 다운되었으므로 그 사이트에서 수입을 얻습니다. 감사!

편집 : 다음은 쿼리에 대해 설명입니다 :

1 SIMPLE TeacherBiography ALL NULL NULL NULL NULL 41 Using where; Using temporary; Using filesort 
1 SIMPLE TeacherPhilosophy ALL NULL NULL NULL NULL 41 Using where; Using join buffer 
1 SIMPLE Upload    ALL NULL NULL NULL NULL 166 Using where; Using join buffer 
1 SIMPLE Teacher    ALL NULL NULL NULL NULL 381 Using where; Using join buffer 
1 SIMPLE InstrumentsPerson ALL NULL NULL NULL NULL 647 Using join buffer 
1 SIMPLE Instrument eq_ref PRIMARY PRIMARY 4 yml_yml.InstrumentsPerson.instrument_id 1 Using where 
1 SIMPLE Person eq_ref PRIMARY PRIMARY 4 yml_yml.TeacherPhilosophy.person_id  1 Using where 
1 SIMPLE TeacherDriveCity ALL NULL NULL NULL NULL 7489 Using where; Using join buffer 

당신이 그것을 쉽게 읽을 수 있도록 포맷하지 압니다 ... 나는 테이블하고 무엇을하지 여기하는 방법을 모른다 . 죄송합니다!

+0

쿼리에 EXPLAIN을 사용한 결과를 게시 해주십시오. – Xint0

답변

1

EXPLAIN을 사용하면 쿼리에 영향을 미칠 수있는 많은 사항이 있으며 성능에 가장 큰 영향을 미치는 문제가 나와야합니다.

  • 는 모든 테이블은 테이블을 조인에 사용되는 필드에 인덱스를 확인합니다

    그러나 여기에는 몇 가지 일반적인 지침입니다.

  • LEFT JOIN을 사용하고 WHERE 절의 구체적인 값을 필터링하는 이유는 무엇입니까? 외부 조인을 사용하면 WHERE 절의 조건에 따라 나중에 필터링되고 삭제되는 행 수가 증가합니다.
  • 필터링에 사용 된 모든 열이 색인으로 덮여 있는지 확인하십시오. 그러나 텍스트 값을 기준으로 필터링하는 이유는 무엇입니까? 도시, 주 및 계기 필드가 인덱스로 덮여 있더라도 정수를 비교하는 것보다 문자열을 비교하는 데 더 많은 처리가 필요합니다.
  • 그룹화 이유가 Person.id 인 경우 무작위로 주문 하시겠습니까? 그룹화는 테이블 조인으로 인해 임시 테이블을 필요로하는 정렬 작업을 강제 실행합니다.

지금 이것에 대해도 생각 :

방법 데이터베이스 프로세스는 각 테이블에서 모든 행을 결합하는 것입니다 다음 조인 조건을 만족하지 않는 조합을 무시 일반적으로 결합한다. 그렇기 때문에 조인 필드에 인덱스를 갖는 것이 매우 중요합니다. 그 이유는 조합이 두 테이블의 모든 필드가있는 임시 테이블이 아닌 인덱스 키를 사용하기 때문입니다.또한 LEFT JOIN을 사용하지 않고 나중에 폐기 된 행 조합 (WHERE 절에 있음)을 버리는 이유이기도합니다.

이 쿼리가 무엇을하고 있는지 아이디어를 얻을, 그리고 성능에 영향을 미치는 왜 너무 심하게 계산하려면 :

Total rows to filter = Number of rows in table Person 
* Number of rows in table TeacherDriveCity 
* Number of rows in table Instrument 
* Number of rows in table Teacher 
* Number of rows in table Upload 
* Number of rows in table TeacherBiography 
* Number of rows in table TeacherPhilosophy 

나는 그것이 매우 큰 숫자가 될 것이라고 확신합니다. 게시 된 EXPLAIN 결과에서 해석

EXPLAIN이 아주 나쁜 : 언급 한 바와 같이

  • , 모든 ALL 값이 아래 type은 MySQL이 전체 테이블 스캔을하고 있다는 것을 의미 가입, 그게입니다 테이블의 모든 행을 읽어야합니다. 이것은 매우 나쁘다.
  • 대부분의 조인 조건에서 NULL 아래 표시된 possible_keys의 사용 가능한 인덱스가 없습니다. 이것은 MySQL이 테이블 스캔을 수행하는 또 다른 이유이며, 필요한 모든 행을 필터링하기 위해 결합 된 모든 행을 조사해야합니다.

나는 최악의 부분은 citystate으로 필터링한다고 말하고 싶습니다. 조인이 없다면 TeacherDriveCity에서 두 필드로 간단히 조회하면 MySQL이 잠재적으로 7489 행을 조사해야합니다. 두 필드 모두 문자열을 유지한다는 것은 말할 필요도 없습니다.

빠른 수정은

JOINWHERE 조항에 사용 된 모든 컬럼에 인덱스를 추가합니다. 그러나 TeacherBiographyTeacherPhilosophy 이외의 테이블에서 외부 (LEFT) 조인을 사용하지 않는 것이 좋습니다.

+0

답장을 보내 주셔서 대단히 감사합니다! 나는 그 도시와 국가가 문제가되는 것처럼 보였습니다. 왜냐하면 그것 없이는 같은 쿼리가 잘 작동했기 때문입니다. 나는 내가 찾고있는 결과를 제공하고 그것들을 최적화하는데 너무 많은 생각을하지 않는다면 항상 쿼리를 받아 들였다. 지금은 도시와 주 필터를 꺼내서 인덱스 조인에 대해 배우는 시간을 보내고 그렇지 않은 경우를 실시간으로 보냅니다. 솔직히 좌익 내측 조인 등의 차이를 결코 이해하지 못했습니다. 왼쪽은 항상 내가 찾던 결과를 반환하는 것처럼 보였습니다. 어쨌든 다시 고마워! –

+0

지금 막 시작한 이유가 있을까요? 쿼리가있는 페이지가 항상 빠르게로드되고 지금까지 몇 달 동안 아무런 문제가 없었 음을 의미합니다. 이 쿼리 (그리고 필자가 작성한 다른 모든 쿼리)를 수정하는 작업을 확실히하겠습니다.하지만 그런 문제를 일으킬 수있는 잘못 작성된 쿼리 외에도 다른 것이 있는지 궁금합니다. 7489 행은 정말 많이 검색합니까? –

+0

문제는 그것이 7489가 아니라 이전 필터 결과 때문입니다. – Xint0