New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PERF: avoid allocating column names where possible #33051

Merged
merged 1 commit into from Jun 6, 2018

Conversation

Projects
None yet
5 participants
@SamSaffron
Contributor

SamSaffron commented Jun 4, 2018

When requesting columns names from database adapters AR:Result
would dup/freeze column names, this prefers using fstrings which
cuts down on repeat allocations

Attributes that are retained keep these fstrings around for the long
term

Note, this has the highest impact on "short" result sets, eg: Topic.first where you can void allocating the number of columns * String.

See also: https://samsaffron.com/archive/2018/02/16/reducing-string-duplication-in-ruby for detailed explanation of uminus

per @rafaelfranca we are fine including uminus in master now. cc @tenderlove @sgrif

@rails-bot

This comment has been minimized.

rails-bot commented Jun 4, 2018

r? @rafaelfranca

(@rails-bot has picked a reviewer for you, use r? to override)

activerecord/lib/active_record/result.rb Outdated
@@ -125,7 +125,7 @@ def hash_rows
begin
# We freeze the strings to prevent them getting duped when
# used as keys in ActiveRecord::Base's @attributes hash
columns = @columns.map { |c| c.dup.freeze }
columns = @columns.map { |c| -c }

This comment has been minimized.

@bdewater

bdewater Jun 5, 2018

Contributor

Might want to change to columns = @columns.map(&:-@) for a small speed improvement.

This comment has been minimized.

@SamSaffron

SamSaffron Jun 5, 2018

Contributor

@bdewater yes I can confirm this is worth it to change, I will amend this PR tomorrow

https://gist.github.com/SamSaffron/805bf43016cc897c0f0c19078e7ad171

@bdewater

This comment has been minimized.

Contributor

bdewater commented Jun 5, 2018

It's the reason Rubocop has Style/SymbolProc. There's a lot of context in #16833

benchmark.rb for this case:

require 'benchmark/ips'

COLUMNS = %w(id foo bar baz qux test yolo)

def block
  COLUMNS.map { |c| -c }
end

def to_proc
  COLUMNS.map(&:-@)
end

Benchmark.ips do |x|
  x.report("block")   { block }
  x.report("to_proc") { to_proc }
  x.compare!
end
Warming up --------------------------------------
               block    65.000k i/100ms
             to_proc    71.129k i/100ms
Calculating -------------------------------------
               block    774.817k (± 1.4%) i/s -      3.900M in   5.034500s
             to_proc    863.802k (± 1.2%) i/s -      4.339M in   5.023677s

Comparison:
             to_proc:   863801.9 i/s
               block:   774816.7 i/s - 1.11x  slower
@rafaelfranca

This comment has been minimized.

Member

rafaelfranca commented Jun 5, 2018

LGTM! Let me know when you update the PR to include the &:-@ change.

PERF: avoid allocating column names where possible
When requesting columns names from database adapters AR:Result
would dup/freeze column names, this prefers using fstrings which
cuts down on repeat allocations

Attributes that are retained keep these fstrings around for the long
term

Note, this has the highest impact on "short" result sets, eg: Topic.first where you can void allocating the number of columns * String.
@SamSaffron

This comment has been minimized.

Contributor

SamSaffron commented Jun 5, 2018

@rafaelfranca done! 🎊

@matthewd matthewd merged commit d0d3e96 into rails:master Jun 6, 2018

2 checks passed

codeclimate All good!
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@rafaelfranca

This comment has been minimized.

Member

rafaelfranca commented Jun 6, 2018

❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment