2015-11-10 34 views
1

我对Ruby on Rails不是特别熟悉,但是我正在解决我们遇到的一个应该清理数据库表的耙工作中遇到的问题。这些表非常快速地增长很大,ActiveRecord生成的查询似乎没有足够的效率来处理它。Raills:获取由delete_all生成的SQL语句

的Ruby调用看起来是这样的:

Source.where("id not IN (#{Log.select('DISTINCT source_id').to_sql})").delete_all 

这:

Log.joins(:report).where(:report_id => Report.where(cond)).delete_all 

我试图让在SQL,所以我们可以有我们的DBA的尝试优化它更好。我注意到如果我删除“.delete_all”,我可以在调用“.delete_all”之前添加一个“.to_sql”,它给了我查询的SELECT语句。我想看看那个delete_all方法正在生成什么SQL。

有没有办法做到这一点?

+0

您使用的是哪种版本的导轨? – hd1

+0

rails版本3.2.8 – blindsnowmobile

回答

0

fine manual

DELETE_ALL(条件=无)

删除记录匹配conditions而不首先实例化的记录,并因此不调用destroy方法也不调用回调。这是一条直接到数据库的单个SQL DELETE语句,比destroy_all更有效。

所以一个Model.delete_all(conditions)最终成为

delete from models where conditions 

当你说Model.where(...).delete_all,该conditionsdelete_all来自where调用所以这些都是相同的:

Model.delete_all(conditions) 
Model.where(conditions).delete_all 

将其应用于你的情况:

Source.where("id not IN (#{Log.select('DISTINCT source_id').to_sql})").delete_all 

你应该看到你正在运行:

delete from sources 
where id not in (
    select distinct source_id 
    from logs 
) 

如果你运行在开发控制台你的代码,你应该看到在控制台或Rails的日志中的SQL,但它会像上面。

就优化而言,我的第一步是放弃DISTINCT。 DISTINCT通常不便宜,而且不管怎样都不在乎重复,所以not in (select distinct ...)可能是毫无意义的繁忙工作。然后,source_id上的索引可能会有所帮助,查询优化器可能能够直接从索引中提取source_id列表,而无需执行表扫描以查找它们。当然,查询优化是一个黑暗的艺术,所以这些简单的步骤可能会或可能不会工作。

1

ActiveRecord::Base.logger = Logger.new(STDOUT)应该向您显示控制台上由rails生成的所有SQL。