Rails如何构建MySQL语句?

我有以下代码在一个控制器内的heroku上运行, 间歇性地失败。 它应该对我很有用,但我必须遗漏一些东西。

@artist = Artist.find(params[:artist_id])

参数hash看起来像这样:

 {"utf8"=>"      ", "authenticity_token"=>"XXXXXXXXXXXXXXX", "password"=>"[FILTERED]", "commit"=>"Download", "action"=>"show", "controller"=>"albums", "artist_id"=>"62", "id"=>"157"} 

我得到的错误看起来像这样:

 ActiveRecord::StatementInvalid: Mysql::Error: : SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = ? LIMIT 1 

注意WHERE艺术家. id = ? 声明的一部分? 它试图找到问号的ID。 含义Rails没有传入params[:artist_id] ,这显然是在params哈希中。 我完全失去了。

我在尝试以类似方式选择记录的不同页面上得到相同的错误。

我的环境:Heroku上的Cedar Stack( 这只发生在Heroku上),Ruby 1.9.3,Rails 3.2.8,托管在Amazon S3上的文件(虽然我怀疑它很重要),使用mysql gem(不是mysql2 ,它没有’完全工作),ClearDB MySQL数据库。

这是完整的痕迹 。

任何帮助将非常感激。

试试sql?

如果它只是这一个声明,并且它导致了生产问题,那么你现在可以省略查询生成器吗? 换句话说,就非常短期而言,只需自己编写SQL。 这会给你带来一些时间。

 # All on one line: Artist.find_by_sql "SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = #{params[:artist_id].to_i} LIMIT 1" 

ARel / MySQL解释?

Rails可以帮助解释MySQL正在尝试做什么:

 Artist.find(params[:artist_id]).explain http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/ 

也许您可以发现成功与失败的查询之间存在某种差异,例如explain如何使用索引或优化。

mysql2 gem?

你能尝试从mysql gem更改为mysql2 gem吗? 切换到mysql2 gem时会出现什么故障?

挥发性?

也许还有其它东西在运行中改变了params散列,所以你在打印它时会看到它,但它在查询运行时会改变吗?

收到params后立即尝试分配变量:

 artist_id = params[:artist_id] ... whatever code here... @artist = Artist.find(artist_id) 

不是params哈希?

你写道“意思是Rails没有通过params [:artist_id],这显然是在params hash中。” 我不认为这是问题 – 我希望你看到这个,因为Rails正在使用“?” 作为准备好的声明的占位符。

要找到答案,请运行@Mori建议的命令并进行比较; 他们应该是一样的。

 Article.find(42).to_sql Article.find(params[:artist_id]).to_sql 

准备好了吗?

当查询实际执行时,可能是准备好的语句缓存问题。

这是失败的代码 – 并且有一个很大的警告。

 begin stmt.execute(*binds.map { |col, val| type_cast(val, col) }) rescue Mysql::Error => e # Older versions of MySQL leave the prepared statement in a bad # place when an error occurs. To support older mysql versions, we # need to close the statement and delete the statement from the # cache. stmt.close @statements.delete sql raise e end 

尝试配置数据库以关闭预准备语句,看看是否有所作为。

./config/database.yml文件中:

 production: adapter: mysql prepared_statements: false ... 

准备好的陈述错误?

Rails忽略此设置可能存在问题。 如果你想了解更多关于它的信息,请参阅Jeremey Cole和Aaron的讨论和错误修复: https : //github.com/rails/rails/pull/7042

Heroku可能会忽略该设置。 这里有一种方法可以尝试通过修补prepared_statements设置来覆盖Heroku: https : //github.com/rails/rails/issues/5297

删除查询缓存?

尝试删除ActiveRecord QueryCache以查看是否有所不同:

 config.middleware.delete ActiveRecord::QueryCache http://edgeguides.rubyonrails.org/configuring.html#configuring-middle 

尝试postgres?

如果你可以尝试Postgres,那也可以清除它。 这对您来说可能不是一个长期的解决方案,但它会将问题与MySQL隔离开来。

MySQL语句显然是错误的,但是你提到的Ruby代码不会产生它。 这里有些问题,要么你使用不同的Ruby代码(可能是来自before_filter的代码),要么传递一个不同的参数(比如params [:artist_id] =“?”)。 看起来你使用嵌套资源,比如Artist has_many :albums 。 也许@artist变量在前一个动作中没有正确初始化,所以params [:artist_id]没有正确的值?