1. 10 5月, 2020 6 次提交
    • R
      Should not substitute binds when `prepared_statements: true` · 157f6a6e
      Ryuta Kamizono 提交于
      Before IN clause optimization 70ddb8a7, Active Record had generated an
      SQL with binds when `prepared_statements: true`:
      
      ```ruby
      # prepared_statements: true
      #
      #   SELECT `authors`.* FROM `authors` WHERE `authors`.`id` IN (?, ?, ?)
      #
      # prepared_statements: false
      #
      #   SELECT `authors`.* FROM `authors` WHERE `authors`.`id` IN (1, 2, 3)
      #
      Author.where(id: [1, 2, 3]).to_a
      ```
      
      But now, binds in IN clause is substituted regardless of whether
      `prepared_statements: true` or not:
      
      ```ruby
      # prepared_statements: true
      #
      #   SELECT `authors`.* FROM `authors` WHERE `authors`.`id`IN (1,2,3)
      #
      # prepared_statements: false
      #
      #   SELECT `authors`.* FROM `authors` WHERE `authors`.`id`IN (1,2,3)
      #
      Author.where(id: [1, 2, 3]).to_a
      ```
      
      I suppose that is considered as a regression for the context:
      
      > While I would prefer that we fix/avoid the too-many-parameters
      problem, but I don't like the idea of globally ditching bind params for
      this edge case... we're getting to the point where I'd almost consider
      anything that doesn't use a bind to be a bug.
      
      https://github.com/rails/rails/pull/33844#issuecomment-421000003
      
      This makes binds consider whether `prepared_statements: true` or not
      (i.e. restore the original behavior as before), but still gain that
      optimization when need the substitute binds (`prepared_statements: false`,
      `relation.to_sql`). Even when `prepared_statements: true`, it still
      much faster than before by optimized (bind node less) binds generation.
      
      ```ruby
      class Post < ActiveRecord::Base
      end
      
      ids = (1..1000).each.map do |n|
        Post.create!.id
      end
      
      puts "prepared_statements: #{Post.connection.prepared_statements.inspect}"
      
      Benchmark.ips do |x|
        x.report("where with ids") do
          Post.where(id: ids).to_a
        end
      end
      ```
      
      * Before (200058b0)
      
      `prepared_statements: true`:
      
      ```
      Warming up --------------------------------------
            where with ids     6.000  i/100ms
      Calculating -------------------------------------
            where with ids     63.806  (± 7.8%) i/s -    318.000  in   5.015903s
      ```
      
      `prepared_statements: false`:
      
      ```
      Warming up --------------------------------------
            where with ids     7.000  i/100ms
      Calculating -------------------------------------
            where with ids     73.550  (± 8.2%) i/s -    371.000  in   5.085672s
      ```
      
      * Now with this change
      
      `prepared_statements: true`:
      
      ```
      Warming up --------------------------------------
            where with ids     9.000  i/100ms
      Calculating -------------------------------------
            where with ids     91.992  (± 7.6%) i/s -    459.000  in   5.020817s
      ```
      
      `prepared_statements: false`:
      
      ```
      Warming up --------------------------------------
            where with ids    10.000  i/100ms
      Calculating -------------------------------------
            where with ids    104.335  (± 8.6%) i/s -    520.000  in   5.026425s
      ```
      157f6a6e
    • R
      Eager generate relation methods if a method is on `Kernel` · 981299e3
      Ryuta Kamizono 提交于
      Follow up of #34122.
      
      Relation method call is relying on method_missing, but if `Kernel` has
      the same named method (e.g. `open`, etc), it will invoke Kernel's method
      since method_missing is not happened.
      
      To prevent that, eager generate relation methods if a method is the same
      name on `Kernel`.
      
      Fixes #39195.
      981299e3
    • R
      ecca3651
    • R
      Remove unused `require "active_support/core_ext/kernel/singleton_class"` · 1165401e
      Ryuta Kamizono 提交于
      `singleton_class` is in Ruby 1.9.2, and there is no use singleton class
      eval in the files.
      1165401e
    • R
      Refactor index creation to use index definition visitor · 2c1b012a
      Ryuta Kamizono 提交于
      Current SQL generation code is hard to maintenance, I've found a bug
      that create index comment in bulk change table when I'm refactoring
      that.
      2c1b012a
    • R
      Fix index creation to preserve comment in bulk change table on MySQL · fc7eab04
      Ryuta Kamizono 提交于
      I've found the bug when I'm refactoring index creation code in #39203.
      fc7eab04
  2. 09 5月, 2020 2 次提交
  3. 08 5月, 2020 1 次提交
  4. 07 5月, 2020 5 次提交
  5. 06 5月, 2020 5 次提交
  6. 05 5月, 2020 6 次提交
  7. 04 5月, 2020 1 次提交
  8. 03 5月, 2020 4 次提交
  9. 02 5月, 2020 5 次提交
    • R
      Fix `minimum` and `maximum` on non numeric column · 767edafc
      Ryuta Kamizono 提交于
      I supposed all aggregation functions will return numeric result in
      #39039, but that assumption was incorrect for `minimum` and `maximum`,
      if an aggregated column is non numeric type.
      
      I've restored type casting aggregated result for `minimum` and `maximum`.
      
      Fixes #39110.
      767edafc
    • R
      Deprecate passing a column to `type_cast` · 92360e9e
      Ryuta Kamizono 提交于
      The type information for type casting is entirely separated to type
      object, so if anyone does passing a column to `type_cast` in Rails 6,
      they are likely doing something wrong. See the comment for more details:
      
      https://github.com/rails/rails/blob/28d815b89487ce4001a3f6f0ab684e6f9c017ed0/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb#L33-L42
      
      This also deprecates passing legacy binds (an array of `[column, value]`
      which is 4.2 style format) to query methods on connection. That legacy
      format was kept for backward compatibility, instead of that, I've
      supported casted binds format (an array of casted values), it is easier
      to construct binds than existing two binds format.
      92360e9e
    • R
      7669dc21
    • E
      Perf: Improve performance of where when using an array of values · 72fd0bae
      eileencodes 提交于
      A coworker at GitHub found a few months back that if we used
      `santitize_sql` over `where` when we knew the values going into `where`
      it was a lot faster than `where`.
      
      This PR adds a new Arel node type called `HomogenousIn` that will be
      used when Rails knows the values are all homogenous and can therefore
      pick a faster codepath. This new codepath skips some of the required
      processing by `where` to make `wheres` with homogenous arrays faster
      without requiring the application author to know when to use which query
      type.
      
      Using our benchmark code:
      
      ```ruby
      ids = (1..1000).each.map do |n|
        Post.create!.id
      end
      
      Benchmark.ips do |x|
        x.report("where with ids") do
          Post.where(id: ids).to_a
        end
      
        x.report("where with sanitize") do
          Post.where(ActiveRecord::Base.sanitize_sql(["id IN (?)", ids])).to_a
        end
      
        x.compare!
      end
      ```
      
      Before this PR comparing where with a list of IDs to santitize sql:
      
      ```
      Warming up --------------------------------------
            where with ids    11.000  i/100ms
       where with sanitize    17.000  i/100ms
      
      Calculating -------------------------------------
            where with ids    115.733  (± 4.3%) i/s -    583.000  in   5.045828s
       where with sanitize    174.231  (± 4.0%) i/s -    884.000  in   5.081495s
      
      Comparison:
       where with sanitize:      174.2 i/s
            where with ids:      115.7 i/s - 1.51x  slower
      ```
      
      After this PR comparing where with a list of IDs to santitize sql:
      
      ```
      Warming up --------------------------------------
            where with ids    16.000  i/100ms
       where with sanitize    19.000  i/100ms
      
      Calculating -------------------------------------
            where with ids    158.293  (± 6.3%) i/s -    800.000  in   5.072208s
       where with sanitize    169.141  (± 3.5%) i/s -    855.000  in   5.060878s
      
      Comparison:
       where with sanitize:      169.1 i/s
            where with ids:      158.3 i/s - same-ish: difference falls within error
      ```
      Co-authored-by: NAaron Patterson <aaron.patterson@gmail.com>
      72fd0bae
    • E
      Support query attrs and bind params in dot output · ff8f40e7
      eileencodes 提交于
      ff8f40e7
  10. 01 5月, 2020 5 次提交
    • R
      Remove internal `without_transaction_enrollment` callbacks · 75873d8f
      Ryuta Kamizono 提交于
      I've found the internal `without_transaction_enrollment` callbacks which
      have not been newly used over five years, when I tried to work reverting
      #9068 (https://github.com/rails/rails/pull/36049#issuecomment-487318060).
      
      I think that we will never make that callbacks public, since the
      mechanism of `without_transaction_enrollment` is too implementation
      specific, at least before #9068, records in a transaction had enrolled
      all into the transaction.
      
      That callbacks was introduced at #18936 to make `touch_later` #19324,
      but I think that the internal callbacks is overkill to just make the
      `touch_later` only, and invoking the extra callbacks also have a little
      overhead even if we haven't used that.
      
      So I think we can remove the internal callbacks for now, until we will
      come up with a good use for that callbacks.
      75873d8f
    • J
      Also batch attribute readers and writers · d12418a7
      Jean Boussier 提交于
      d12418a7
    • R
      Avoid quite useless loop in `find_by_sql` · 71e45582
      Ryuta Kamizono 提交于
      `column_types` is empty except PostgreSQL adapter, and
      `attribute_types.each_key { |k| column_types.delete k }` is also empty
      even if PostgreSQL adapter almost all case, so that code is quite
      useless. This improves performance for `find_by_sql` to avoid that
      useless loop as much as possible.
      
      ```ruby
      ActiveRecord::Schema.define do
        create_table :active_storage_blobs do |t|
          t.string   :key,          null: false
          t.string   :filename,     null: false
          t.string   :content_type
          t.text     :metadata
          t.string   :service_name, null: false
          t.bigint   :byte_size,    null: false
          t.string   :checksum,     null: false
          t.datetime :created_at,   null: false
      
          t.index [ :key ], unique: true
        end
      end
      
      class ActiveStorageBlob < ActiveRecord::Base
      end
      
      Benchmark.ips do |x|
        x.report("find_by") { ActiveStorageBlob.find_by(id: 1) }
      end
      ```
      
      Before:
      
      ```
      Warming up --------------------------------------
                   find_by     1.256k i/100ms
      Calculating -------------------------------------
                   find_by     12.595k (± 3.4%) i/s -     64.056k in   5.091599s
      ```
      
      After:
      
      ```
      Warming up --------------------------------------
                   find_by     1.341k i/100ms
      Calculating -------------------------------------
                   find_by     13.170k (± 3.5%) i/s -     67.050k in   5.097439s
      ```
      
      To avoid column types loop for PostgreSQL adapter, this skips returning
      additional column types if a column has already been type casted by pg
      decoders. Fortunately this fixes #36186 partly for common types.
      71e45582
    • R
      Replace `result_as_array` by type mapping · 348e142b
      Ryuta Kamizono 提交于
      348e142b
    • R
      Should not rely on the global `Arel::Table.engine` in the framework · bc99e401
      Ryuta Kamizono 提交于
      Relying on the `Arel::Table.engine` is convenient if an app have only a
      single kind of database, but if not so, the global state is not always
      the same with the current connection.
      bc99e401