Reduce Array object allocations when querying PG
This patch reduced the number of array allocations made when querying PG. It works by returning a PG specific subclass of `ActiveRecord::Result` that delegates to the `PGResult` class. This allows us to iterate over the result rows only once (or possibly even lazily). I removed a call to `PGResult#clear`. I believe this is a safe change because the PGResult free function will clear the results when the object gets garbage collected: https://github.com/ged/ruby-pg/blob/6e6a44b5bfc1ff5c4147dcf45448067e0fe07567/ext/pg_result.c#L211-L212 I don't think we need to aggressively clear the result. Here is the benchmark I used: ```ruby require 'active_record' require 'benchmark/ips' require 'allocation_tracer' ActiveRecord::Base.establish_connection(adapter: "postgresql") ActiveRecord::Migration.verbose = false ActiveRecord::Schema.define do create_table :users, force: true do |t| t.string :name, :email t.timestamps null: false end end class User < ActiveRecord::Base; end attributes = { name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", email: "foobar@email.com" } 1000.times do User.create!(attributes) end ObjectSpace::AllocationTracer.setup(%i{type}) result = ObjectSpace::AllocationTracer.trace do str = "" User.all.each do |user| str << "name: #{user.name} email: #{user.email}\n" end end p :ALLOCATIONS => result p :TOTAL_ALLOCATIONS => result.map { |_,v| v.first }.inject(:+) Benchmark.ips do |x| x.report("all") do str = "" User.all.each do |user| str << "name: #{user.name} email: #{user.email}\n" end end end ``` Here are the results from BEFORE: ``` {:ALLOCATIONS=>{[:T_STRING]=>[8018, 0, 0, 0, 0, 0], [:T_ARRAY]=>[1068, 0, 0, 0, 0, 0], [:T_OBJECT]=>[5011, 0, 0, 0, 0, 0], [:T_HASH]=>[6009, 0, 0, 0, 0, 0], [:T_DATA]=>[12, 0, 0, 0, 0, 0], [:T_IMEMO]=>[24, 0, 0, 0, 0, 0], [:T_STRUCT]=>[1, 0, 0, 0, 0, 0]}} {:TOTAL_ALLOCATIONS=>20143} Warming up -------------------------------------- all 5.000 i/100ms Calculating ------------------------------------- all 60.787 (± 3.3%) i/s - 305.000 in 5.021694s ``` and AFTER: ``` {:ALLOCATIONS=>{[:T_STRING]=>[8013, 0, 1169, 0, 1, 0], [:T_ARRAY]=>[65, 0, 60, 0, 1, 0], [:T_OBJECT]=>[5011, 2, 878, 0, 1, 0], [:T_HASH]=>[6010, 0, 1741, 0, 1, 0], [:T_DATA]=>[12, 2, 12, 1, 1, 0], [:T_IMEMO]=>[24, 4, 20, 0, 1, 0], [:T_STRUCT]=>[1, 0, 1, 1, 1, 0]}} {:TOTAL_ALLOCATIONS=>19136} Warming up -------------------------------------- all 6.000 i/100ms Calculating ------------------------------------- all 63.746 (± 3.1%) i/s - 324.000 in 5.087608s ```
Showing
想要评论请 注册 或 登录