1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/lib/arel
Ryuta Kamizono 157f6a6efe Should not substitute binds when prepared_statements: true
Before IN clause optimization 70ddb8a, 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 (200058b011)

`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
```
2020-05-10 21:59:27 +09:00
..
attributes Perf: Improve performance of where when using an array of values 2020-05-01 15:12:05 -04:00
collectors Refactor preparable to be had the state in Arel collectors 2020-05-03 23:19:41 +09:00
nodes Ensure type cast is not evaluated at relation build time 2020-05-06 12:50:24 +09:00
visitors Should not substitute binds when prepared_statements: true 2020-05-10 21:59:27 +09:00
alias_predication.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30
crud.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30
delete_manager.rb Handle DELETE with LIMIT in Arel 2018-09-30 21:21:54 +09:00
errors.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30
expressions.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30
factory_methods.rb Make update_counters preparable 2018-09-28 04:14:15 +09:00
insert_manager.rb Get rid of Arel::Nodes::Values 2019-03-18 03:57:16 +09:00
math.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30
nodes.rb Perf: Improve performance of where when using an array of values 2020-05-01 15:12:05 -04:00
order_predications.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30
predications.rb Remove deprecated attr.in(range_object) optimization 2020-05-06 14:50:10 +09:00
select_manager.rb Revert unused code and re-using query annotation for update_all and delete_all 2019-04-01 15:04:11 +09:00
table.rb Revert "Merge pull request #39022 from kamipo/perf_where_in" 2020-05-05 12:45:10 -04:00
tree_manager.rb Revert unused code and re-using query annotation for update_all and delete_all 2019-04-01 15:04:11 +09:00
update_manager.rb Handle DELETE with LIMIT in Arel 2018-09-30 21:21:54 +09:00
visitors.rb Remove unused Arel visitors in the code base 2020-04-15 18:33:37 +09:00
window_predications.rb Arel: :nodoc: all 2018-02-24 18:11:47 +10:30