首页 > 解决方案 > 将数组放入 WHERE IN 子句 Ruby on Rails

问题描述

我正在构建一个 ruby​​ on rails 应用程序,它使用原始 SQL 来查询我的数据库,因为我听说它比使用 ActiveRecord 执行得更好。我有一个数组,用于存储 BigInts 的项目列表。例如:

my_items_id = [43627164222, 43667161211, 43667161000]

我的 sql 语句应该返回表中的所有值,其中 id 是my_items_id.

sql = "select * from table1 where id IN #{my_items_id}"
records_array = ActiveRecord::Base.connection.execute(sql)

这不起作用的原因是因为 my_items_id 是一个数组,我知道这一点。但是将其转换为的最佳方法是:(43627164222, 43667161211, 43667161000)以便 sql 语句真正起作用。

标签: sqlruby-on-railsrubypostgresql

解决方案


你写你想避免 ActiveRecord 因为读取原始 SQL 执行得更好。这可能是正确的,尤其是当您必须处理数百万条记录时。

但是,与原始 SQL 相比,ActiveRecord 变慢的原因肯定不是预先构建和清理查询。ActiveRecord 比较慢,因为它解析结果并返回数据库模型的实例,而不是简单的类似哈希的结构。

也就是说,IMO 可以使用 ActiveRecord 查询语言构建查询,但在普通连接上将其作为原始 SQL 运行。然后,您仍然会受益于 ActiveRecord 的查询语言和它针对 SQL 注入的安全功能。

my_items_id = [43627164222, 43667161211, 43667161000]
sql = Table1.where(id: my_items_id).to_sql           # <= Note the `to_sql` where
records_array = ActiveRecord::Base.connection.execute(sql)

处理数百万条记录时的另一个问题不仅是 ActiveRecord 的解析部分,还有数百万条记录消耗大量 RAM 并因此可能比预期慢的事实。ActiveRecord 也有解决这个问题的辅助方法——比如find_eachorfind_in_batches。这些方法不会同时将所有记录加载到内存中,而是以较小的批量加载,并且可以大大提高操作的整体性能。

Table1.where(id: my_items_id).find_each do |item|
  # handle each item
end

或者您可能只需要原始记录的一部分,而不是所有列然后使用pluck会有帮助。它再次提高了 ActiveRecord 查询的性能,因为它返回一个简单的嵌套数组而不是复杂的 ActiveRecord 实例——这节省了解析和内存的时间。

另一个问题是在肯定丢失的数据库索引中对数百万条记录进行缓慢查询。但是如果不了解更多关于数据库结构和慢查询的信息,就不可能给出任何建议。


推荐阅读