From a3c748c62745f7f9b337be11cd6a1841fdc6d6d1 Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Thu, 18 Apr 2019 02:06:28 +0300 Subject: [PATCH 01/11] add pghero --- Gemfile | 2 ++ Gemfile.lock | 10 +++++++++- config/application.rb | 1 + config/routes.rb | 7 +++++-- optimization/case-study.md | 21 +++++++++++++++++++++ optimization/feedback-loop.rb | 26 ++++++++++++++++++++++++++ 6 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 optimization/case-study.md create mode 100644 optimization/feedback-loop.rb diff --git a/Gemfile b/Gemfile index 33017fd..0359d56 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,8 @@ gem 'rails', '~> 5.2.3' gem 'pg', '>= 0.18', '< 2.0' gem 'puma', '~> 3.11' gem 'bootsnap', '>= 1.1.0', require: false +gem 'skylight' +gem 'pghero' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index eb22e16..1b6a2ee 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,8 +77,10 @@ GEM nokogiri (1.10.2) mini_portile2 (~> 2.4.0) pg (1.1.4) + pghero (2.2.0) + activerecord puma (3.12.1) - rack (2.0.6) + rack (2.0.7) rack-test (1.1.0) rack (>= 1.0, < 3) rails (5.2.3) @@ -110,6 +112,10 @@ GEM rb-inotify (0.10.0) ffi (~> 1.0) ruby_dep (1.5.0) + skylight (3.1.5) + skylight-core (= 3.1.5) + skylight-core (3.1.5) + activesupport (>= 4.2.0) sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -138,8 +144,10 @@ DEPENDENCIES byebug listen (>= 3.0.5, < 3.2) pg (>= 0.18, < 2.0) + pghero puma (~> 3.11) rails (~> 5.2.3) + skylight tzinfo-data web-console (>= 3.3.0) diff --git a/config/application.rb b/config/application.rb index 9c33109..fe3da3b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -15,5 +15,6 @@ class Application < Rails::Application # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. + config.skylight.environments += ["development"] end end diff --git a/config/routes.rb b/config/routes.rb index a2da6a7..75e4856 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - get "/" => "statistics#index" - get "автобусы/:from/:to" => "trips#index" + get '/' => 'statistics#index' + get 'автобусы/:from/:to' => 'trips#index' + mount PgHero::Engine, at: 'pghero' end diff --git a/optimization/case-study.md b/optimization/case-study.md new file mode 100644 index 0000000..434b4b2 --- /dev/null +++ b/optimization/case-study.md @@ -0,0 +1,21 @@ +# Case-study оптимизации + +## Актуальная проблема +Загрузка файла с данными расписаний автобусов выполнятся больше минуты. Необходимо оптимизировать механизм перезагрузки расписания из файла так, чтобы он обрабатывал файл в пределах минуты. + +## Формирование метрики + +## Гарантия корректности работы оптимизированной программы + +## Feedback-Loop + +## Фиксируем исходное состоние системы + +## Вникаем в детали системы, чтобы найти 20% точек роста + +## Результаты + +за какое время выполняется импорт файла fixtures/large.json +за какое время рендерится страница автобусы/Самара/Москва + +## Защита от регресса производительности diff --git a/optimization/feedback-loop.rb b/optimization/feedback-loop.rb new file mode 100644 index 0000000..fa49b72 --- /dev/null +++ b/optimization/feedback-loop.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'benchmark/ips' +require 'rake' +require 'bundler' +require_relative '../config/application' +Rails.application.load_tasks + +def reevaluate_metric + Benchmark.ips do |bench| + bench.report('Process large.json') do + Rake::Task['reload_json'].invoke('fixtures/large.json') + end + end +end + +def test_correctness + # File.write('result.json', '') + # work('fixtures/data_fixture.txt') + # expected_result = File.read('fixtures/expected_result_fixture.json') + # passed = expected_result == File.read('result.json') + # passed ? puts('PASSED') : puts('!!! TEST FAILED !!!') +end + +reevaluate_metric +test_correctness From 59b72616bc2e89befee153ffeb44549746206fe0 Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Thu, 18 Apr 2019 22:04:03 +0300 Subject: [PATCH 02/11] add cpu profiler to feedbackloop --- Gemfile | 1 + Gemfile.lock | 2 ++ app/services/trips_service.rb | 46 +++++++++++++++++++++++++++++++ optimization/feedback-loop.rb | 52 +++++++++++++++++++++++++++++------ 4 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 app/services/trips_service.rb diff --git a/Gemfile b/Gemfile index 0359d56..2992182 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,7 @@ gem 'puma', '~> 3.11' gem 'bootsnap', '>= 1.1.0', require: false gem 'skylight' gem 'pghero' +gem 'ruby-prof' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index 1b6a2ee..0fabb90 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,6 +111,7 @@ GEM rb-fsevent (0.10.3) rb-inotify (0.10.0) ffi (~> 1.0) + ruby-prof (0.17.0) ruby_dep (1.5.0) skylight (3.1.5) skylight-core (= 3.1.5) @@ -147,6 +148,7 @@ DEPENDENCIES pghero puma (~> 3.11) rails (~> 5.2.3) + ruby-prof skylight tzinfo-data web-console (>= 3.3.0) diff --git a/app/services/trips_service.rb b/app/services/trips_service.rb new file mode 100644 index 0000000..4480589 --- /dev/null +++ b/app/services/trips_service.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'json' + +class TripsService + def self.load(file_name) + new(file_name).load + end + + def initialize(file_name) + @file_name = file_name + end + + def load + json = JSON.parse(File.read(@file_name)) + + ::ActiveRecord::Base.transaction do + City.delete_all + Bus.delete_all + Service.delete_all + Trip.delete_all + ::ActiveRecord::Base.connection.execute('delete from buses_services;') + + json.each do |trip| + from = City.find_or_create_by(name: trip['from']) + to = City.find_or_create_by(name: trip['to']) + services = [] + trip['bus']['services'].each do |service| + s = Service.find_or_create_by(name: service) + services << s + end + bus = Bus.find_or_create_by(number: trip['bus']['number']) + bus.update(model: trip['bus']['model'], services: services) + + Trip.create!( + from: from, + to: to, + bus: bus, + start_time: trip['start_time'], + duration_minutes: trip['duration_minutes'], + price_cents: trip['price_cents'] + ) + end + end + end +end diff --git a/optimization/feedback-loop.rb b/optimization/feedback-loop.rb index fa49b72..9f1210f 100644 --- a/optimization/feedback-loop.rb +++ b/optimization/feedback-loop.rb @@ -1,16 +1,28 @@ # frozen_string_literal: true require 'benchmark/ips' -require 'rake' -require 'bundler' -require_relative '../config/application' -Rails.application.load_tasks +require 'ruby-prof' +require 'memory_profiler' +require 'active_record' +require './app/models/application_record' +require './app/services/trips_service' +require './app/models/city' +require './app/models/bus' +require './app/models/service' +require './app/models/trip' + +config = YAML.load_file('config/database.yml')['development'] +ActiveRecord::Base.establish_connection(config) + +GC.enable_stats +RubyProf.measure_mode = RubyProf::WALL_TIME def reevaluate_metric Benchmark.ips do |bench| - bench.report('Process large.json') do - Rake::Task['reload_json'].invoke('fixtures/large.json') - end + bench.report('small') { TripsService.load('fixtures/small.json') } + # bench.report('medium') { TripsService.load('fixtures/medium.json') } + # bench.report('large') { TripsService.load('fixtures/large.json') } + bench.compare! end end @@ -22,5 +34,29 @@ def test_correctness # passed ? puts('PASSED') : puts('!!! TEST FAILED !!!') end -reevaluate_metric +def cpu_profile + result = RubyProf.profile do + TripsService.load('fixtures/small.json') + end + + # File.open './cpu-time-call-stack.html', 'w' do |file| + # RubyProf::CallStackPrinter.new(result).print(file) + # end + + File.open './wall-time-cal-tree.txt', 'w' do |_file| + RubyProf::CallTreePrinter.new(result).print(path: '.', profile: 'profile') + end +end + +def memory_profile + report = MemoryProfiler.report do + TripsService.load('fixtures/small.json') + end + + report.pretty_print(scale_bytes: true) +end + +# reevaluate_metric test_correctness +# cpu_profile +memory_profile From 4102f57567127f206a5db4da9612173da0deb565 Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Sat, 20 Apr 2019 02:09:22 +0300 Subject: [PATCH 03/11] add rspec --- .rspec | 1 + Gemfile | 8 +- Gemfile.lock | 39 ++++- ...ips_service.rb => import_trips_service.rb} | 27 +++- lib/tasks/utils.rake | 60 +++---- optimization/feedback-loop.rb | 9 +- optimization/task-4.rb | 38 +++++ spec/fixtures/example.json | 152 ++++++++++++++++++ spec/rails_helper.rb | 73 +++++++++ spec/services/import_trips_service_spec.rb | 19 +++ spec/spec_helper.rb | 96 +++++++++++ test/application_system_test_case.rb | 5 - test/controllers/.keep | 0 test/fixtures/.keep | 0 test/fixtures/files/.keep | 0 test/helpers/.keep | 0 test/integration/.keep | 0 test/mailers/.keep | 0 test/models/.keep | 0 test/system/.keep | 0 test/test_helper.rb | 10 -- 21 files changed, 481 insertions(+), 56 deletions(-) create mode 100644 .rspec rename app/services/{trips_service.rb => import_trips_service.rb} (64%) create mode 100644 optimization/task-4.rb create mode 100644 spec/fixtures/example.json create mode 100644 spec/rails_helper.rb create mode 100644 spec/services/import_trips_service_spec.rb create mode 100644 spec/spec_helper.rb delete mode 100644 test/application_system_test_case.rb delete mode 100644 test/controllers/.keep delete mode 100644 test/fixtures/.keep delete mode 100644 test/fixtures/files/.keep delete mode 100644 test/helpers/.keep delete mode 100644 test/integration/.keep delete mode 100644 test/mailers/.keep delete mode 100644 test/models/.keep delete mode 100644 test/system/.keep delete mode 100644 test/test_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/Gemfile b/Gemfile index 2992182..cf50e77 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,8 @@ gem 'puma', '~> 3.11' gem 'bootsnap', '>= 1.1.0', require: false gem 'skylight' gem 'pghero' -gem 'ruby-prof' +gem 'activerecord-import' +gem 'oj' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -23,6 +24,11 @@ group :development do end group :test do + gem 'rspec' + gem 'rspec-rails' + gem 'rspec-sqlimit' + gem 'test-prof' + gem 'database_cleaner' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 0fabb90..7a95a05 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -33,6 +33,8 @@ GEM activemodel (= 5.2.3) activesupport (= 5.2.3) arel (>= 9.0) + activerecord-import (1.0.1) + activerecord (>= 3.2) activestorage (5.2.3) actionpack (= 5.2.3) activerecord (= 5.2.3) @@ -50,6 +52,8 @@ GEM byebug (11.0.1) concurrent-ruby (1.1.5) crass (1.0.4) + database_cleaner (1.7.0) + diff-lcs (1.3) erubi (1.8.0) ffi (1.10.0) globalid (0.4.2) @@ -76,6 +80,7 @@ GEM nio4r (2.3.1) nokogiri (1.10.2) mini_portile2 (~> 2.4.0) + oj (3.7.12) pg (1.1.4) pghero (2.2.0) activerecord @@ -111,7 +116,30 @@ GEM rb-fsevent (0.10.3) rb-inotify (0.10.0) ffi (~> 1.0) - ruby-prof (0.17.0) + rspec (3.8.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-rails (3.8.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-support (~> 3.8.0) + rspec-sqlimit (0.0.2) + rails (> 4.0, < 6.0) + rspec (~> 3.0) + rspec-support (3.8.0) ruby_dep (1.5.0) skylight (3.1.5) skylight-core (= 3.1.5) @@ -124,6 +152,7 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + test-prof (0.8.0) thor (0.20.3) thread_safe (0.3.6) tzinfo (1.2.5) @@ -141,15 +170,21 @@ PLATFORMS ruby DEPENDENCIES + activerecord-import bootsnap (>= 1.1.0) byebug + database_cleaner listen (>= 3.0.5, < 3.2) + oj pg (>= 0.18, < 2.0) pghero puma (~> 3.11) rails (~> 5.2.3) - ruby-prof + rspec + rspec-rails + rspec-sqlimit skylight + test-prof tzinfo-data web-console (>= 3.3.0) diff --git a/app/services/trips_service.rb b/app/services/import_trips_service.rb similarity index 64% rename from app/services/trips_service.rb rename to app/services/import_trips_service.rb index 4480589..ca0f2c0 100644 --- a/app/services/trips_service.rb +++ b/app/services/import_trips_service.rb @@ -1,25 +1,40 @@ # frozen_string_literal: true -require 'json' +# require 'oj' -class TripsService +class ImportTripsService def self.load(file_name) new(file_name).load end + attr_reader :json + def initialize(file_name) - @file_name = file_name + # @file_name = file_name + @json = Oj.load(File.read(file_name)) end def load - json = JSON.parse(File.read(@file_name)) + # json = Oj.load(File.read(file_name)) - ::ActiveRecord::Base.transaction do + ActiveRecord::Base.transaction do City.delete_all Bus.delete_all Service.delete_all Trip.delete_all - ::ActiveRecord::Base.connection.execute('delete from buses_services;') + ActiveRecord::Base.connection.execute('delete from buses_services;') + + # def load_cities + # sities = [] + + # json.each do |trip| + # sities << trip['from'] + # sities << trip['to'] + # end + + # sities.uniq! + # City.import + # end json.each do |trip| from = City.find_or_create_by(name: trip['from']) diff --git a/lib/tasks/utils.rake b/lib/tasks/utils.rake index 540fe87..23beccb 100644 --- a/lib/tasks/utils.rake +++ b/lib/tasks/utils.rake @@ -1,34 +1,38 @@ -# Наивная загрузка данных из json-файла в БД +# frozen_string_literal: true + # rake reload_json[fixtures/small.json] task :reload_json, [:file_name] => :environment do |_task, args| - json = JSON.parse(File.read(args.file_name)) + # puts Benchmark.measure do + + ImportTripsService.load(args[:file_name]) + # json = JSON.parse(File.read(args[:file_name])) - ActiveRecord::Base.transaction do - City.delete_all - Bus.delete_all - Service.delete_all - Trip.delete_all - ActiveRecord::Base.connection.execute('delete from buses_services;') + # ActiveRecord::Base.transaction do + # City.delete_all + # Bus.delete_all + # Service.delete_all + # Trip.delete_all + # ActiveRecord::Base.connection.execute('delete from buses_services;') - json.each do |trip| - from = City.find_or_create_by(name: trip['from']) - to = City.find_or_create_by(name: trip['to']) - services = [] - trip['bus']['services'].each do |service| - s = Service.find_or_create_by(name: service) - services << s - end - bus = Bus.find_or_create_by(number: trip['bus']['number']) - bus.update(model: trip['bus']['model'], services: services) + # json.each do |trip| + # from = City.find_or_create_by(name: trip['from']) + # to = City.find_or_create_by(name: trip['to']) + # services = [] + # trip['bus']['services'].each do |service| + # s = Service.find_or_create_by(name: service) + # services << s + # end + # bus = Bus.find_or_create_by(number: trip['bus']['number']) + # bus.update(model: trip['bus']['model'], services: services) - Trip.create!( - from: from, - to: to, - bus: bus, - start_time: trip['start_time'], - duration_minutes: trip['duration_minutes'], - price_cents: trip['price_cents'], - ) - end - end + # Trip.create!( + # from: from, + # to: to, + # bus: bus, + # start_time: trip['start_time'], + # duration_minutes: trip['duration_minutes'], + # price_cents: trip['price_cents'] + # ) + # end + # end end diff --git a/optimization/feedback-loop.rb b/optimization/feedback-loop.rb index 9f1210f..5a95eb8 100644 --- a/optimization/feedback-loop.rb +++ b/optimization/feedback-loop.rb @@ -22,7 +22,7 @@ def reevaluate_metric bench.report('small') { TripsService.load('fixtures/small.json') } # bench.report('medium') { TripsService.load('fixtures/medium.json') } # bench.report('large') { TripsService.load('fixtures/large.json') } - bench.compare! + # bench.compare! end end @@ -53,10 +53,11 @@ def memory_profile TripsService.load('fixtures/small.json') end - report.pretty_print(scale_bytes: true) + # report.pretty_print(scale_bytes: true) + report.pretty_print(to_file: 'memory.txt') end -# reevaluate_metric +reevaluate_metric test_correctness # cpu_profile -memory_profile +# memory_profile diff --git a/optimization/task-4.rb b/optimization/task-4.rb new file mode 100644 index 0000000..ecacdb1 --- /dev/null +++ b/optimization/task-4.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rubygems' +require 'active_record' +require 'pg' + +def work(file_name) + json = JSON.parse(File.read(file_name)) + + ActiveRecord::Base.transaction do + City.delete_all + Bus.delete_all + Service.delete_all + Trip.delete_all + ActiveRecord::Base.connection.execute('delete from buses_services;') + + json.each do |trip| + from = City.find_or_create_by(name: trip['from']) + to = City.find_or_create_by(name: trip['to']) + services = [] + trip['bus']['services'].each do |service| + s = Service.find_or_create_by(name: service) + services << s + end + bus = Bus.find_or_create_by(number: trip['bus']['number']) + bus.update(model: trip['bus']['model'], services: services) + + Trip.create!( + from: from, + to: to, + bus: bus, + start_time: trip['start_time'], + duration_minutes: trip['duration_minutes'], + price_cents: trip['price_cents'] + ) + end + end +end diff --git a/spec/fixtures/example.json b/spec/fixtures/example.json new file mode 100644 index 0000000..510b4c2 --- /dev/null +++ b/spec/fixtures/example.json @@ -0,0 +1,152 @@ +[ + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 168, + "from": "Москва", + "price_cents": 474, + "start_time": "11:00", + "to": "Самара" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 37, + "from": "Самара", + "price_cents": 173, + "start_time": "17:30", + "to": "Москва" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 323, + "from": "Москва", + "price_cents": 672, + "start_time": "12:00", + "to": "Самара" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 315, + "from": "Самара", + "price_cents": 969, + "start_time": "18:30", + "to": "Москва" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 304, + "from": "Москва", + "price_cents": 641, + "start_time": "13:00", + "to": "Самара" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 21, + "from": "Самара", + "price_cents": 663, + "start_time": "19:30", + "to": "Москва" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 598, + "from": "Москва", + "price_cents": 629, + "start_time": "14:00", + "to": "Самара" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 292, + "from": "Самара", + "price_cents": 22, + "start_time": "20:30", + "to": "Москва" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 127, + "from": "Москва", + "price_cents": 795, + "start_time": "15:00", + "to": "Самара" + }, + { + "bus": { + "model": "Икарус", + "number": "123", + "services": [ + "Туалет", + "WiFi" + ] + }, + "duration_minutes": 183, + "from": "Самара", + "price_cents": 846, + "start_time": "21:30", + "to": "Москва" + } +] diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..10b40a6 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../config/environment', __dir__) +# Prevent database truncation if the environment is production +abort('The Rails environment is running in production mode!') if Rails.env.production? +require 'rspec/rails' +require 'rspec-sqlimit' +require 'test_prof/recipes/rspec/let_it_be' +require 'test_prof/recipes/rspec/before_all' +require 'test_prof/recipes/rspec/any_fixture' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove these lines. +begin + ActiveRecord::Migration.maintain_test_schema! +rescue ActiveRecord::PendingMigrationError => e + puts e.to_s.strip + exit 1 +end +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") + config.before(:suite) { DatabaseCleaner.clean_with :truncation } + config.before(:each) do + DatabaseCleaner[:active_record].strategy = :transaction + DatabaseCleaner.start + end + config.after(:each) { DatabaseCleaner.clean } +end diff --git a/spec/services/import_trips_service_spec.rb b/spec/services/import_trips_service_spec.rb new file mode 100644 index 0000000..f834c34 --- /dev/null +++ b/spec/services/import_trips_service_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ImportTripsService do + subject { ImportTripsService.load('fixtures/example.json') } + + it 'corrects import trips', :aggregate_failures do + subject + expect(City.count).to eq 2 + expect(Trip.count).to eq 10 + expect(Service.count).to eq 2 + expect(Bus.count).to eq 1 + end + + it 'has constant number of requests to DB' do + expect { subject }.not_to exceed_query_limit(96) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..ce33d66 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,96 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb deleted file mode 100644 index d19212a..0000000 --- a/test/application_system_test_case.rb +++ /dev/null @@ -1,5 +0,0 @@ -require "test_helper" - -class ApplicationSystemTestCase < ActionDispatch::SystemTestCase - driven_by :selenium, using: :chrome, screen_size: [1400, 1400] -end diff --git a/test/controllers/.keep b/test/controllers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixtures/.keep b/test/fixtures/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/helpers/.keep b/test/helpers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/integration/.keep b/test/integration/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/mailers/.keep b/test/mailers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/models/.keep b/test/models/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/system/.keep b/test/system/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_helper.rb b/test/test_helper.rb deleted file mode 100644 index 3ab84e3..0000000 --- a/test/test_helper.rb +++ /dev/null @@ -1,10 +0,0 @@ -ENV['RAILS_ENV'] ||= 'test' -require_relative '../config/environment' -require 'rails/test_help' - -class ActiveSupport::TestCase - # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. - fixtures :all - - # Add more helper methods to be used by all tests here... -end From 914b447f1257595730155d083bac5edc47f0a43e Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Sat, 20 Apr 2019 22:16:58 +0300 Subject: [PATCH 04/11] add index to bus --- Gemfile | 2 + Gemfile.lock | 11 +++ app/services/import_trips_service.rb | 84 +++++++++++++------ db/migrate/20190420191017_add_index_to_bus.rb | 9 ++ db/schema.rb | 3 +- 5 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 db/migrate/20190420191017_add_index_to_bus.rb diff --git a/Gemfile b/Gemfile index cf50e77..952833a 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'skylight' gem 'pghero' gem 'activerecord-import' gem 'oj' +gem 'strong_migrations' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -29,6 +30,7 @@ group :test do gem 'rspec-sqlimit' gem 'test-prof' gem 'database_cleaner' + gem 'pry-byebug' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 7a95a05..2c2b7fc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,6 +50,7 @@ GEM msgpack (~> 1.0) builder (3.2.3) byebug (11.0.1) + coderay (1.1.2) concurrent-ruby (1.1.5) crass (1.0.4) database_cleaner (1.7.0) @@ -84,6 +85,12 @@ GEM pg (1.1.4) pghero (2.2.0) activerecord + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-byebug (3.7.0) + byebug (~> 11.0) + pry (~> 0.10) puma (3.12.1) rack (2.0.7) rack-test (1.1.0) @@ -152,6 +159,8 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + strong_migrations (0.3.1) + activerecord (>= 3.2.0) test-prof (0.8.0) thor (0.20.3) thread_safe (0.3.6) @@ -178,12 +187,14 @@ DEPENDENCIES oj pg (>= 0.18, < 2.0) pghero + pry-byebug puma (~> 3.11) rails (~> 5.2.3) rspec rspec-rails rspec-sqlimit skylight + strong_migrations test-prof tzinfo-data web-console (>= 3.3.0) diff --git a/app/services/import_trips_service.rb b/app/services/import_trips_service.rb index ca0f2c0..92f41e3 100644 --- a/app/services/import_trips_service.rb +++ b/app/services/import_trips_service.rb @@ -7,16 +7,16 @@ def self.load(file_name) new(file_name).load end - attr_reader :json + attr_reader :json, :sities, :buses def initialize(file_name) # @file_name = file_name @json = Oj.load(File.read(file_name)) + @sities = {} + @buses = {} end def load - # json = Oj.load(File.read(file_name)) - ActiveRecord::Base.transaction do City.delete_all Bus.delete_all @@ -24,33 +24,24 @@ def load Trip.delete_all ActiveRecord::Base.connection.execute('delete from buses_services;') - # def load_cities - # sities = [] - - # json.each do |trip| - # sities << trip['from'] - # sities << trip['to'] - # end - - # sities.uniq! - # City.import - # end + load_cities + load_buses json.each do |trip| - from = City.find_or_create_by(name: trip['from']) - to = City.find_or_create_by(name: trip['to']) - services = [] - trip['bus']['services'].each do |service| - s = Service.find_or_create_by(name: service) - services << s - end - bus = Bus.find_or_create_by(number: trip['bus']['number']) - bus.update(model: trip['bus']['model'], services: services) - + # from = City.find_or_create_by(name: trip['from']) + # to = City.find_or_create_by(name: trip['to']) + # services = [] + # trip['bus']['services'].each do |service| + # s = Service.find_or_create_by(name: service) + # services << s + # end + # bus = Bus.find_or_create_by(number: trip['bus']['number']) + # bus.update(model: trip['bus']['model'], services: services) + # binding.pry Trip.create!( - from: from, - to: to, - bus: bus, + from_id: sities[trip['from']], + to_id: sities[trip['to']], + bus_id: buses[trip['bus']['number']], start_time: trip['start_time'], duration_minutes: trip['duration_minutes'], price_cents: trip['price_cents'] @@ -58,4 +49,43 @@ def load end end end + + def load_cities + sities_data = [] + + json.each do |trip| + sities_data << [trip['from']] + sities_data << [trip['to']] + end + + sities_data.uniq! + + names = City.import([:name], sities_data, returning: :name) + ids = names.ids + names.results.each.with_index { |name, i| sities[name] = ids[i].to_i } + end + + def load_buses + buses_data = [] + # services = [] + json.each do |trip| + bus = Bus.new(number: trip['bus']['number'], model: trip['bus']['model']) + trip['bus']['services'].each do |service| + bus.services.build(name: service) + end + buses_data << bus + end + binding.pry + numbers = Bus.import buses_data, recursive: true, returning: :number, on_duplicate_key_ignore: true + ids = numbers.ids + numbers.results.each.with_index { |number, i| buses[number] = ids[i].to_i } + # trip['bus']['services'].each do |service| + # s = Service.find_or_create_by(name: service) + # services << s + # end + # end + + # bus = Bus.find_or_create_by(number: trip['bus']['number']) + # bus.update(model: trip['bus']['model'], services: services) + end end diff --git a/db/migrate/20190420191017_add_index_to_bus.rb b/db/migrate/20190420191017_add_index_to_bus.rb new file mode 100644 index 0000000..1480b7b --- /dev/null +++ b/db/migrate/20190420191017_add_index_to_bus.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddIndexToBus < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + add_index :buses, :number, algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index f6921e4..37269c4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_03_30_193044) do +ActiveRecord::Schema.define(version: 2019_04_20_191017) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -18,6 +18,7 @@ create_table "buses", force: :cascade do |t| t.string "number" t.string "model" + t.index ["number"], name: "index_buses_on_number" end create_table "buses_services", force: :cascade do |t| From 98b880d14c87aa7306d440e69c6a9a558b783ddf Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Sun, 21 Apr 2019 03:23:42 +0300 Subject: [PATCH 05/11] add activerecord import --- Gemfile | 2 + Gemfile.lock | 6 + app/models/bus.rb | 27 ++-- app/models/buses_service.rb | 6 + app/models/service.rb | 27 ++-- app/services/import_trips_service.rb | 132 +++++++++++------- db/migrate/20190420191017_add_index_to_bus.rb | 3 +- ...190420204751_add_index_to_buses_service.rb | 9 ++ .../20190420215325_add_index_to_services.rb | 10 ++ db/schema.rb | 10 +- optimization/feedback-loop.rb | 12 +- spec/services/import_trips_service_spec.rb | 3 +- 12 files changed, 160 insertions(+), 87 deletions(-) create mode 100644 app/models/buses_service.rb create mode 100644 db/migrate/20190420204751_add_index_to_buses_service.rb create mode 100644 db/migrate/20190420215325_add_index_to_services.rb diff --git a/Gemfile b/Gemfile index 952833a..55aaac0 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,7 @@ gem 'activerecord-import' gem 'oj' gem 'strong_migrations' + group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] @@ -22,6 +23,7 @@ group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' + gem 'progress_bar' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 2c2b7fc..9179ee7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -59,6 +59,7 @@ GEM ffi (1.10.0) globalid (0.4.2) activesupport (>= 4.2.0) + highline (2.0.2) i18n (1.6.0) concurrent-ruby (~> 1.0) listen (3.1.5) @@ -82,9 +83,13 @@ GEM nokogiri (1.10.2) mini_portile2 (~> 2.4.0) oj (3.7.12) + options (2.3.2) pg (1.1.4) pghero (2.2.0) activerecord + progress_bar (1.3.0) + highline (>= 1.6, < 3) + options (~> 2.3.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -187,6 +192,7 @@ DEPENDENCIES oj pg (>= 0.18, < 2.0) pghero + progress_bar pry-byebug puma (~> 3.11) rails (~> 5.2.3) diff --git a/app/models/bus.rb b/app/models/bus.rb index 1dcc54c..d224860 100644 --- a/app/models/bus.rb +++ b/app/models/bus.rb @@ -1,19 +1,22 @@ +# frozen_string_literal: true + class Bus < ApplicationRecord - MODELS = [ - 'Икарус', - 'Мерседес', - 'Сканиа', - 'Буханка', - 'УАЗ', - 'Спринтер', - 'ГАЗ', - 'ПАЗ', - 'Вольво', - 'Газель', + MODELS = %w[ + Икарус + Мерседес + Сканиа + Буханка + УАЗ + Спринтер + ГАЗ + ПАЗ + Вольво + Газель ].freeze has_many :trips - has_and_belongs_to_many :services, join_table: :buses_services + has_many :buses_services + has_many :services, through: :buses_services validates :number, presence: true, uniqueness: true validates :model, inclusion: { in: MODELS } diff --git a/app/models/buses_service.rb b/app/models/buses_service.rb new file mode 100644 index 0000000..976a0c1 --- /dev/null +++ b/app/models/buses_service.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class BusesService < ApplicationRecord + belongs_to :bus + belongs_to :service +end diff --git a/app/models/service.rb b/app/models/service.rb index 9cbb2a3..81d092f 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -1,18 +1,21 @@ +# frozen_string_literal: true + class Service < ApplicationRecord - SERVICES = [ - 'WiFi', - 'Туалет', - 'Работающий туалет', - 'Ремни безопасности', - 'Кондиционер общий', - 'Кондиционер Индивидуальный', - 'Телевизор общий', - 'Телевизор индивидуальный', - 'Стюардесса', - 'Можно не печатать билет', + SERVICES = %w[ + WiFi + Туалет + Работающий туалет + Ремни безопасности + Кондиционер общий + Кондиционер Индивидуальный + Телевизор общий + Телевизор индивидуальный + Стюардесса + Можно не печатать билет ].freeze - has_and_belongs_to_many :buses, join_table: :buses_services + has_many :buses_services + has_many :buses, through: :buses_services validates :name, presence: true validates :name, inclusion: { in: SERVICES } diff --git a/app/services/import_trips_service.rb b/app/services/import_trips_service.rb index 92f41e3..20678d8 100644 --- a/app/services/import_trips_service.rb +++ b/app/services/import_trips_service.rb @@ -1,91 +1,117 @@ # frozen_string_literal: true -# require 'oj' - class ImportTripsService + BATCH_SIZE = 1000 + def self.load(file_name) new(file_name).load end - attr_reader :json, :sities, :buses + attr_accessor :json, :sities, :buses, :services def initialize(file_name) - # @file_name = file_name @json = Oj.load(File.read(file_name)) @sities = {} @buses = {} + @services = {} end def load ActiveRecord::Base.transaction do - City.delete_all - Bus.delete_all - Service.delete_all - Trip.delete_all - ActiveRecord::Base.connection.execute('delete from buses_services;') - + clean_db! load_cities load_buses - - json.each do |trip| - # from = City.find_or_create_by(name: trip['from']) - # to = City.find_or_create_by(name: trip['to']) - # services = [] - # trip['bus']['services'].each do |service| - # s = Service.find_or_create_by(name: service) - # services << s - # end - # bus = Bus.find_or_create_by(number: trip['bus']['number']) - # bus.update(model: trip['bus']['model'], services: services) - # binding.pry - Trip.create!( - from_id: sities[trip['from']], - to_id: sities[trip['to']], - bus_id: buses[trip['bus']['number']], - start_time: trip['start_time'], - duration_minutes: trip['duration_minutes'], - price_cents: trip['price_cents'] - ) - end + load_services + load_buses_services + load_trips end end + def clean_db! + BusesService.delete_all + Trip.delete_all + City.delete_all + Bus.delete_all + Service.delete_all + end + def load_cities sities_data = [] - + # bar = ProgressBar.new(json.length) json.each do |trip| - sities_data << [trip['from']] - sities_data << [trip['to']] + sities_data << { name: trip['from'] } + sities_data << { name: trip['to'] } + # bar.increment! end sities_data.uniq! - - names = City.import([:name], sities_data, returning: :name) - ids = names.ids - names.results.each.with_index { |name, i| sities[name] = ids[i].to_i } + result = City.import([:name], sities_data, returning: :name, **options) + processing_result result, sities end def load_buses buses_data = [] - # services = [] json.each do |trip| - bus = Bus.new(number: trip['bus']['number'], model: trip['bus']['model']) + buses_data << { + number: trip['bus']['number'], + model: trip['bus']['model'] + } + end + buses_data.uniq! + result = Bus.import(buses_data, returning: :number, **options) + processing_result result, buses + end + + def load_services + services_data = [] + json.each do |trip| trip['bus']['services'].each do |service| - bus.services.build(name: service) + services_data << { name: service } end - buses_data << bus end - binding.pry - numbers = Bus.import buses_data, recursive: true, returning: :number, on_duplicate_key_ignore: true - ids = numbers.ids - numbers.results.each.with_index { |number, i| buses[number] = ids[i].to_i } - # trip['bus']['services'].each do |service| - # s = Service.find_or_create_by(name: service) - # services << s - # end - # end + services_data.uniq! + result = Service.import(services_data, returning: :name, **options) + processing_result result, services + end + + def load_buses_services + buses_services = [] + json.each do |trip| + trip['bus']['services'].each do |service| + buses_services << { + bus_id: buses[trip['bus']['number']], + service_id: services[service] + } + end + end + buses_services.uniq! + BusesService.import(buses_services, options) + end + + def load_trips + trips = [] + json.each do |trip| + trips << { + from_id: sities[trip['from']], + to_id: sities[trip['to']], + bus_id: buses[trip['bus']['number']], + start_time: trip['start_time'], + duration_minutes: trip['duration_minutes'], + price_cents: trip['price_cents'] + } + end + + Trip.import(trips, options) + end + + def options + { + batch_size: BATCH_SIZE + } + end - # bus = Bus.find_or_create_by(number: trip['bus']['number']) - # bus.update(model: trip['bus']['model'], services: services) + def processing_result(selection, collection = {}) + ids = selection.ids + selection.results.each.with_index { |attr, i| collection[attr] = ids[i].to_i } end end diff --git a/db/migrate/20190420191017_add_index_to_bus.rb b/db/migrate/20190420191017_add_index_to_bus.rb index 1480b7b..e04c863 100644 --- a/db/migrate/20190420191017_add_index_to_bus.rb +++ b/db/migrate/20190420191017_add_index_to_bus.rb @@ -4,6 +4,7 @@ class AddIndexToBus < ActiveRecord::Migration[5.2] disable_ddl_transaction! def change - add_index :buses, :number, algorithm: :concurrently + safety_assured { change_column_null :buses, :number, false } + add_index :buses, :number, algorithm: :concurrently, unique: true end end diff --git a/db/migrate/20190420204751_add_index_to_buses_service.rb b/db/migrate/20190420204751_add_index_to_buses_service.rb new file mode 100644 index 0000000..6e6a55c --- /dev/null +++ b/db/migrate/20190420204751_add_index_to_buses_service.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddIndexToBusesService < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + add_index :buses_services, %i[bus_id service_id], algorithm: :concurrently, unique: true + end +end diff --git a/db/migrate/20190420215325_add_index_to_services.rb b/db/migrate/20190420215325_add_index_to_services.rb new file mode 100644 index 0000000..dc5af49 --- /dev/null +++ b/db/migrate/20190420215325_add_index_to_services.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddIndexToServices < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + safety_assured { change_column_null :services, :name, false } + add_index :services, :name, algorithm: :concurrently, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 37269c4..ce840a9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,20 +10,21 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_04_20_191017) do +ActiveRecord::Schema.define(version: 2019_04_20_215325) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" create_table "buses", force: :cascade do |t| - t.string "number" + t.string "number", null: false t.string "model" - t.index ["number"], name: "index_buses_on_number" + t.index ["number"], name: "index_buses_on_number", unique: true end create_table "buses_services", force: :cascade do |t| t.integer "bus_id" t.integer "service_id" + t.index ["bus_id", "service_id"], name: "index_buses_services_on_bus_id_and_service_id", unique: true end create_table "cities", force: :cascade do |t| @@ -31,7 +32,8 @@ end create_table "services", force: :cascade do |t| - t.string "name" + t.string "name", null: false + t.index ["name"], name: "index_services_on_name", unique: true end create_table "trips", force: :cascade do |t| diff --git a/optimization/feedback-loop.rb b/optimization/feedback-loop.rb index 5a95eb8..30f6e8b 100644 --- a/optimization/feedback-loop.rb +++ b/optimization/feedback-loop.rb @@ -5,11 +5,15 @@ require 'memory_profiler' require 'active_record' require './app/models/application_record' -require './app/services/trips_service' +require './app/services/import_trips_service' require './app/models/city' require './app/models/bus' require './app/models/service' require './app/models/trip' +require './app/models/buses_service' +require 'Oj' +require 'progress_bar' +require 'activerecord-import' config = YAML.load_file('config/database.yml')['development'] ActiveRecord::Base.establish_connection(config) @@ -19,7 +23,7 @@ def reevaluate_metric Benchmark.ips do |bench| - bench.report('small') { TripsService.load('fixtures/small.json') } + bench.report('small') { ImportTripsService.load('fixtures/small.json') } # bench.report('medium') { TripsService.load('fixtures/medium.json') } # bench.report('large') { TripsService.load('fixtures/large.json') } # bench.compare! @@ -36,7 +40,7 @@ def test_correctness def cpu_profile result = RubyProf.profile do - TripsService.load('fixtures/small.json') + ImportTripsService.load('fixtures/small.json') end # File.open './cpu-time-call-stack.html', 'w' do |file| @@ -50,7 +54,7 @@ def cpu_profile def memory_profile report = MemoryProfiler.report do - TripsService.load('fixtures/small.json') + ImportTripsService.load('fixtures/small.json') end # report.pretty_print(scale_bytes: true) diff --git a/spec/services/import_trips_service_spec.rb b/spec/services/import_trips_service_spec.rb index f834c34..5c92113 100644 --- a/spec/services/import_trips_service_spec.rb +++ b/spec/services/import_trips_service_spec.rb @@ -11,9 +11,10 @@ expect(Trip.count).to eq 10 expect(Service.count).to eq 2 expect(Bus.count).to eq 1 + expect(BusesService.count).to eq 2 end it 'has constant number of requests to DB' do - expect { subject }.not_to exceed_query_limit(96) + expect { subject }.not_to exceed_query_limit(12) end end From 891a13f40dc3e987203d4d29f70d7d2cb6ce869a Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Sun, 21 Apr 2019 20:27:24 +0300 Subject: [PATCH 06/11] case study 1 --- Gemfile | 2 +- app/services/import_trips_service.rb | 4 +-- optimization/feedback-loop.rb | 45 +++------------------------- 3 files changed, 6 insertions(+), 45 deletions(-) diff --git a/Gemfile b/Gemfile index 55aaac0..0621f1e 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'skylight' gem 'pghero' gem 'activerecord-import' gem 'oj' +gem 'progress_bar' gem 'strong_migrations' @@ -23,7 +24,6 @@ group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' - gem 'progress_bar' end group :test do diff --git a/app/services/import_trips_service.rb b/app/services/import_trips_service.rb index 20678d8..4e433a5 100644 --- a/app/services/import_trips_service.rb +++ b/app/services/import_trips_service.rb @@ -37,15 +37,13 @@ def clean_db! def load_cities sities_data = [] - # bar = ProgressBar.new(json.length) json.each do |trip| sities_data << { name: trip['from'] } sities_data << { name: trip['to'] } - # bar.increment! end sities_data.uniq! - result = City.import([:name], sities_data, returning: :name, **options) + result = City.import(sities_data, returning: :name, **options) processing_result result, sities end diff --git a/optimization/feedback-loop.rb b/optimization/feedback-loop.rb index 30f6e8b..289c83b 100644 --- a/optimization/feedback-loop.rb +++ b/optimization/feedback-loop.rb @@ -11,57 +11,20 @@ require './app/models/service' require './app/models/trip' require './app/models/buses_service' -require 'Oj' +require 'oj' require 'progress_bar' require 'activerecord-import' config = YAML.load_file('config/database.yml')['development'] ActiveRecord::Base.establish_connection(config) -GC.enable_stats -RubyProf.measure_mode = RubyProf::WALL_TIME - def reevaluate_metric Benchmark.ips do |bench| bench.report('small') { ImportTripsService.load('fixtures/small.json') } - # bench.report('medium') { TripsService.load('fixtures/medium.json') } - # bench.report('large') { TripsService.load('fixtures/large.json') } - # bench.compare! + bench.report('medium') { ImportTripsService.load('fixtures/medium.json') } + bench.report('large') { ImportTripsService.load('fixtures/large.json') } + bench.compare! end end -def test_correctness - # File.write('result.json', '') - # work('fixtures/data_fixture.txt') - # expected_result = File.read('fixtures/expected_result_fixture.json') - # passed = expected_result == File.read('result.json') - # passed ? puts('PASSED') : puts('!!! TEST FAILED !!!') -end - -def cpu_profile - result = RubyProf.profile do - ImportTripsService.load('fixtures/small.json') - end - - # File.open './cpu-time-call-stack.html', 'w' do |file| - # RubyProf::CallStackPrinter.new(result).print(file) - # end - - File.open './wall-time-cal-tree.txt', 'w' do |_file| - RubyProf::CallTreePrinter.new(result).print(path: '.', profile: 'profile') - end -end - -def memory_profile - report = MemoryProfiler.report do - ImportTripsService.load('fixtures/small.json') - end - - # report.pretty_print(scale_bytes: true) - report.pretty_print(to_file: 'memory.txt') -end - reevaluate_metric -test_correctness -# cpu_profile -# memory_profile From be28a277b47f43b6bc7849efac30a8532722d6b7 Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Sun, 21 Apr 2019 23:35:36 +0300 Subject: [PATCH 07/11] fix n+1 --- Gemfile | 6 +++ Gemfile.lock | 48 +++++++++++++++++++ app/controllers/trips_controller.rb | 4 +- config/environments/development.rb | 10 ++++ ...0190421185932_add_foreign_keys_to_trips.rb | 10 ++++ db/schema.rb | 4 +- spec/controllers/trips_controller_spec.rb | 19 ++++++++ spec/factories.rb | 34 +++++++++++++ spec/rails_helper.rb | 2 + 9 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20190421185932_add_foreign_keys_to_trips.rb create mode 100644 spec/controllers/trips_controller_spec.rb create mode 100644 spec/factories.rb diff --git a/Gemfile b/Gemfile index 0621f1e..279b45e 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,8 @@ gem 'activerecord-import' gem 'oj' gem 'progress_bar' gem 'strong_migrations' +gem 'newrelic_rpm' + group :development, :test do @@ -24,6 +26,7 @@ group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' + gem 'bullet' end group :test do @@ -32,6 +35,9 @@ group :test do gem 'rspec-sqlimit' gem 'test-prof' gem 'database_cleaner' + gem 'n_plus_one_control' + gem 'factory_bot_rails' + gem 'faker', :git => 'https://github.com/stympy/faker.git', :branch => 'master' gem 'pry-byebug' end diff --git a/Gemfile.lock b/Gemfile.lock index 9179ee7..0e5913e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,16 @@ +GIT + remote: https://github.com/stympy/faker.git + revision: 59a92644d5583828add1c68351074f6e52c6deb6 + branch: master + specs: + faker (1.9.3) + i18n (>= 0.7) + pastel (~> 0.7.2) + thor (~> 0.20.0) + tty-pager (~> 0.12.0) + tty-screen (~> 0.6.5) + tty-tree (~> 0.2.0) + GEM remote: https://rubygems.org/ specs: @@ -49,13 +62,22 @@ GEM bootsnap (1.4.2) msgpack (~> 1.0) builder (3.2.3) + bullet (5.9.0) + activesupport (>= 3.0.0) + uniform_notifier (~> 1.11) byebug (11.0.1) coderay (1.1.2) concurrent-ruby (1.1.5) crass (1.0.4) database_cleaner (1.7.0) diff-lcs (1.3) + equatable (0.5.0) erubi (1.8.0) + factory_bot (5.0.2) + activesupport (>= 4.2.0) + factory_bot_rails (5.0.2) + factory_bot (~> 5.0.2) + railties (>= 4.2.0) ffi (1.10.0) globalid (0.4.2) activesupport (>= 4.2.0) @@ -79,11 +101,16 @@ GEM mini_portile2 (2.4.0) minitest (5.11.3) msgpack (1.2.9) + n_plus_one_control (0.3.1) + newrelic_rpm (6.2.0.354) nio4r (2.3.1) nokogiri (1.10.2) mini_portile2 (~> 2.4.0) oj (3.7.12) options (2.3.2) + pastel (0.7.2) + equatable (~> 0.5.0) + tty-color (~> 0.4.0) pg (1.1.4) pghero (2.2.0) activerecord @@ -164,13 +191,29 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + strings (0.1.5) + strings-ansi (~> 0.1) + unicode-display_width (~> 1.5) + unicode_utils (~> 1.4) + strings-ansi (0.1.0) strong_migrations (0.3.1) activerecord (>= 3.2.0) test-prof (0.8.0) thor (0.20.3) thread_safe (0.3.6) + tty-color (0.4.3) + tty-pager (0.12.1) + strings (~> 0.1.4) + tty-screen (~> 0.6) + tty-which (~> 0.4) + tty-screen (0.6.5) + tty-tree (0.2.0) + tty-which (0.4.0) tzinfo (1.2.5) thread_safe (~> 0.1) + unicode-display_width (1.5.0) + unicode_utils (1.4.0) + uniform_notifier (1.12.1) web-console (3.7.0) actionview (>= 5.0) activemodel (>= 5.0) @@ -186,9 +229,14 @@ PLATFORMS DEPENDENCIES activerecord-import bootsnap (>= 1.1.0) + bullet byebug database_cleaner + factory_bot_rails + faker! listen (>= 3.0.5, < 3.2) + n_plus_one_control + newrelic_rpm oj pg (>= 0.18, < 2.0) pghero diff --git a/app/controllers/trips_controller.rb b/app/controllers/trips_controller.rb index acb38be..36481d8 100644 --- a/app/controllers/trips_controller.rb +++ b/app/controllers/trips_controller.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class TripsController < ApplicationController def index @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.preload(bus: :services).where(from: @from, to: @to).order(:start_time) end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 1311e3e..115845c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -58,4 +60,12 @@ # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + config.after_initialize do + Bullet.enable = true + Bullet.alert = true + Bullet.bullet_logger = true + Bullet.console = true + Bullet.add_footer = true + end end diff --git a/db/migrate/20190421185932_add_foreign_keys_to_trips.rb b/db/migrate/20190421185932_add_foreign_keys_to_trips.rb new file mode 100644 index 0000000..76ce860 --- /dev/null +++ b/db/migrate/20190421185932_add_foreign_keys_to_trips.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddForeignKeysToTrips < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + add_foreign_key :trips, :cities, column: :to_id + add_foreign_key :trips, :cities, column: :from_id + end +end diff --git a/db/schema.rb b/db/schema.rb index ce840a9..8f9b162 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_04_20_215325) do +ActiveRecord::Schema.define(version: 2019_04_21_185932) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -45,4 +45,6 @@ t.integer "bus_id" end + add_foreign_key "trips", "cities", column: "from_id" + add_foreign_key "trips", "cities", column: "to_id" end diff --git a/spec/controllers/trips_controller_spec.rb b/spec/controllers/trips_controller_spec.rb new file mode 100644 index 0000000..7aec54d --- /dev/null +++ b/spec/controllers/trips_controller_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe TripsController do + describe 'GET index' do + let_it_be(:moscow) { create(:city, name: 'Москва') } + let_it_be(:samara) { create(:city, name: 'Самара') } + + context 'N+1', :n_plus_one do + populate { |n| create_list(:trip, n) } + + specify do + expect { get :index, params: { from: moscow.name, to: samara.name } } + .to perform_constant_number_of_queries + end + end + end +end diff --git a/spec/factories.rb b/spec/factories.rb new file mode 100644 index 0000000..aca9b9e --- /dev/null +++ b/spec/factories.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :trip do + from + to + bus + duration_minutes { 200 } + start_time { '11:45' } + price_cents { 100 } + end + + factory :city, aliases: %i[to from] do + name { Faker::Address.city.tr(' ', '_') } + end + + factory :bus do + number { Faker::Number.number(5) } + model { Bus::MODELS[rand(0..9)] } + + after(:create) do |bus, _evaluator| + create_list(:buses_service, 5, bus: bus) + end + end + + factory :service do + name { Service::SERVICES[rand(0..9)] } + end + + factory :buses_service do + bus + service + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 10b40a6..bc5fa38 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -11,6 +11,7 @@ require 'test_prof/recipes/rspec/let_it_be' require 'test_prof/recipes/rspec/before_all' require 'test_prof/recipes/rspec/any_fixture' +require 'n_plus_one_control/rspec' # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in @@ -37,6 +38,7 @@ exit 1 end RSpec.configure do |config| + config.include FactoryBot::Syntax::Methods # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" From aa5a4d7796b248fc677f464272359ba0a007fd8c Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Sun, 21 Apr 2019 23:55:52 +0300 Subject: [PATCH 08/11] optimization 2 --- app/views/trips/_delimiter.html.erb | 1 - app/views/trips/_service.html.erb | 1 - app/views/trips/_services.html.erb | 6 ------ app/views/trips/_trip.html.erb | 24 +++++++++++++++++----- app/views/trips/index.html.erb | 12 ++--------- lib/tasks/utils.rake | 32 ----------------------------- 6 files changed, 21 insertions(+), 55 deletions(-) delete mode 100644 app/views/trips/_delimiter.html.erb delete mode 100644 app/views/trips/_service.html.erb delete mode 100644 app/views/trips/_services.html.erb diff --git a/app/views/trips/_delimiter.html.erb b/app/views/trips/_delimiter.html.erb deleted file mode 100644 index 3f845ad..0000000 --- a/app/views/trips/_delimiter.html.erb +++ /dev/null @@ -1 +0,0 @@ -==================================================== diff --git a/app/views/trips/_service.html.erb b/app/views/trips/_service.html.erb deleted file mode 100644 index 178ea8c..0000000 --- a/app/views/trips/_service.html.erb +++ /dev/null @@ -1 +0,0 @@ -
  • <%= "#{service.name}" %>
  • diff --git a/app/views/trips/_services.html.erb b/app/views/trips/_services.html.erb deleted file mode 100644 index 2de639f..0000000 --- a/app/views/trips/_services.html.erb +++ /dev/null @@ -1,6 +0,0 @@ -
  • Сервисы в автобусе:
  • -
      - <% services.each do |service| %> - <%= render "service", service: service %> - <% end %> -
    diff --git a/app/views/trips/_trip.html.erb b/app/views/trips/_trip.html.erb index fa1de9a..731ab82 100644 --- a/app/views/trips/_trip.html.erb +++ b/app/views/trips/_trip.html.erb @@ -1,5 +1,19 @@ -
  • <%= "Отправление: #{trip.start_time}" %>
  • -
  • <%= "Прибытие: #{(Time.parse(trip.start_time) + trip.duration_minutes.minutes).strftime('%H:%M')}" %>
  • -
  • <%= "В пути: #{trip.duration_minutes / 60}ч. #{trip.duration_minutes % 60}мин." %>
  • -
  • <%= "Цена: #{trip.price_cents / 100}р. #{trip.price_cents % 100}коп." %>
  • -
  • <%= "Автобус: #{trip.bus.model} №#{trip.bus.number}" %>
  • +
      +
    • <%= "Отправление: #{ trip.start_time }" %>
    • +
    • <%= "Прибытие: #{ (Time.parse(trip.start_time) + trip.duration_minutes.minutes ).strftime('%H:%M')}" %>
    • +
    • <%= "В пути: #{ trip.duration_minutes / 60 }ч. #{ trip.duration_minutes % 60 }мин." %>
    • +
    • <%= "Цена: #{ trip.price_cents / 100 }р. #{ trip.price_cents % 100 }коп." %>
    • +
    • <%= "Автобус: #{ trip.bus.model } №#{ trip.bus.number }" %>
    • + + <% if trip.bus.services.exists? %> +
    • Сервисы в автобусе:
    • +
        + <% trip.bus.services.each do |service| %> + <% cache service do %> +
      • <%= "#{service.name}" %>
      • + <% end %> + <% end %> +
      + <% end %> +
    +==================================================== diff --git a/app/views/trips/index.html.erb b/app/views/trips/index.html.erb index a60bce4..40f35c2 100644 --- a/app/views/trips/index.html.erb +++ b/app/views/trips/index.html.erb @@ -2,15 +2,7 @@ <%= "Автобусы #{@from.name} – #{@to.name}" %>

    - <%= "В расписании #{@trips.count} рейсов" %> + <%= "В расписании #{@trips.length} рейсов" %>

    -<% @trips.each do |trip| %> -
      - <%= render "trip", trip: trip %> - <% if trip.bus.services.present? %> - <%= render "services", services: trip.bus.services %> - <% end %> -
    - <%= render "delimiter" %> -<% end %> +<%= render @trips, cached: true %> diff --git a/lib/tasks/utils.rake b/lib/tasks/utils.rake index 23beccb..1f23da9 100644 --- a/lib/tasks/utils.rake +++ b/lib/tasks/utils.rake @@ -2,37 +2,5 @@ # rake reload_json[fixtures/small.json] task :reload_json, [:file_name] => :environment do |_task, args| - # puts Benchmark.measure do - ImportTripsService.load(args[:file_name]) - # json = JSON.parse(File.read(args[:file_name])) - - # ActiveRecord::Base.transaction do - # City.delete_all - # Bus.delete_all - # Service.delete_all - # Trip.delete_all - # ActiveRecord::Base.connection.execute('delete from buses_services;') - - # json.each do |trip| - # from = City.find_or_create_by(name: trip['from']) - # to = City.find_or_create_by(name: trip['to']) - # services = [] - # trip['bus']['services'].each do |service| - # s = Service.find_or_create_by(name: service) - # services << s - # end - # bus = Bus.find_or_create_by(number: trip['bus']['number']) - # bus.update(model: trip['bus']['model'], services: services) - - # Trip.create!( - # from: from, - # to: to, - # bus: bus, - # start_time: trip['start_time'], - # duration_minutes: trip['duration_minutes'], - # price_cents: trip['price_cents'] - # ) - # end - # end end From 7c381e5fac372ada0786728945c29080e5f438e5 Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Mon, 22 Apr 2019 00:37:47 +0300 Subject: [PATCH 09/11] add indexes to trips --- app/views/trips/_trip.html.erb | 2 ++ db/migrate/20190421211613_add_index_to_trips.rb | 13 +++++++++++++ db/schema.rb | 7 ++++++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20190421211613_add_index_to_trips.rb diff --git a/app/views/trips/_trip.html.erb b/app/views/trips/_trip.html.erb index 731ab82..acba0e2 100644 --- a/app/views/trips/_trip.html.erb +++ b/app/views/trips/_trip.html.erb @@ -1,3 +1,4 @@ +<% cache [trip, trip.bus] do %>
    • <%= "Отправление: #{ trip.start_time }" %>
    • <%= "Прибытие: #{ (Time.parse(trip.start_time) + trip.duration_minutes.minutes ).strftime('%H:%M')}" %>
    • @@ -17,3 +18,4 @@ <% end %>
    ==================================================== +<% end %> diff --git a/db/migrate/20190421211613_add_index_to_trips.rb b/db/migrate/20190421211613_add_index_to_trips.rb new file mode 100644 index 0000000..72a7e63 --- /dev/null +++ b/db/migrate/20190421211613_add_index_to_trips.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddIndexToTrips < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + add_foreign_key :trips, :buses + add_index :trips, :start_time, algorithm: :concurrently, order: { start_time: :asc } + add_index :trips, :bus_id, algorithm: :concurrently + add_index :trips, :from_id, algorithm: :concurrently + add_index :trips, :to_id, algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index 8f9b162..64f508b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_04_21_185932) do +ActiveRecord::Schema.define(version: 2019_04_21_211613) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -43,8 +43,13 @@ t.integer "duration_minutes" t.integer "price_cents" t.integer "bus_id" + t.index ["bus_id"], name: "index_trips_on_bus_id" + t.index ["from_id"], name: "index_trips_on_from_id" + t.index ["start_time"], name: "index_trips_on_start_time" + t.index ["to_id"], name: "index_trips_on_to_id" end + add_foreign_key "trips", "buses" add_foreign_key "trips", "cities", column: "from_id" add_foreign_key "trips", "cities", column: "to_id" end From 85b03a95617b99341ac562e006453fc74cf6e09b Mon Sep 17 00:00:00 2001 From: Andrey Paderin Date: Mon, 22 Apr 2019 01:18:11 +0300 Subject: [PATCH 10/11] add case stude opt 2 --- optimization/case-study.md | 109 +++++++++++++++++++++++++++++++++---- optimization/new_relic.png | Bin 0 -> 154798 bytes 2 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 optimization/new_relic.png diff --git a/optimization/case-study.md b/optimization/case-study.md index 434b4b2..7c1a29a 100644 --- a/optimization/case-study.md +++ b/optimization/case-study.md @@ -1,21 +1,108 @@ # Case-study оптимизации -## Актуальная проблема -Загрузка файла с данными расписаний автобусов выполнятся больше минуты. Необходимо оптимизировать механизм перезагрузки расписания из файла так, чтобы он обрабатывал файл в пределах минуты. +## Оптимизация 1 +Цель: Необходимо оптимизировать механизм перезагрузки расписания из файла так, чтобы он обрабатывал файл в пределах минуты. -## Формирование метрики +Метрика: Время загрузки файла расписания -## Гарантия корректности работы оптимизированной программы +Время загрузки файла `large.json` до оптимизации составило почти **9 минут**. +``` +Warming up -------------------------------------- + small 1.000 i/100ms + medium 1.000 i/100ms + large 1.000 i/100ms +Calculating ------------------------------------- + small 0.123 (± 0.0%) i/s - 1.000 in 8.114570s + medium 0.020 (± 0.0%) i/s - 1.000 in 50.703538s + large 0.002 (± 0.0%) i/s - 1.000 in 516.493682s +``` -## Feedback-Loop +Написан тест проверщий работоспособность сервиса импорта. -## Фиксируем исходное состоние системы +Написан `feedback-loop.rb` выполнящий замер производительности. -## Вникаем в детали системы, чтобы найти 20% точек роста +Для чистоты эксперимента вынес загрузку расписания в отдельный сервис `TripsService`: + - Создал индексы для таблиц `Bus`, `Service`, `BusesService` + - Переделал чтение json через `oj` + - Сделал пакетное добавление данных в БД с `activerecord-import` -## Результаты +В результате: -за какое время выполняется импорт файла fixtures/large.json -за какое время рендерится страница автобусы/Самара/Москва +Удалось уменьшить время загрузки до **15 сек**. -## Защита от регресса производительности +Сократил число запросов к базе с **96** к константным **12**. + +``` +Warming up -------------------------------------- + small 1.000 i/100ms + medium 1.000 i/100ms + large 1.000 i/100ms +Calculating ------------------------------------- + small 3.859 (± 0.0%) i/s - 19.000 in 5.025707s + medium 0.572 (± 0.0%) i/s - 3.000 in 5.248226s + large 0.065 (± 0.0%) i/s - 1.000 in 15.374852s + +Comparison: + small: 3.9 i/s + medium: 0.6 i/s - 6.75x slower + large: 0.1 i/s - 59.33x slower +``` + +## Оптимизация 2 +По графику из new relic видно, что много времени занимает рендеринг паршалов и поиск сервисов и автобусов в БД. + +![NewRelic](new_relic.png) + +### Оптимизация +- Перенес паршалы в один паршал `_trips`. +- Добавил кеширование к этому паршалу. +- Избавился от `N+1` с помощью `bullet` и написал тест c `n_plus_one_control` добавил предзагрузку автобусов с сервисами. +- Добавил индексы к полям `trips`. + +В результате проделанной оптимизации время рендеринга страницы составило **824 ms** для файла `large.json` +``` +➜ ab -n 100 -c 10 http://localhost:3000/автобусы/Самара/Москва/ +This is ApacheBench, Version 2.3 <$Revision: 1826891 $> +Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ +Licensed to The Apache Software Foundation, http://www.apache.org/ + +Benchmarking localhost (be patient).....done + + +Server Software: +Server Hostname: localhost +Server Port: 3000 + +Document Path: /автобусы/Самара/Москва/ +Document Length: 71470 bytes + +Concurrency Level: 10 +Time taken for tests: 8.246 seconds +Complete requests: 100 +Failed requests: 0 +Non-2xx responses: 100 +Total transferred: 7171200 bytes +HTML transferred: 7147000 bytes +Requests per second: 12.13 [#/sec] (mean) +Time per request: 824.596 [ms] (mean) +Time per request: 82.460 [ms] (mean, across all concurrent requests) +Transfer rate: 849.28 [Kbytes/sec] received + +Connection Times (ms) + min mean[+/-sd] median max +Connect: 0 0 0.0 0 0 +Processing: 91 791 133.8 817 1120 +Waiting: 91 790 133.8 815 1111 +Total: 91 791 133.8 817 1120 + +Percentage of the requests served within a certain time (ms) + 50% 817 + 66% 834 + 75% 844 + 80% 856 + 90% 892 + 95% 912 + 98% 962 + 99% 1120 + 100% 1120 (longest request) +``` diff --git a/optimization/new_relic.png b/optimization/new_relic.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8e73864627de2707189aca09f852d501822184 GIT binary patch literal 154798 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

    H|wl1{Pw!l#uY#u^;>-c{d^gB2;th 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 Date: Mon, 22 Apr 2019 01:30:22 +0300 Subject: [PATCH 11/11] fix 1 --- optimization/task-4.rb | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 optimization/task-4.rb diff --git a/optimization/task-4.rb b/optimization/task-4.rb deleted file mode 100644 index ecacdb1..0000000 --- a/optimization/task-4.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rubygems' -require 'active_record' -require 'pg' - -def work(file_name) - json = JSON.parse(File.read(file_name)) - - ActiveRecord::Base.transaction do - City.delete_all - Bus.delete_all - Service.delete_all - Trip.delete_all - ActiveRecord::Base.connection.execute('delete from buses_services;') - - json.each do |trip| - from = City.find_or_create_by(name: trip['from']) - to = City.find_or_create_by(name: trip['to']) - services = [] - trip['bus']['services'].each do |service| - s = Service.find_or_create_by(name: service) - services << s - end - bus = Bus.find_or_create_by(number: trip['bus']['number']) - bus.update(model: trip['bus']['model'], services: services) - - Trip.create!( - from: from, - to: to, - bus: bus, - start_time: trip['start_time'], - duration_minutes: trip['duration_minutes'], - price_cents: trip['price_cents'] - ) - end - end -end