Оптимизация загрузки данных в бд из json и загрузки страницы#117
Оптимизация загрузки данных в бд из json и загрузки страницы#117lightalloy wants to merge 9 commits intohardcode-dev:masterfrom
Conversation
| described_class.call(Rails.root.join("fixtures/example.json")) | ||
| end.to change(City, :count).by(2).and change(Service, :count).by(2).and change(Bus, :count).by(1).and change(Trip, :count).by(10) | ||
|
|
||
| expect(Bus.last.services.count).to eq(2) |
There was a problem hiding this comment.
Базовый тест, можно бы разбить, но для наших целей хватит))
Также не помешал бы тест на производительность.
|
|
||
| Решила рискнуть и попробовать на `1M.json`, получилось за 30 секунд. Как так? Все записи на месте в бд. | ||
|
|
||
| ## Б. Отображение расписаний |
There was a problem hiding this comment.
Не помешало бы реквест-тест добавить, моя недоработка )
Хоть и изменения минимальные в этом пункте.
There was a problem hiding this comment.
в ПР видел ещё тесты на view, вот это крутотень конечно
There was a problem hiding this comment.
Ну реквест- типа интеграционные, покроют и вью (в той мере, в к-й напишем :)
| t.index ["name"], name: "index_services_on_name", unique: true | ||
| end | ||
|
|
||
| create_table "trips", force: :cascade do |t| |
There was a problem hiding this comment.
Вообще думаю, что индексы на to_id и тд связи не помешали бы ))
There was a problem hiding this comment.
Но почему то нигде не показало что поиск по Trip какой то медленный запрос, я поэтому и не стал ничего добавлять. Надо следовать мантре)
There was a problem hiding this comment.
Согласна. В реальном приложении важна ещё согласованность данных, это, конечно про foreign key, но индекс обычно сразу тоже.
Сейчас попробовала для интереса добавить внешние ключи и индексы. Конечно, вставка стала намного медленнее - ведь субд индексы ещё поддерживать нужно в актуальном состоянии.
There was a problem hiding this comment.
А отображение страницы с индексами - первый запрос так же +-, последующие в 2 раза быстрее где-то.
There was a problem hiding this comment.
Т.е. как всегда - решение зависит от целей :)
| @from = City.find_by_name!(params[:from]) | ||
| @to = City.find_by_name!(params[:to]) | ||
| @trips = Trip.where(from: @from, to: @to).order(:start_time) | ||
| @trips = Trip.where(from: @from, to: @to).includes(bus: :services).order(:start_time) |
There was a problem hiding this comment.
💪
Любопытно только, почему ты добавила его после where?
There was a problem hiding this comment.
Не специально. Вообще ar соберёт.
| # вот такой insert into buses_services | ||
| # вообще чаще используем has_and_belongs_to_many , потому что часто в связке потом нужны доп. данные и таймстемпы, и свой id | ||
| # тогда можно было бы insert_all использовать | ||
| if buses_services.present? |
There was a problem hiding this comment.
Ухты, не подумал что так можно было buses_services одним запросом вставить
|
|
||
| Время: 632 | ||
|
|
||
| Решила, что этого хватит. |
| end | ||
|
|
||
| def call | ||
| json = JSON.parse(File.read(file)) |
There was a problem hiding this comment.
Можно поробовать разбирать JSON потоков
https://github.com/dgraham/yajl-ffi
https://github.com/dgraham/json-stream
И ваще курутотень будет)
| gem 'rspec-rails' | ||
| gem 'rack-mini-profiler' | ||
| gem 'ruby-prof' | ||
| gem 'strong_migrations' |
| @@ -0,0 +1,94 @@ | |||
| class TripsImporter | |||
| <% end %> | ||
| </ul> | ||
| <%= render "delimiter" %> | ||
| ==================================================== |
There was a problem hiding this comment.
можно оставить паршлы, применить рендеринг коллекций и там даже можно delimiter (spacer) задать параметром https://guides.rubyonrails.org/layouts_and_rendering.html#spacer-templates
так будет не настолько тормозить, и при этом сохраняется удобство декомпозиции на паршлы
| Сначала попробовала поэтапно идти: | ||
|
|
||
| - переписала на один insert trips, не трогая другие части; стало ещё медленнее - откатила пока | ||
| - добавляла уникальные индексы на справочные данные + использовала upsert, но во-первых не так уж сильно оптимизировало, во-вторых оказалось, что `upsert` не возвращает id, если нет вставки. Тест не отловил, т.к. там одна поездка. Дописывать тест не стала (поленилась), но в реальном приложении нужно. |
There was a problem hiding this comment.
при вставке какого-то большого объёма данных может иметь смысл наоборот удалить индексы, вставить все данные, а потом уже пересоздать индексы заново
| @from = City.find_by_name!(params[:from]) | ||
| @to = City.find_by_name!(params[:to]) | ||
| @trips = Trip.where(from: @from, to: @to).order(:start_time) | ||
| @trips = Trip.where(from: @from, to: @to).includes(bus: :services).order(:start_time) |
There was a problem hiding this comment.
по идее не помешало бы ещё индекс на trips [from_id, to_id], можно составной
именно на время рендеринга это сильно не влияет (так как процент на выполнение этого SQL маленький), но если бы мы заходили со стороны оптимизации БД - там бы это очень помогло;
вынесла код в service object
тест на основную функциональность
оптимизировала вставку в бд
оптмизировала загрузку страницы