I believe the binds are used to improve the statement caching and not suggested to be used directly.
Here is an example of an internal use when `Post.find(1)` executed: id_query_attribute = ActiveRecord::Relation::QueryAttribute.new(:id, 1, Post.type_for_attribute(:id)) Post.find_by_sql('select * from posts where id = ?', [id_query_attribute]) On Fri, Jun 26, 2015 at 1:05 PM, Al Tenhundfeld <tenhundf...@gmail.com> wrote: > If I'm following the code, it looks like the binds argument is passed > through #select_all and eventually down to the adapter's #exec_query, e.g., > the MySQL adapter > <https://github.com/rails/rails/blob/83821e2c4a32b17b153fcbcb247dec6e32f47284/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb#L253>. > So, the behavior could be different depending on the adapter and even DB > version. That makes sense, because different databases handle prepared > statements and bind variables differently. > > And it looks like the documentation example of #find_by_sql, passing the > array with "bind variables" into the sql arg, works because that sql arg is > being passed to #sanitize_sql > <https://github.com/rails/rails/blob/1d43458c148f9532a81b92ee3a247da4f1c0b7ad/activerecord/lib/active_record/sanitization.rb#L91>, > which has its own implementation of replacing variables outside of/before > the adapter. So, using this syntax isn't really using bind variables, > passed to the database. It's more string interpolation and sanitation. > > So, following the code, I was able to get a query executing with the > Postgres adapter and actually passing the bind variables to Postgres. > > *Example 1, using binds arg:* > Project.find_by_sql('select * from projects where client_id = $1 and > region = $2', [[nil, 123], [nil, 'West']]) > (NOTE: You can use the column name in place of nil, but I get a warning > when I do that.) > Results in this statements in the PG log: > LOG: execute a3: select * from projects where client_id = $1 and region = > $2 > DETAIL: parameters: $1 = '123', $2 = 'West' > > *Example 2, specifying the variables in the sql arg:* > Project.find_by_sql(['select * from projects where client_id = ? and > region = ?',123, 'West']) > Results in: > LOG: execute <unnamed>: select * from projects where client_id = 123 and > region = 'West' > > So, you can see those are clearly different. In example 1, the statement > is being prepared, and the bind variables are passed to Postgres. In > example 2, the variables are being replaced by Rails via #sanitize_sql > before the statement is passed on to the adapter, which results in an > unnamed statement passed to Postgres with no bind variables. (I think, > that's how I'm interpreting it at least.) > > I couldn't get a true bind variable example working with MySQL, but I > don't have a convenient environment using recent versions of the adapter > and MySQL server. I think this is related to Pat Shaughnessy's post on > prepared > statements > <http://patshaughnessy.net/2011/10/22/show-some-love-for-prepared-statements-in-rails-3-1> > . > > Following that logic, it's not too surprising that standard model methods > result in different behavior in PG and MySQL: > > Project.find(1) using the Postgres adapter results in: > LOG: execute a4: SELECT "projects".* FROM "projects" WHERE > "projects"."id" = $1 LIMIT 1 > DETAIL: parameters: $1 = '1' > > Project.find(1) using (my older version of) the MySQL adapter results in > the MySQL equivalent of: > LOG: execute <unnamed>: SELECT "projects".* FROM "projects" WHERE > "projects"."id" = 1 LIMIT 1 > > I haven't really kept up with database internals enough to know how much > of an improvement prepared statements yield. Years ago, prepared statements > could give you a significant performance improvement, because the query > parser can easily see two queries are the same, reuse copies of the > execution plan, etc. My understanding is databases have gotten better about > deriving similarities in queries and reusing plans, cached results, etc. > > I don't have an opinion (yet) on what should be done to improve the > situation, but I hope that sheds a little light on what's happening with > the binds arg and why you might want to use it. > > Cheers, > Al > > > > > On Fri, Jun 26, 2015 at 3:01 AM, Matias Korhonen <korhonen.m...@gmail.com> > wrote: > >> There's also no test case (as far as I can find >> <https://github.com/rails/rails/blob/3e36db4406beea32772b1db1e9a16cc1e8aea14c/activerecord/test/cases/finder_test.rb#L248-L265>) >> that would cover passing the binds args to #find_by_sql >> >> Anyone know what it's supposed to be used for? >> >> >> >> On Thursday, 25 June 2015 18:48:10 UTC+3, T.J. Schuck wrote: >>> >>> The `bind` argument was added as `bind_values` all the way back in 2010, >>> with no change to the documentation: >>> https://github.com/rails/rails/commit/cc468d3ec81d6f1298fca91c0549584b36dafcc6 >>> >>> So the docs are probably just wrong — I’m sure a documentation PR would >>> be quickly merged. >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "Ruby on Rails: Core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to rubyonrails-core+unsubscr...@googlegroups.com. >> To post to this group, send email to rubyonrails-core@googlegroups.com. >> Visit this group at http://groups.google.com/group/rubyonrails-core. >> For more options, visit https://groups.google.com/d/optout. >> > > -- > You received this message because you are subscribed to the Google Groups > "Ruby on Rails: Core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to rubyonrails-core+unsubscr...@googlegroups.com. > To post to this group, send email to rubyonrails-core@googlegroups.com. > Visit this group at http://groups.google.com/group/rubyonrails-core. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-core+unsubscr...@googlegroups.com. To post to this group, send email to rubyonrails-core@googlegroups.com. Visit this group at http://groups.google.com/group/rubyonrails-core. For more options, visit https://groups.google.com/d/optout.