# frozen_string_literal: true require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'pg', github: 'ged/ruby-pg' gem 'mini_sql', path: '../' gem 'activesupport' gem 'activerecord' gem 'activemodel' gem 'memory_profiler' gem 'benchmark-ips' gem 'sequel', github: 'jeremyevans/sequel' gem 'sequel_pg', github: 'jeremyevans/sequel_pg', require: 'sequel' gem 'swift-db-postgres', github: 'deepfryed/swift-db-postgres' gem 'draper' end require 'sequel' require 'active_record' require 'memory_profiler' require 'benchmark/ips' require 'mini_sql' ActiveRecord::Base.establish_connection( :adapter => "postgresql", :database => "test_db" ) DB = Sequel.postgres('test_db') pg = ActiveRecord::Base.connection.raw_connection pg.async_exec < 0 $mini_sql.query_decorator(TopicDecorator, 'select id, title from topics order by id limit 1000').each do |obj| obj.title_bang obj.id end n -= 1 end end r.report('extend') do |n| while n > 0 $mini_sql.query('select id, title from topics order by id limit 1000').each do |obj| d_obj = obj.extend(TopicDecorator) d_obj.title_bang d_obj.id end n -= 1 end end r.report('draper') do |n| while n > 0 $mini_sql.query('select id, title from topics order by id limit 1000').each do |obj| d_obj = TopicDraper.new(obj) d_obj.title_bang d_obj.id end n -= 1 end end r.report('simple_delegator') do |n| while n > 0 $mini_sql.query('select id, title from topics order by id limit 1000').each do |obj| d_obj = TopicSimpleDelegator.new(obj) d_obj.title_bang d_obj.id end n -= 1 end end r.report('query') do |n| while n > 0 $mini_sql.query('select id, title from topics order by id limit 1000').each do |obj| obj.title + '!!!' obj.id end n -= 1 end end r.report('ar model') do |n| while n > 0 TopicArModel.limit(1000).order(:id).select(:id, :title).each do |obj| obj.title_bang obj.id end n -= 1 end end r.report('sequel model') do |n| while n > 0 TopicDecoratorSequel.limit(1000).order(:id).select(:id, :title).each do |obj| obj.title_bang obj.id end n -= 1 end end r.compare! end # Comparison: # query: 828.4 i/s # query_decorator: 819.3 i/s - same-ish: difference falls within error # sequel model: 672.4 i/s - 1.23x slower # extend: 519.4 i/s - 1.59x slower # simple_delegator: 496.8 i/s - 1.67x slower # draper: 416.2 i/s - 1.99x slower # ar model: 113.4 i/s - 7.30x slower Benchmark.ips do |r| r.report('query_hash') do |n| while n > 0 $mini_sql.query_hash('select id, title from topics order by id limit 1000').each do |hash| [hash['id'], hash['title']] end n -= 1 end end r.report('query_array') do |n| while n > 0 $mini_sql.query_array('select id, title from topics order by id limit 1000').each do |id, title| [id, title] end n -= 1 end end r.report('query') do |n| while n > 0 $mini_sql.query('select id, title from topics order by id limit 1000').each do |obj| [obj.id, obj.title] end n -= 1 end end r.compare! end # Comparison: # query_array: 1351.6 i/s # query: 963.8 i/s - 1.40x slower # query_hash: 787.4 i/s - 1.72x slower Benchmark.ips do |r| r.report('query_single') do |n| while n > 0 $mini_sql.query_single('select id from topics order by id limit 1000') n -= 1 end end r.report('query_array') do |n| while n > 0 $mini_sql.query_array('select id from topics order by id limit 1000').flatten n -= 1 end end r.compare! end # Comparison: # query_single: 2368.9 i/s # query_array: 1350.1 i/s - 1.75x slower Benchmark.ips do |r| r.report("ar select title id") do |n| while n > 0 ar_title_id n -= 1 end end r.report("ar select title id pluck") do |n| while n > 0 ar_title_id_pluck n -= 1 end end r.report("sequel title id select") do |n| while n > 0 sequel_select_title_id n -= 1 end end r.report("pg select title id") do |n| while n > 0 pg_title_id n -= 1 end end r.report("mini_sql select title id") do |n| while n > 0 mini_sql_title_id n -= 1 end end r.report("sequel title id pluck") do |n| while n > 0 sequel_pluck_title_id n -= 1 end end r.report("mini_sql query_single title id") do |n| while n > 0 mini_sql_title_id_query_single n -= 1 end end r.report("swift title id") do |n| while n > 0 swift_select_title_id n -= 1 end end r.compare! end def wide_topic_ar Topic.first end def wide_topic_pg r = $conn.async_exec("select * from topics limit 1") row = r.first r.clear row end def wide_topic_sequel TopicSequel.first end def wide_topic_mini_sql $conn.query("select * from topics limit 1").first end Benchmark.ips do |r| r.report("wide topic ar") do |n| while n > 0 wide_topic_ar n -= 1 end end r.report("wide topic sequel") do |n| while n > 0 wide_topic_sequel n -= 1 end end r.report("wide topic pg") do |n| while n > 0 wide_topic_pg n -= 1 end end r.report("wide topic mini sql") do |n| while n > 0 wide_topic_mini_sql n -= 1 end end r.compare! end # Comparison: # pg select title id: 1519.7 i/s # mini_sql query_single title id: 1335.0 i/s - 1.14x slower # sequel title id pluck: 1261.6 i/s - 1.20x slower # mini_sql select title id: 1188.6 i/s - 1.28x slower # swift title id: 1077.5 i/s - 1.41x slower # sequel title id select: 969.7 i/s - 1.57x slower # ar select title id pluck: 738.7 i/s - 2.06x slower # ar select title id: 149.6 i/s - 10.16x slower # # # Comparison: # wide topic pg: 7474.0 i/s # wide topic mini sql: 7355.2 i/s - same-ish: difference falls within error # wide topic sequel: 5696.8 i/s - 1.31x slower # wide topic ar: 2515.0 i/s - 2.97x slower # to run deep analysis run # MemoryProfiler.report do # ar # end.pretty_print