Настройка производительности базы данных Rails - PullRequest
2 голосов
/ 19 декабря 2011

В настоящее время я много работаю с ОЧЕНЬ большой базой данных mysql2, и хотя я проиндексировал то, что мне показалось правильным полем, время возврата для некоторых запросов довольно медленное.

У меня есть две модели, которые вызывают проблемы, Comment и Commenter.

Теперь между Commenter и Comment существует отношение has_many, но мой запрос основан на поиске имени пользователя для каждого комментария. Так что я буду запускать что-то вроде этого:

c = Blog.first.comments ##this bit runs fine, I indexed the "blog_id" field on Comments
c.collect {|c| c.commenter.username}

Чтобы помочь с проблемами скорости, я создал индекс в поле commenter_id для модели Comment. Но он все еще работает очень медленно ..

Кто-нибудь знает, что я мог бы сделать по-другому, это помогло бы увеличить скорость запроса?

Ответы [ 4 ]

3 голосов
/ 19 декабря 2011

Индекс на commenter_id помогает, когда вы хотите найти комментарии для данного commenter_id («найди мне все комментарии, сделанные Джо»).

Но когда вы делаете c.commenter you 'ищет пользователей, предположительно того, чей id равен комментарию commenter_id.Уже должен быть индекс для столбца id.Безошибочный способ состоит в том, чтобы взять фактические сгенерированные SQL-операторы (в разработке они находятся в development.log) и использовать для них объяснение, например

explain select * from comments where id = 12345

Учитывая, что очень маловероятно, что вам удалось создатьтаблица без индекса в столбце id, наиболее вероятная причина - стремительная загрузка - если в сообщении содержится 500 комментариев, то приведенный выше код извлекает связанных пользователей по одному, и эти 500 циклических переходов в базу данных складывают

c.includes(:commenter).collect {...}

или

c.eager_load(:commenter).collect {...}

исправят это (в приведенных выше фрагментах предполагается, что вы используете рельсы 3).

2 голосов
/ 19 декабря 2011

Collect собирается загружать объекты ActiveRecord для каждого комментатора со всеми полями по одному. Включение / Eager Загрузка загрузит их одним запросом, который поможет с быстротой, но если вам нужна абсолютная лучшая производительность, и вам просто нужны имена, к которым вам лучше обратиться к SQL, более напрямую с чем-то таким:

c         = Blog.first.comments
user_ids  = c.collect(&:commenter_id)
usernames = Commenter.where(['commenter_id IN (?)',user_ids]).select('username').collect(&:username)
1 голос
/ 19 декабря 2011

Прежде всего вы делаете слишком много ненужных запросов здесь c.collect {|c| c.commenter.username} Я думаю, что энергичная загрузка может помочь вам. Смотреть это http://railscasts.com/episodes/23-counter-cache-column?autoplay=true

0 голосов
/ 20 декабря 2011

Я понял это, используя энергичную нагрузку, которая не является ссылкой, опубликованной RaskolnikOFF, а брошенными на нее рельсами, http://railscasts.com/episodes/22-eager-loading (все еще дал вам ответ, чтобы подтолкнуть меня к ответу)

Очевидно, что я искал следующее:

b = Blog.find(:first, :include=>{:comments => :commenter})
b.comments.collect {|c| c.commenter.username}

Первая строка загружает первый блог и все его отношения (и возвращает блог).Поэтому, когда я вызываю вторую строку, все уже загружено и ожидает доступа ...

Что работает намного лучше, чем я делал первоначально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...