2016-10-28 2 views
0

어디서 닫히는 지에 따라 다른 실행 시간을 제공하는 제한이있는 쿼리가 있습니다. 저는 MySQL 5.1을 사용하고 있으며, 가장 큰 테이블 인 "경고"에서 약 1 억 개의 레코드를보고 있습니다. 나는이 실행 계획을 볼 때MySQL 쿼리 실행 계획 (한계가 다를 경우)

, 나는 행복 해요, 내 쿼리는 두 번째 채 걸리지 :

mysql> EXPLAIN SELECT alert.id, category.severity, category.classification, category.completion, alert.description, 
->  alert.detectTime, analyzer.name, analyzer.manufacturer, analyzer.model, analyzer.version, 
->  analyzer.class, analyzer.osType, analyzer.osVersion, analyzerNode.hostName, 
->  analyzerNode.address, sourceNode.hostName, sourceNode.address, targetNode.hostName, 
->  targetNode.address, sourceUser.userName, sourceUser.uid, targetUser.userName, targetUser.uid, 
->  alert.filePath, alert.sourceProcessPid, alert.sourceProcessPath, alert.targetProcessPid, 
->  alert.targetProcessPath, alert.acknowledgeUserName, alert.acknowledgeTime, reference.url, reference.meaning 
-> FROM alerts AS alert 
->  LEFT JOIN categories AS category ON category.id = alert.categoryId 
->  LEFT JOIN analyzers AS analyzer ON analyzer.id = alert.analyzerId 
->  LEFT JOIN nodes AS analyzerNode ON analyzerNode.id = alert.analyzerNodeId 
->  LEFT JOIN nodes AS sourceNode ON sourceNode.id = alert.sourceNodeId 
->  LEFT JOIN nodes AS targetNode ON targetNode.id = alert.targetNodeId 
->  LEFT JOIN users AS sourceUser ON sourceUser.id = alert.sourceUserId 
->  LEFT JOIN users AS targetUser ON targetUser.id = alert.targetUserId 
->  LEFT JOIN `references` AS reference ON reference.id = alert.referenceId 
-> WHERE category.severity = 'info' 
-> ORDER BY alert.id DESC 
-> LIMIT 40 OFFSET 0; 
  • | 이드 | select_type | 테이블 | 유형 | possible_keys | 열쇠 | key_len | 심판 | 행 | 추가 |
  • | 1 | 단순 | 경고 | 색인 | categoryIndex | PRIMARY | 8 | NULL | 40 | |
  • | 1 | 단순 | 카테고리 | eq_ref | PRIMARY, severityIndex | PRIMARY | 8 | am.alert.categoryId | 1 | 사용 위치 |
  • | 1 | 단순 | 분석기 | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.analyzerId | 1 | |
  • | 1 | 단순 | analyzerNode | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.analyzerNodeId | 1 | |
  • | 1 | 단순 | sourceNode | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.sourceNodeId | 1 | |
  • | 1 | 단순 | targetNode | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.targetNodeId | 1 | |
  • | 1 | 단순 | sourceUser | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.sourceUserId | 1 | |
  • | 1 | 단순 | targetUser | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.targetUserId | 1 | |
  • | 1 | 단순 | 참고 문헌 | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.referenceId | 1 | |

그러나 where 절 (이 경우 열거 형이지만 값이 적절하지 않다고 생각합니다)의 값을 변경하면 극적으로 다른 결과를 얻을 수 있으며 내 쿼리에는 영원히 걸릴 수 있습니다.

mysql> EXPLAIN SELECT alert.id, category.severity, category.classification, category.completion, alert.description, 
->  alert.detectTime, analyzer.name, analyzer.manufacturer, analyzer.model, analyzer.version, 
->  analyzer.class, analyzer.osType, analyzer.osVersion, analyzerNode.hostName, 
->  analyzerNode.address, sourceNode.hostName, sourceNode.address, targetNode.hostName, 
->  targetNode.address, sourceUser.userName, sourceUser.uid, targetUser.userName, targetUser.uid, 
->  alert.filePath, alert.sourceProcessPid, alert.sourceProcessPath, alert.targetProcessPid, 
->  alert.targetProcessPath, alert.acknowledgeUserName, alert.acknowledgeTime, reference.url, reference.meaning 
-> FROM alerts AS alert 
->  LEFT JOIN categories AS category ON category.id = alert.categoryId 
->  LEFT JOIN analyzers AS analyzer ON analyzer.id = alert.analyzerId 
->  LEFT JOIN nodes AS analyzerNode ON analyzerNode.id = alert.analyzerNodeId 
->  LEFT JOIN nodes AS sourceNode ON sourceNode.id = alert.sourceNodeId 
->  LEFT JOIN nodes AS targetNode ON targetNode.id = alert.targetNodeId 
->  LEFT JOIN users AS sourceUser ON sourceUser.id = alert.sourceUserId 
->  LEFT JOIN users AS targetUser ON targetUser.id = alert.targetUserId 
->  LEFT JOIN `references` AS reference ON reference.id = alert.referenceId 
-> WHERE category.severity = 'high' 
-> ORDER BY alert.id DESC 
-> LIMIT 40 OFFSET 0; 
  • | 이드 | select_type | 테이블 | 유형 | possible_keys | 열쇠 | key_len | 심판 | 행 | 추가 |
  • | 1 | 단순 | 카테고리 | 심판 | PRIMARY, severityIndex | severityIndex | 2 | const | 8 | 사용 장소; 임시 사용; filesort 사용 |
  • | 1 | 단순 | 경고 | 심판 | categoryIndex | categoryIndex | 8 | am.category.id | 3883428 | |
  • | 1 | 단순 | 분석기 | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.analyzerId | 1 | |
  • | 1 | 단순 | analyzerNode | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.analyzerNodeId | 1 | |
  • | 1 | 단순 | sourceNode | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.sourceNodeId | 1 | |
  • | 1 | 단순 | targetNode | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.targetNodeId | 1 | |
  • | 1 | 단순 | sourceUser | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.sourceUserId | 1 | |
  • | 1 | 단순 | targetUser | eq_ref | PRIMARY | PRIMARY | 8 | 오전.targetUserId | 1 | |
  • | 1 | 단순 | 참고 문헌 | eq_ref | PRIMARY | PRIMARY | 8 | am.alert.referenceId | 1 | |

실행의 첫 번째 단계로 제한이 있고 다른 하나는 제한이없는 것에 유의하십시오. 어쨌든 MySQL 쿼리 최적화 프로그램이 이것을 먼저 수행하도록 강제 할 것입니까?

+0

첫 번째 조인을 '내부 조인'으로 변경하면 어떻게됩니까? _Your'WHERE'는 효과적으로 결과를 바꾸지 않으므로 결과를 바꿔서는 안됩니다. _ – Uueerdo

+0

최적화 도구 힌트를 사용할 수 있습니다 : https://dev.mysql.com/doc/refman/5.7/en/optimizer-hints.html . 또 다른 방법은 나쁜 실행 계획을 좋게 만드는 인덱스를 추가하거나 옵티마이 저가 다른 계획을 생성하는 것입니다. – mm759

+0

INNER JOIN은 쿼리 또는 실행 계획의 성능을 변경하지 않았습니다. 옵티 마이저 힌트에 관해서는 솔직히 제 문제에 대한 해결책으로 나를 움켜 쥐었던 것을 보지 못했습니다. 나는 제안에 개방적이다. – Agricola

답변

0

ORDER BY 및 LIMIT를 사용하는 경우 주문 순서는 색인에 있어야합니다.

옵티마이 저가 다른 인덱스를 선택하기로 결정한 경우 결과가 검색되고 더 많은 레코드가 스캔 될 때 한계가 적용되지 않습니다.

'info'경고보다 '높음'이 적으며 옵티마이 저가 카테고리 테이블의 심각도 인덱스를 선호합니다.

경고 표의 PK를 강제로 FORCE INDEX으로 시도하거나 범주 테이블의 심각도 색인을 무시하려고 할 수 있습니다.

article 정도면 유용합니다.