2012-06-25 3 views
1

Я разработал приложение, которое дает зарегистрированным пользователям обзор статистики в месяц.Как оптимизировать ruby ​​on rails статистика в месяц запрос

Это мой текущий подход:

Statistics.html.haml:

#(@parsed months is an array of monthnames.) 

- @parsed_months.each do |month| 
    = render :partial => "statistic", :locals => {:month => month} 

_statistic.html.haml:

%tr{:class => cycle("odd", "even")} 
    %td= l(month, :format => "%B").capitalize 
    %td= current_user.total_views_count(month) 
    %td= current_user.total_leads_count(month) 
    %td= current_user.total_clicks_count(month) 

Метод, который возвращает общее число просмотров (в пользователя .rb):

def total_views_count(month = nil) 
    if month == nil 
    v = 0 
    self.companies.each {|c| v += c.counts.size} 
    return v 
    else 
    v = 0 
    self.companies.each {|c| v += c.counts.where(:created_at => Date.today.beginning_of_year..Date.today.end_of_year).where(:created_at => month.beginning_of_month..month.end_of_month).size} 
    return v 
    end 
end 

Company.rb:

belongs_to :user 
has_many :counts, :as => :countable, :dependent => :destroy 

Count.rb:

belongs_to :countable, :polymorphic => true 

User.rb:

has_many :companies 

Это работает хорошо, но через несколько месяцев модель графа выросла миллион + записей, вызывая тайм-ауты запроса на героку.

Что я могу сделать для оптимизации этих запросов или есть ли более эффективные подходы к этому?

Заранее благодарен!

+1

Можете ли вы разместить соответствующий контент у компании и считать модели? а также рассказать нам больше о том, как подсчеты связаны с компаниями в реальной проблеме? – rubish

+0

Я сделал некоторые изменения, но они довольно просты. Счета - это количество просмотров (сделанных посетителями) профиля компании, компания принадлежит одному пользователю, и пользователь может иметь больше компаний. – Laurens

+0

Хорошо, я получил отношения между ними. Можете ли вы также рассказать, как вы храните счет? Можете ли вы опубликовать все поля в модели подсчета. Также как вы храните счет? они отображаются на посетителя за посещение, или каждый вид посетителя преобразуется в строку в модели подсчета? – rubish

ответ

1

Вы должны обратить внимание на следующие оптимизировать запросы:

  1. попытаться сократить запросы в одном запросе
  2. Оптимизировать вы индексы
  3. Создать накопительные столы

Очки 2 и 3 такие же, как упоминалось в @opensourcechris.

Я не работал с активной записью в течение некоторого времени, поэтому я не могу дать вам синтаксис запроса isl, но главная проблема заключается в том, что есть много данных, и вы делаете много тяжелых запросов в одном запросе. Вы должны использовать объединения для сокращения запросов и тщательного использования индексов, чтобы сделать объединение и запрос оптимальным.Запрос с соединениями будет выглядеть примерно следующим образом:

SELECT count(c.id) FROM users u 
    JOIN companies comp ON comp.user_id = u.id 
    JOIN counts c ON c.company_id = comp.id 
        AND c.countable_type = 'Company' 
        AND c.created_at BETWEEN date_range 
    WHERE u.id = currrent_user_id 

Вы также можете использовать GROUP BY здесь, чтобы получить данные для всех месяцев в одном запросе Yest сохранить счетчики на ежемесячной основе.

Для того, чтобы эффективно работать, вы должны иметь индекс на companies.user_id и составной индекс на counts.countable_id, counts.countable_type, counts.created_at.

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

Этот объем данных, поступающих в режиме вставки, также вызывает беспокойство. Поэтому вам, вероятно, следует создать таблицу без каких-либо индексов и записать все данные подсчета в эту таблицу. Данные могут быть свернуты в другие таблицы через регулярные промежутки времени. Таблицы свертывания могут быть созданы по степени детализации, как требуется для отчетности. Общие параметры - ежечасно, ежедневно, еженедельно, ежемесячно и ежегодно сводят таблицы.

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

PS: Я думаю, вы должны использовать session_id (uuid) вместе с ip-адресом для правильного подсчета просмотров. В общем, общедоступный IP-адрес является общим для многих пользователей Интернета.

0

Чтобы оптимизировать запросы, вы должны начать с проверки индексов на каждой таблице. Так как ваш WHERE на поле даты, я думаю, индексы будут работать хорошо использовать для просмотра индексов:

USE *database*; 
SHOW INDEX FROM *tablename*; 

Затем убедитесь, что вы индексировать где столбцы.

Другой вариант заключается в том, чтобы забыть вычисления итогов за исторические месяцы, просто рассчитать их в конце месяца и сохранить их в новой сводной таблице. Таким образом, все, что вы будете рассчитывать «на лету», это данные за текущий месяц, предыдущие месяцы могут быть возвращены из вашей новой сводной таблицы.

+0

Это не похоже на проблему индексирования, это больше похоже на «запрос в цикле в цикле в пределах цикла "для меня. –

+0

Действительно, добавление индекса не улучшает производительность. – Laurens

Смежные вопросы