Как стать автором
Обновить

Комментарии 8

Спасибо, было интересно.


  1. А как вы выяснили, что дело в памяти? И что контейнер прибивается целиком по oom?
  2. А сколько занимает сам отчёт, на построение которого уходит 18 Гб памяти? Кажется, что если в итоге размер отчёта — не 18 Гб, то надо было просто оптимизировать запросы к базе, чтобы получать только то, что нужно, а не всё, что есть. Ну или заменить библиотеку построения xlsx, т.к. эта какая-то неэффективная.
1) Я просто попытался воспроизвести в командной строке на сервере вызов сервиса с заданными параметрами, и меня выбрасывало из консоли со 137 ошибкой. Сделали вывод, что дело в памяти (уже с подобным сталкивались)
2) Сам отчет весил несколько мегабайт, может десятки. Запрос, на самом деле, я почти не оптимизировал, только перенес его из одного места в другой, и применил `find_each`. Но вообще память в Ruby раздувается достаточно легко, и самое главное — совсем не умеет «сдуваться» обратно ) Подробней о памяти можно вот в этом посте почитать что раздувает память в Ruby
А вы не пробовали использовать xls вместо xlsx? Он в чем-то более компактен.
Нет, не пробовали, надо будет сравнить их бенчмарки, спасибо )
По сути вывод статьи — используйте find_each, если объектов больше 1000.
И для подтверждения приводится разница между бенчмарками на 100 и 1000.
Ну, раз уж пошла такая пьянка:
conn = ActiveRecord::Base.connection.raw_connection

conn.exec("DECLARE report_data CURSOR FOR #{sql}")

loop do
  data_chunk = conn.exec("FETCH FORWARD 10000 FROM report_data")
  data_chunk.type_map = PG::BasicTypeMapForResults.new(conn)

  data_chunk.each do |row|
     ... магия вроде интернационализации и т.п...
    csv << processed_row
  end

  data_chunk.clear
  # Закомментарено, т.к. если достали все данные, база сама закрывает курсор.
  # conn.exec("CLOSE report_data;")  
end
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.