如何加速这些ActiveRecord查询?

时间:2014-11-20 18:45:02

标签: ruby-on-rails rails-activerecord

我的数据库中有三个表:值,键和源。键和源都有很多值。 sources有一个名为file_date的日期时间列。对于每个密钥,我必须选择具有特定日期范围(通常在两年内)之间的源的所有值。并非该范围内的所有日期都有来源,并非所有来源都有值。我需要创建一个包含该范围内所有值的数组。

我起初试图简单地一次查询整个源数组,如下所示:

Value.where(key: 1, source: sources_array)

但是,由于有几个值为nil,它只返回在该日期具有值的记录。

现在,我已经创建了一个包含该日期范围之间所有来源的数组。没有来源的日子只有零。然后,对于每个键,我遍历sources数组,返回与foo和source匹配的值。这显然不太理想,页面加载大约需要7秒钟。

以下是代码:

sources.map do |source|
  Value.where(source: source, key: key)
end

有什么想法吗?

4 个答案:

答案 0 :(得分:0)

.map的一个大问题是,它会运行多个查询,而不是一个包含所需结果的查询。对于每个附加查询,您将添加将请求发送到数据库并接收响应的开销。您需要做的是生成查询,使其返回 all 您可能正在查找的结果,然后处理任何分组或排序应用程序端。

答案 1 :(得分:0)

您可以尝试在单个交易中包装您的查询:

ActiveRecord::Base.transaction do
  sources.map do |source|
    Value.where(source: source, key: key)
  end
end

答案 2 :(得分:0)

我需要像疯了一样重构这个,但我有一些东西已经把它减少到3秒:

  source_ids = sources.map do |source|
    if source
      source.id
    else
      nil
    end
  end

  values = Value.where(source: sources, key: key)
  value_sources = values.pluck(:source_id)
  value_decimals = values.pluck(:value_decimal)

  source_ids.map do |id|
    index = value_sources.index(id)

    if index
      value_decimals[index]
    else
      nil
    end
  end

答案 3 :(得分:0)

如果您只需要检索数据并且返回数组就足够了,您还可以生成单个SQL查询。

output = []

sources.each do |source|   
  output << "select * from values where (source like #{source} and key like #{key})"   
end

result = ActiveRecord::Base.connection.execute(output.join(" union ")).to_a
相关问题