Ruby On Rails работает медленно?

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

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

Изменить. Во-первых, я был в разработке. окр. В производственной среде самый медленный просмотр занимает 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 для тех методов, которые подходят, если только вы не запросите страницу первым.


person Giann    schedule 19.02.2009    source источник
comment
Кроме того, вероятно, это медленный код, написанный вами, или тот факт, что вы запускаете производственную среду в процессе разработки. Если бы вы могли опубликовать соответствующее содержание просмотров, мы могли бы дать правильный ответ.   -  person TomHastjarjanto    schedule 19.02.2009
comment
Согласитесь с @Tomh - это совсем не типично даже для больших наборов данных. Нам понадобится дополнительная информация, чтобы поставить какой-либо диагноз.   -  person Sarah Mei    schedule 19.02.2009
comment
Это может показаться глупым, но убедитесь, что вы работаете в производственном режиме. В режиме разработки все классы будут перезагружены при каждом запросе.   -  person Dave Ray    schedule 19.02.2009
comment
Первая глупость: я был в разработке env. Переключитесь на производство, производительность лучше, но все еще не приемлемо. Я ищу плохую логику, которая может замедлить работу приложения.   -  person Giann    schedule 19.02.2009


Ответы (11)


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

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

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

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

В кузнице - профилирование приложений Rails

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

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

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

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

person srboisvert    schedule 20.02.2009

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

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

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

Что-то вроде этого:

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

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

здесь

person Mike Woodhouse    schedule 19.02.2009

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

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

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

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

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

person Joe Soul-bringer    schedule 19.02.2009
comment
Извините, -1 был я. Никаких ссылок на то, что R-n-R (?) Был медленным, что, по моему опыту, казалось аргументированным и ненужным, а также не соответствовало действительности. - person Mike Woodhouse; 20.02.2009
comment
Цитирования не было, но это довольно распространенное мнение, правда оно или нет. - person Craig; 20.02.2009

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

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

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

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

person Alex Wayne    schedule 19.02.2009
comment
Не лучше ли сделать это во-первых, посмотрите rubyprof - person srboisvert; 20.02.2009
comment
Почему ваш метод профилирования заключается в том, чтобы закомментировать фрагменты кода, а не научный метод использования профилировщика? - person yfeldblum; 20.02.2009

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

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

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

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

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

person btw    schedule 19.02.2009
comment
Да, New Relic отлично подходит для отслеживания этого материала. - person Brian Armstrong; 20.08.2010

Такое долгое время выполнения заставило бы меня заподозрить проблему с сетью - может быть, истекло время ожидания DNS-запроса на основном DNS-сервере?

person Ori Pessach    schedule 19.02.2009

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

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

person Marc Seeger    schedule 19.02.2009

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

person Beep beep    schedule 20.02.2009


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

person Harry Forbess    schedule 11.11.2010

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

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

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

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

#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.

person Pedro Rolo    schedule 23.07.2014