2010-05-13 4 views
1

하나의 큰 조인이 아니라 일련의 개별 쿼리로 분할되는 많은 포함을 통해 매우 복잡한 찾기를 수행하고 있습니다. 쿼리가 정말 느립니다. 데이터 세트가 방대하지 않고 수천 개가 넘는 테이블이 없습니다.레일스에서 ​​느린 쿼리 - 인덱스가 사용 중인지 확실하지 않습니다.

나는 쿼리에서 검사되는 모든 필드의 색인을 생성했으나 색인이 어떤 이유로 도움이되지 않을까 걱정됩니다. "query_reviewer"라는 플러그인을 설치하여 페이지를 표시하고 문제를 나열합니다. 인덱스가 사용 중이 지 않으며 여러 문제점을 나열한 u 리에 'Explain'을 호출 한 결과가 표시됩니다. 여기에 생성 된 SQL 쿼리를하는

Question.paginate(:all, {:page=>1, :include=>[:answers, :quizzes, :subject, {:taggings=>:tag}, {:gradings=>[:age_group, :difficulty]}], :conditions=>["((questions.subject_id = ?) or (questions.subject_id = ? and tags.name = ?))", "1", 19, "English"], :order=>"subjects.name, (gradings.difficulty_id is null), gradings.age_group_id, gradings.difficulty_id", :per_page=>30}) 

을 그리고 : 예를 들면 : 전화를 찾을 것

SELECT DISTINCT `questions`.id 
    FROM `questions` 
    LEFT OUTER JOIN `taggings` ON `taggings`.taggable_id = `questions`.id 
    AND `taggings`.taggable_type = 'Question' 
    LEFT OUTER JOIN `tags` ON `tags`.id = `taggings`.tag_id 
    LEFT OUTER JOIN `subjects` ON `subjects`.id = `questions`.subject_id 
    LEFT OUTER JOIN `gradings` ON gradings.question_id = questions.id 
    WHERE (((questions.subject_id = '1') or (questions.subject_id = 19 and tags.name = 'English'))) 
    ORDER BY subjects.name, (gradings.difficulty_id is null), gradings.age_group_id, gradings.difficulty_id 
    LIMIT 0, 30 

SELECT `questions`.`id` AS t0_r0 <..etc...> 
    FROM `questions` 
    LEFT OUTER JOIN `answers` ON answers.question_id = questions.id 
    LEFT OUTER JOIN `quiz_questions` ON (`questions`.`id` = `quiz_questions`.`question_id`) 
    LEFT OUTER JOIN `quizzes` ON (`quizzes`.`id` = `quiz_questions`.`quiz_id`) 
    LEFT OUTER JOIN `subjects` ON `subjects`.id = `questions`.subject_id 
    LEFT OUTER JOIN `taggings` ON `taggings`.taggable_id = `questions`.id 
    AND `taggings`.taggable_type = 'Question' 
    LEFT OUTER JOIN `tags` ON `tags`.id = `taggings`.tag_id 
    LEFT OUTER JOIN `gradings` ON gradings.question_id = questions.id 
    LEFT OUTER JOIN `age_groups` ON `age_groups`.id = `gradings`.age_group_id 
    LEFT OUTER JOIN `difficulties` ON `difficulties`.id = `gradings`.difficulty_id 
    WHERE (((questions.subject_id = '1') or (questions.subject_id = 19 and tags.name = 'English'))) 
    AND `questions`.id IN (602, 634, 666, 698, 730, 762, 613, 645, 677, 709, 741, 592, 624, 656, 688, 720, 752, 603, 635, 667, 699, 731, 763, 614, 646, 678, 710, 742, 593, 625) 
    ORDER BY subjects.name, (gradings.difficulty_id is null), gradings.age_group_id, gradings.difficulty_id 

SELECT count(DISTINCT `questions`.id) AS count_all FROM `questions` 
    LEFT OUTER JOIN `answers` ON answers.question_id = questions.id 
    LEFT OUTER JOIN `quiz_questions` ON (`questions`.`id` = `quiz_questions`.`question_id`) 
    LEFT OUTER JOIN `quizzes` ON (`quizzes`.`id` = `quiz_questions`.`quiz_id`) 
    LEFT OUTER JOIN `subjects` ON `subjects`.id = `questions`.subject_id 
    LEFT OUTER JOIN `taggings` ON `taggings`.taggable_id = `questions`.id 
    AND `taggings`.taggable_type = 'Question' 
    LEFT OUTER JOIN `tags` ON `tags`.id = `taggings`.tag_id 
    LEFT OUTER JOIN `gradings` ON gradings.question_id = questions.id 
    LEFT OUTER JOIN `age_groups` ON `age_groups`.id = `gradings`.age_group_id 
    LEFT OUTER JOIN `difficulties` ON `difficulties`.id = `gradings`.difficulty_id 
    WHERE (((questions.subject_id = '1') or (questions.subject_id = 19 and tags.name = 'English'))) 

사실,이 모든 좋게 여기 형식의보고, 여기에 무슨 가입의 미친 양이있다. 이것은 반드시 최적 일 수는 없습니다. 어쨌든 두 가지 질문이있는 것 같습니다.

1) 여기에 언급 된 각각의 ID와 외래 키 필드에 대한 색인이 있습니다. 위의 쿼리의 두 번째는 느린이며, (직접 MySQL의에서 그 일을)에 설명 호출 다음 나에게 제공합니다

+----+-------------+----------------+--------+---------------------------------------------------------------------------------+-------------------------------------------------+---------+------------------------------------------------+------+----------------------------------------------+ 
| id | select_type | table   | type | possible_keys                 | key            | key_len | ref           | rows | Extra          | 
+----+-------------+----------------+--------+---------------------------------------------------------------------------------+-------------------------------------------------+---------+------------------------------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | questions  | range | PRIMARY,index_questions_on_subject_id           | PRIMARY           | 4  | NULL           | 30 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | answers  | ref | index_answers_on_question_id             | index_answers_on_question_id     | 5  | millionaire_development.questions.id   | 2 |            | 
| 1 | SIMPLE  | quiz_questions | ref | index_quiz_questions_on_question_id            | index_quiz_questions_on_question_id    | 5  | millionaire_development.questions.id   | 1 |            | 
| 1 | SIMPLE  | quizzes  | eq_ref | PRIMARY                   | PRIMARY           | 4  | millionaire_development.quiz_questions.quiz_id | 1 |            | 
| 1 | SIMPLE  | subjects  | eq_ref | PRIMARY                   | PRIMARY           | 4  | millionaire_development.questions.subject_id | 1 |            | 
| 1 | SIMPLE  | taggings  | ref | index_taggings_on_taggable_id_and_taggable_type,index_taggings_on_taggable_type | index_taggings_on_taggable_id_and_taggable_type | 263  | millionaire_development.questions.id,const  | 1 |            | 
| 1 | SIMPLE  | tags   | eq_ref | PRIMARY                   | PRIMARY           | 4  | millionaire_development.taggings.tag_id  | 1 | Using where         | 
| 1 | SIMPLE  | gradings  | ref | index_gradings_on_question_id             | index_gradings_on_question_id     | 5  | millionaire_development.questions.id   | 2 |            | 
| 1 | SIMPLE  | age_groups  | eq_ref | PRIMARY                   | PRIMARY           | 4  | millionaire_development.gradings.age_group_id | 1 |            | 
| 1 | SIMPLE  | difficulties | eq_ref | PRIMARY                   | PRIMARY           | 4  | millionaire_development.gradings.difficulty_id | 1 |            | 
+----+-------------+----------------+--------+---------------------------------------------------------------------------------+-------------------------------------------------+---------+------------------------------------------------+------+----------------------------------------------+ 

query_reviewer 플러그인이 그것에 대해 말할 수있다 - 그것은 몇 가지 문제를 나열

Table questions: Using temporary table, Long key length (263), Using filesort 
MySQL must do an extra pass to find out how to retrieve the rows in sorted order. 
To resolve the query, MySQL needs to create a temporary table to hold the result. 
The key used for the index was rather long, potentially affecting indices in memory 

2) 레일이이 부분을 아주 잘 분리하는 것처럼 보이지 않습니다. 그래, 그렇지? 내가 하나의 큰 결합 된 하나보다는 수동으로 여러 가지 찾기 쿼리를하는 것이 낫지 않습니까? 어떤 조언에 대한 감사

, 별도의 쿼리와 최대

답변

2

일반적으로 액티브 미리로드 협회, 그것은 일반적으로 더 빨리 때문이다. 그러나 포함 된 연관을 :conditions 또는 :order에 사용했음을 알게되면 필요한 테이블뿐만 아니라 모든 테이블을 포함하여 하나의 큰 쿼리를 수행합니다.

questions = Question.paginate(:all, {:page=>1, :include => [:subject, {:taggings=>:tag}, :gradings], :conditions=>["((questions.subject_id = ?) or (questions.subject_id = ? and tags.name = ?))", "1", 19, "English"], :order=>"subjects.name, (gradings.difficulty_id is null), gradings.age_group_id, gradings.difficulty_id", :per_page=>30}) 

Question.send(:preload_associations, questions, [:answers, :quizzes, {:gradings=>[:age_group, :difficulty]}]) 

첫 번째 쿼리는 주제 taggings, 태그, gradings에 질문에서 실행됩니다 : 당신은 아마 수행 할 수있는

만 사용되어지는 조건이 해당 테이블을 포함하고 이후 다른 모든 연결을 미리로드하는 것입니다 테이블, 그들은 coditions/order에서 사용된다. 및 : answers, : quizzes, age_group 및 : 난이도는 4 개의 별도 간단한 쿼리가됩니다.

그리고 당신은 시도 할 수 있습니다 및 query_reviewer에서

0

출력이 쿼리 때문에 일부 order_by 문제를 두 번 호출해야합니다에 MySQL을 가지고 있다고 더 등 당신의 인덱스를 최적화 할 수 있습니다. 전화를 걸어서 order 부분을 제거하면 문제가 있는지 확인할 수 있습니다. 문제가 있다면 훨씬 빨리 실행해야합니다.

검색어가 매우 복잡해 보입니다. 복잡한 데이터를로드해야합니까? 연관된 모델의 필드 대부분에 액세스하지 않으면 포함하지 않는 것이 좋습니다.