Медленные запросы в направляющих - не уверенный, если мои индексы используются

Я делаю довольно сложный, находят с большим количеством из, включает, который направляющие разделяет на последовательность дискретных запросов, а не сделайте единственное большое соединение. Запросы являются действительно медленными - мой набор данных не значителен ни с одной из таблиц, имеющих больше чем несколько тысяч записей.

Я индексировал все поля, которые исследованы в запросах, но я волнуюсь, что индексы не помогают по некоторым причинам: я установил плагин, названный "query_reviewer", который смотрит на запросы, раньше создавал страницу и перечисляет проблемы с ними. Это указывает, что индексы не используются, и это показывает результаты вызова, 'объясняют' на запросе, который перечисляет различные проблемы. Вот пример, находят вызов:

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})

И вот сгенерированные запросы SQL:

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) У меня есть индекс на каждом из идентификаторов и полей внешнего ключа, упомянутых здесь. Второй из вышеупомянутых запросов является самым медленным, и вызов объясняют на нем (выполнение его непосредственно в 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) Похоже, что направляющие не разделяют эту находку очень оптимальным способом. Это, Вы, думают? Действительно ли я - более обеспеченное выполнение нескольких запросов находки вручную, а не одного большого объединенного?

Благодарный за любой совет, макс.

1
задан Max Williams 13 May 2010 в 09:39
поделиться

2 ответа

В выводе query_reviewer говорится, что mysql должен вызываться для вашего запроса дважды из-за некоторой проблемы order_by . Вы можете проверить, является ли он причиной ваших проблем, просто удалив часть заказа из своего звонка. Если это проблема, то он должен работать намного быстрее.

Ваш запрос выглядит очень сложным. Вы уверены, что вам нужно загрузить такие сложные данные? Если у вас нет доступа к большинству полей в связанных моделях, было бы лучше не включать их.

0
ответ дан 3 September 2019 в 00:34
поделиться

Обычно ActiveRecord предварительно загружает ассоциации отдельными запросами, так как это обычно быстрее. Однако, когда он замечает, что вы использовали включенные ассоциации в :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]}])

Первый запрос будет выполняться к таблицам предметов, тегов, меток, оценок и вопросов, так как они используются в условиях/заказе. А :answers, :quizzes, age_group и :difficulty будут 4 отдельными простыми запросами.

И тогда вы можете попробовать оптимизировать больше индексов и т.д.

2
ответ дан 3 September 2019 в 00:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: