From b6828fc91531ae0cc0a0f216705dd19112596301 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Mon, 22 Apr 2019 14:41:00 +0900 Subject: PERF: 20% faster pk attribute access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've realized that `user.id` is 20% slower than `user.name` in the benchmark (https://github.com/rails/rails/pull/35987#issuecomment-483882480). The reason that performance difference is that `self.class.primary_key` method call is a bit slow. Avoiding that method call will make almost attribute access faster and `user.id` will be completely the same performance with `user.name`. Before (02b5b8cb): ``` Warming up -------------------------------------- user.id 140.535k i/100ms user['id'] 96.549k i/100ms user.name 158.110k i/100ms user['name'] 94.507k i/100ms user.changed? 19.003k i/100ms user.saved_changes? 25.404k i/100ms Calculating ------------------------------------- user.id 2.231M (± 0.9%) i/s - 11.243M in 5.040066s user['id'] 1.310M (± 1.3%) i/s - 6.565M in 5.012607s user.name 2.683M (± 1.2%) i/s - 13.439M in 5.009392s user['name'] 1.322M (± 0.9%) i/s - 6.615M in 5.003239s user.changed? 201.999k (±10.9%) i/s - 1.007M in 5.091195s user.saved_changes? 258.214k (±17.1%) i/s - 1.245M in 5.007421s ``` After (this change): ``` Warming up -------------------------------------- user.id 158.364k i/100ms user['id'] 106.412k i/100ms user.name 158.644k i/100ms user['name'] 107.518k i/100ms user.changed? 19.082k i/100ms user.saved_changes? 24.886k i/100ms Calculating ------------------------------------- user.id 2.768M (± 1.1%) i/s - 13.936M in 5.034957s user['id'] 1.507M (± 2.1%) i/s - 7.555M in 5.017211s user.name 2.727M (± 1.5%) i/s - 13.643M in 5.004766s user['name'] 1.521M (± 1.3%) i/s - 7.634M in 5.018321s user.changed? 200.865k (±11.1%) i/s - 992.264k in 5.044868s user.saved_changes? 269.652k (±10.5%) i/s - 1.344M in 5.077972s ``` --- .../lib/active_record/attribute_methods/primary_key.rb | 16 +++++++--------- activerecord/lib/active_record/attribute_methods/read.rb | 3 +-- .../lib/active_record/attribute_methods/write.rb | 3 +-- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'activerecord/lib/active_record/attribute_methods') diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index feaef72a30..b4f5e6e75a 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -16,34 +16,32 @@ module ActiveRecord # Returns the primary key column's value. def id - primary_key = self.class.primary_key - _read_attribute(primary_key) if primary_key + _read_attribute(@primary_key) end # Sets the primary key column's value. def id=(value) - primary_key = self.class.primary_key - _write_attribute(primary_key, value) if primary_key + _write_attribute(@primary_key, value) end # Queries the primary key column's value. def id? - query_attribute(self.class.primary_key) + query_attribute(@primary_key) end # Returns the primary key column's value before type cast. def id_before_type_cast - read_attribute_before_type_cast(self.class.primary_key) + read_attribute_before_type_cast(@primary_key) end # Returns the primary key column's previous value. def id_was - attribute_was(self.class.primary_key) + attribute_was(@primary_key) end # Returns the primary key column's value from the database. def id_in_database - attribute_in_database(self.class.primary_key) + attribute_in_database(@primary_key) end private @@ -116,7 +114,7 @@ module ActiveRecord # # Project.primary_key # => "foo_id" def primary_key=(value) - @primary_key = value && value.to_s + @primary_key = value && -value.to_s @quoted_primary_key = nil @attributes_builder = nil end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 409a150e56..c787fb6a94 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -31,8 +31,7 @@ module ActiveRecord name = self.class.attribute_alias(name) end - primary_key = self.class.primary_key - name = primary_key if name == "id" && primary_key + name = @primary_key if name == "id" && @primary_key _read_attribute(name, &block) end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 6a21643884..6a54bd2fc2 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -35,8 +35,7 @@ module ActiveRecord name = self.class.attribute_alias(name) end - primary_key = self.class.primary_key - name = primary_key if name == "id" && primary_key + name = @primary_key if name == "id" && @primary_key _write_attribute(name, value) end -- cgit v1.2.3