• 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
quoting.rb 7.8 KB