【问题标题】:how to avoid preloading in Ecto Query Elixir如何避免在 Ecto Query Elixir 中预加载
【发布时间】:2022-02-11 23:46:47
【问题描述】:

我有一张桌子GateReportSubclass(嵌入)和GateReportEvent(交付)。一个GateReportSubclass可以有多个GateReportEvent比如

  schema "deliveries" do
    field(:cameraex, :string)
    field(:arrived_at, :utc_datetime)
    field(:left_at, :utc_datetime)

    belongs_to(:embedding_in, GateReportSubclass, foreign_key: :embedding_id_in)
    belongs_to(:embedding_out, GateReportSubclass, foreign_key: :embedding_id_out)
  end

GateReportSubclass

  schema "embeddings" do
    field(:cameraex, :string)
    field(:embeddings, :map)

    has_many(:in_deliveries, GateReportEvent, foreign_key: :embedding_id_in)
    has_many(:out_deliveries, GateReportEvent, foreign_key: :embedding_id_out)
  end

所以,在 deliveries 中,embedding_id_in/embedding_id_out 中可以有 embeddings 的 id。

我正在尝试使用arrived_atleft_at 查询deliveries,以获取发生在特定日期事件的子类。

我有这个问题

GateReportSubclass
|> join(:left, [s], d in GateReportEvent,
  on: d.embedding_id_in == s.id or d.embedding_id_out == s.id
)
|> where([s], s.cameraex == ^exid)
|> where(
  query,
  [s, d],
  date_compare(^period, ^timezone, d.arrived_at, ^date) or
    date_compare(^period, ^timezone, d.left_at, ^date)
)
|> preload([:in_deliveries, :out_deliveries])
|> distinct([s], s.id)
|> select([:id, :class, :subclass, :cameraex, :features])

现在这个查询一切正常。 但是

GateReportSubclass 可以出现在超过 10K 个GateReportEvents 中,例如

  • GateReport 子类
    • in_deliveries [10k GateReportEvent]
    • out_deliveries [15k GateReportEvent]

在这种情况下查询很慢。我也想得到in_deliveriesout_deliveries 的总和。为此,我正在这样做

subclasses =
  data.items
  |> Enum.reduce([], fn subclass, acc ->
    %{in_deliveries: in_deliveries, out_deliveries: out_deliveries} = subclass
    occurances = Enum.count(in_deliveries) + Enum.count(out_deliveries)
    elem = subclass |> Map.from_struct() |> Map.put(:occurances, occurances)
    [acc | [elem]]
  end)
  |> List.flatten()

我想避免这个preload,但也想计算总进出事件的数量。你能指导我吗,我希望我解释得很好。提前致谢

Map.put(data, :items, subclasses)

【问题讨论】:

标签: elixir ecto


【解决方案1】:

如果您不需要预加载 GateReportEvents,请从查询中删除 |> preload([:in_deliveries, :out_deliveries])。您可以在 select 语句中使用聚合函数,它将在数据库服务器上执行聚合函数,而不是在您的应用程序代码中。这将更快、更高效。

你可能想尝试这样的事情:


from(
   grs in GateReportSubclass,

   left_join: gre in GateReportEvent,
   on: gre.embedding_id_in == grs.id or gre.embedding_id_out == grs.id,

   where: grs.cameraex == ^exid
   where: # put your date filtering clause here,

   select: %{
     id: grs.id,
     in_count: filter(sum(1), not is_nil(gre.embedding_id_in)),
     out_count: filter(sum(1), not is_nil(gre.embedding_id_out))
  }
) |> Repo.one()

这可能需要一些调整,因为我无法测试它,但似乎它应该可以工作。

【讨论】:

  • 请注意,过滤器 synatx 仅适用于 postgres,否则您必须使用带有 case 语句的片段。
猜你喜欢
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多