Ruby On Rails работает медленно ...? - PullRequest
7 голосов
/ 19 февраля 2009

Я пишу веб-приложение для мониторинга производственного процесса на мебельной фабрике. Он имеет тысячи данных для обработки. Пока что я запускаю RoR на Mongrel + MySQL, и это действительно очень медленно (2-4 минуты для некоторых просмотров). Когда я смотрю журналы RoR, кажется, что запросы к базе данных не медленные (0-10 мс).

Замедлен ли RoR при преобразовании данных базы данных в объект? Дворняга медленный?

Редактировать : Первое: я был в dev. окр. В производственной среде самый медленный просмотр занимает 2 минуты (что на хорошем компьютере должно быть менее 1 минуты, моему 5 лет). Имея ruby-prof и немного здравого смысла, я выяснил, какие методы замедляют работу приложения. Проблема заключается в том, что одиночные SQL-запросы вызываются в циклах на больших наборах данных:

ofs = Ofkb.find_by_sql ["..some large sql query..."]

for of in ofs # About 700-1000 elements
   ops = Operation.find(..the single query..)
   etc.
end

Вот результаты ruby-prof по этим методам:

 %self     total     self     wait    child    calls  name
 32.19     97.91    97.91     0.00     0.00       55  IO#gets (ruby_runtime:0}
 28.31     86.39    86.08     0.00     0.32    32128  Mysql#query (ruby_runtime:0}
  6.14     18.66    18.66     0.00     0.00    12432  IO#write (ruby_runtime:0}
  0.80      2.53     2.42     0.00     0.11    32122  Mysql::Result#each_hash (ruby_runtime:0}

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

Ответы [ 11 ]

17 голосов
/ 20 февраля 2009

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

Несколько советов по профилированию:

Как профилировать приложение Rails

Приложения для тестирования производительности рельсов

В Forge - Профилирование рельсовых приложений

Как только вы нашли узкое место, вы можете понять, что делать.

Я рекомендую эти видео: Railslab Scaling Rails

Пересмотрено теперь на основе результатов проф:

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

5 голосов
/ 19 февраля 2009

Хотя R-n-R имеет репутацию медленного , это звучит слишком экстремально, чтобы быть простой проблемой с языком.

Вы должны запустить профилировщик, чтобы точно определить, какие функции работают медленно и почему. Наиболее распространенная вещь, замедляющая работу веб-приложения, - это « n + 1 проблема ». То есть, когда у вас есть n элементов данных в вашей базе данных, приложение выполняет n отдельных запросов к базе данных вместо того, чтобы делать один запрос, который их получает. Но вы не можете знать , пока не запустите профилировщик. ruby-prof - это один из профилировщиков, который я использовал.

Редактирование на основе результатов профиля:

Я твердо верю, что вы можете всегда удалить цикл запроса. Как говорит Майк Вудхаус, способ Rails сделать это - указать отношения между вашими таблицами с помощью has_many или другой ассоциации, а затем позволить rails автоматически генерировать объединение таблиц, это ясно , быстрый и "рельсовый путь". Но если вы начинаете с голого SQL или если ассоциации не работают в этом случае, вы можете просто сгенерировать соответствующие объединения самостоятельно. И если ничего не помогает, вы можете создать представление или денормализованную таблицу, в которой хранятся результаты, которые ранее были найдены с помощью цикла. В самом деле, тот факт, что вы должны выполнять итерации по сгенерированным запросам , может быть признаком того, что в самой структуре вашей таблицы есть некоторые недостатки.

Все это говорит, что если кеширование результатов вашего запроса работает достаточно хорошо для вас, то оставайтесь с этим. Оптимизируйте при необходимости.

5 голосов
/ 19 февраля 2009

Сколько из этих запросов 0-10ms выполняется для доступа к представлению? На какие части вашей модели данных ссылаются? Используете ли вы: включить, чтобы получить загрузку ваших ассоциаций?

Rails так же медленны, как и вы. С пониманием приходит скорость (обычно!)

Расширяя вышесказанное, есть ли у вас ассоциации has_many, где, в частности, ваша точка зрения ссылается на сторону "многих" без :include? Это приводит к выполнению вашей find(:all) в основной таблице с объединением деталей - если у вас есть большое количество записей подробностей и вы обрабатываете их все по отдельности, это может дорого обойтись.

Примерно так:

Master.find(:all, :include => :details)

... может помочь. Тем не менее, я все еще догадываюсь из скудной информации.

Есть старый Railscast по теме здесь

4 голосов
/ 19 февраля 2009

Это не нормально. У вас есть логика, которая замедляет вас. Попытка закомментировать кусочки вашего кода, которые, по вашему мнению, занимают много времени, и посмотреть, поможет ли это. Если это так, вам нужно выяснить, как оптимизировать эту логику.

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

Проблемы такого типа могут возникать на любом языке или в любой среде. Хотя Ruby не так быстр, как другие языки, в большинстве случаев он достаточно быстр. Если вам необходимо постоянно проводить расчеты с большими наборами данных, то Ruby может не подойти вам. Посмотрите на написание расширения Ruby C, которое будет обрабатывать ваш код, снижающий производительность. Но сначала попробуйте диагностировать и провести рефакторинг.

Наконец, проверьте RubyProf , чтобы узнать, может ли это помочь вам найти узкое место.

3 голосов
/ 19 февраля 2009

Предыдущие два ответа полезны, особенно с использованием инструментов мониторинга производительности. Я использую New Relic RPM , и это очень помогло мне в прошлом.

Тем не менее, эти виды инструментов действительно лучше, когда вы пытаетесь ускорить, скажем, от 3 секунд до 1 секунды.

2-4 минуты для визуализации абсолютно ненормально при любых нормальных обстоятельствах.

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

Включаете ли вы в браузер время загрузки изображений, javascripts или других файлов в это общее измерение?

0 голосов
/ 23 июля 2014

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

Как уже говорилось в других ответах, если обе модели связаны, вы должны стремиться загрузить ассоциации, что подразумевает указание Active Record выполнить запросы на соединение:

#left outer join
ofkbs=Ofkb.includes(:operation).where(name: "banana")

Если вам нужны не okbs, а только операции, вы можете выполнить внутреннее объединение

#inner join (discards the Ofkbs that do not have any operation)
operations=Operation.joins(:ofkb).where(ofkb:{name:"banana"})

Это решение выполняет предварительную обработку только одного запроса и позволяет впоследствии выполнять итерацию по данным, которые уже были собраны из БД:

operations=ofkbs.map{|of| of.operations}.flatten

operations.each do |o|
  do_whatever_you_want_with_operation(o)
end

Если запросы очень сложные, вместо них следует использовать arel .

0 голосов
/ 11 ноября 2010

Когда я привязал сервер к IP-адресу ящика вместо 0.0.0.0, это ускорило для меня все.

0 голосов
/ 25 февраля 2009

Есть несколько хороших скриншотов на эту тему http://railslab.newrelic.com/scaling-rails

Такие вещи, как кэширование фрагментов и использование: include (чтобы избежать n + 1) могут помочь Похоже, вы уже используете memcached, так почему бы не свернуть URL, чтобы предварительно извлечь кеш?

0 голосов
/ 20 февраля 2009

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

0 голосов
/ 19 февраля 2009

Вы можете попробовать использовать JRuby или переключиться на Ruby 1.9.
Оба они должны привести к значительному повышению производительности.
Проблема с JRuby в том, что гемы, использующие C, не будут компилироваться / работать. Есть Java-эквиваленты, которые устанавливаются приложением jruby "gem", но некоторые из них просто не работают

У вас, в принципе, будет такая же проблема с Ruby 1.9. Немного изменился синтаксис, но главная проблема в том, что огромное количество драгоценных камней больше не работает. Люди в процессе обновления хотя (проверить прогресс на http://isitruby19.com/)

...