2014-06-05 3 views
1

내가 가지고있는 다음과 같은 두 개의 테이블 : StudentId데이터베이스 인덱스의 원인이 사용하지 않는 슬로우 쿼리

StudentCourse 
- Id, 
- StudentId, 
- CourseId 

고유 인덱스와 CourseId

StudentCourseCount 
- Id, 
- Student1Id, 
- Student2Id, 
- CourseCount 

지수 Student1Id에와 Student2IdCourseCount

색인 및 CourseCount

내가 CourseId 일 때 나는 코스를 듣는 학생들을 나열합니다. 성취하고자하는 열쇠는 학생이 이전에 수업을 들었던 다른 학생들을 열거하고 싶습니다.

나는 다음과 같은 쿼리를 시도하고있다 :

SELECT * FROM StudentCourseCount sc 
INNER JOIN StudentCourse s1 ON s1.course_id = <id> AND sc.student1_id = s1.student_id 
INNER JOIN StudentCourse s2 ON s2.course_id = <id> AND sc.student2_id = s2.student_id 
WHERE sc.course_count > 1 

이 쿼리가 예상 작품으로을; 그러나, 그것은 매우 큰 테이블 (10,000,000 + 행)에서 매우 느립니다.

쿼리를 설명 할 때 StudentCourseCount은 인덱스를 사용하지 않습니다. Student1IdStudent2Id에 대해 가능한 인덱스가 있음을 적절히 식별하지만 둘 중 하나를 사용하지는 않습니다.

실행 계획 : 테이블 : SC 가능한 키 : Student1Id, Student2Id 키 : 널 (null) 행 : 28648392

테이블 : C2 키 : student_id 행 : 1 개

테이블 : C1 키 : student_id 행 : 1

첫 번째 표는 분명히 검색 중이며 신속하게 필터링하기 위해 키를 사용하지 않습니다.

+1

실행 계획과 테이블의 인덱스 정의를 복사하십시오. – Olli

+3

난 그냥 궁금해서. . . 어떤 애플리케이션이 'StudentCourse' 테이블에 10,000,000 개의 행을 가지고 있습니까? –

+0

인덱스를 추가하고 쿼리 실행 계획을 설명했습니다 (중요한 부분을 다시 작성하므로 잘 복사/붙여 넣기하지 않았습니다). – endyourif

답변

0

outer_season에도 course_id 필터를 넣어야하는 것처럼 보입니다. StudentCourseCount의 유일한 필터는 course_count입니다. 1 course_id 만 검색한다고 가정하면 sc.course_count> 1이고 sc.course_id = id 여야합니다. 그렇지 않은 경우 sc.course_count> 1 결과 집합에 필터를 적용하는 것은 조인입니다.

값이 고르게 분포되어 있다고 가정하면이 쿼리 (또는 변형)가 실행되어야합니다. 10M 행은 매우 크지 않아 쿼리를 최적화해야합니다.

+0

sc는 코스 ID가 없으므로 학생과 카운트가 포함되어 있습니다. 코스 ID는 s1 및 s2 테이블에서 필터링됩니다. – endyourif

+0

아, 그러면 StudentCourseCount가 아닌 StudentCourse 테이블에서 먼저 선택하려는 것 같습니다. –

0

브렌트 베이즐리는 좋은 점을 알았습니다. 나는 처음에는 <id>을 보지 못했습니다. 같은 과정에 두 학생을 모두두고 싶으므로 Join에서 연결하고 where 절에서 course_id=<id> 조건을 얻을 수 있습니다. 나는 그 자체로 옵티마이 저가 그런 일을해야한다고 생각하지만, 시도해 볼만한 가치가있다 :

SELECT * FROM StudentCourseCount sc 
INNER JOIN StudentCourse s1 ON sc.student1_id = s1.student_id 
INNER JOIN StudentCourse s2 ON s2.course_id = s1.course_id AND sc.student2_id = s2.student_id 
WHERE sc.course_count > 1 AND s1.course_id = <id> 
+0

s1.course_id를 where 절로 이동 시키면 더 느려집니다. 그래서 이것은 도움이되지 않았다. – endyourif

+0

그러면 다시 얼마나 많은 레코드가 StudentCourseCount와 StudentCourse에 있습니까? 얼마나 많은 StudentCourseCount 레코드가 course_count> 1에 해당하고 얼마나 많은 StudentCourse 레코드가 적합합니까? course_id =

+0

3 대 1 시나리오입니다. 카운트는 코스보다 3 배 더 많이 포함되어 있습니다. 각 과목 별 ID는 50-100 명으로 추정됩니다. 이것들은 50 명의 학생들과 함께 수업을 위해 돌아 오는 카운트 테이블의 시간에 대해 매번 일치합니다. 이것은 각 학생의 500 가지 조합으로 다른 학생과 수업을 같이합니다. – endyourif

0

이것은 매우 큰 결과 집합을 반환하는 매우 큰 쿼리이다. 데이터 양이 반환되기 때문에 최적화 할 수 있는지 확신 할 수 없습니다. 당신이 테이블에서 원하는

SELECT * 
FROM StudentCourseCount sc INNER JOIN 
    StudentCourse s1 
    ON s1.course_id = <id> AND sc.student1_id = s1.student_id INNER JOIN 
    StudentCourse s2 
    ON s2.course_id = <id> AND sc.student2_id = s2.student_id 
WHERE sc.course_count > 1; 

인덱스는 StudentCourseCount(course_count, student_id)StudentCourse(student_id, course_id) 있습니다.

이제이 쿼리가 작동한다고 말하면서 결과가 마음에 드신다고 가정합니다.

미만 :

물론 id을 촬영하고 둘 이상의 물론

이 매우 다르다을 촬영 한 학생의 모든 쌍을 가져 오기 : 그것은 다음과 같은 질문에 답한다 나는 이전에 수업을 들었던 다른 학생들을 열거하고 싶습니다.

이것이 진짜 질문이라면, 스택 오버플로에 대한 다른 질문을 통해 더 나은 쿼리를 얻을 것을 제안합니다.

관련 문제