Ruby on rails 避免生成N+;1通过ActiveRecord获取对象图时的查询

Ruby on rails 避免生成N+;1通过ActiveRecord获取对象图时的查询,ruby-on-rails,activerecord,ancestry,Ruby On Rails,Activerecord,Ancestry,我有两个模型:资产和所有权 资产属于所有权/所有权有许多资产项 标题可以具有父标题(从而创建层次结构);头衔中的父/子关系由祖先宝石管理 我有一个控制器正在获取一堆资产。这些资产应该与他们的头衔、头衔的父项、头衔的父项等一起出现。最后,控制器用JSON表示这个对象图。我正在试图找到一种方法,以便为给定的资产项加载所有的标题层次结构 我在控制器中执行此操作: def show asset_items = AssetItem.includes(:title).where(:id =>

我有两个模型:资产和所有权

  • 资产属于所有权/所有权有许多资产项
  • 标题可以具有父标题(从而创建层次结构);头衔中的父/子关系由祖先宝石管理
我有一个控制器正在获取一堆资产。这些资产应该与他们的头衔、头衔的父项、头衔的父项等一起出现。最后,控制器用JSON表示这个对象图。我正在试图找到一种方法,以便为给定的资产项加载所有的标题层次结构

我在控制器中执行此操作:

def show
  asset_items = AssetItem.includes(:title).where(:id => list_of_ids)
  eager_load_titles_for(asset_items)
  respond_with asset_items, serializer: AssetItemSerializer
end

private

def eager_load_titles_for(asset_items)
  title_ids = asset_items.map { |a| a.title.ancestor_ids }.flatten
  Title.find(title_ids) # these titles are not really used, this is just to eager load them
end
其思想是,获取资产项的集合,然后简单地加载(但不使用)与这些资产项关联的标题ID,这样当序列化程序执行类似于object.parent.parent.parent.some_属性的操作时,它从缓存而不是数据库获取该标题

但是,日志中的结果与我的预期不符:

10:19:27 web.1    |   AssetItem Load (1.3ms)  SELECT "asset_items".* FROM "asset_items" WHERE "asset_items"."id" IN (291, 311, 316, 309, 323, 304, 296, 289, 328, 284, 373, 342, 330, 335, 361, 366, 354, 347, 359, 380, 400, 405, 392, 378, 397, 417, 412, 385, 436, 429, 450, 448, 431, 455, 462, 424, 443, 481, 498, 467, 501, 493, 474, 506, 486, 479, 532, 525, 520, 513)
10:19:27 web.1    |   Title Load (0.6ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" IN (167, 182, 188, 203, 227, 242, 248, 263, 284, 299, 305, 320, 341, 356, 377, 392, 398, 413, 434, 449, 455, 470, 491, 506, 515, 530, 551, 566, 587, 602, 608, 623, 644, 659, 665, 680, 701, 716, 737, 752, 758, 773, 794, 809, 818, 833, 854, 875, 890, 911)
10:19:27 web.1    |   Title Load (0.9ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" IN (186, 187, 246, 247, 261, 262, 240, 241, 282, 283, 225, 226, 201, 202, 180, 181, 297, 298, 165, 166, 432, 433, 339, 340, 303, 304, 318, 319, 396, 397, 411, 412, 375, 376, 354, 355, 390, 391, 453, 454, 513, 514, 528, 529, 489, 490, 447, 448, 504, 505, 564, 565, 549, 550, 468, 469, 621, 622, 600, 601, 663, 664, 657, 658, 606, 607, 678, 679, 699, 700, 585, 586, 642, 643, 756, 757, 807, 808, 714, 715, 816, 817, 792, 793, 735, 736, 831, 832, 771, 772, 750, 751, 909, 910, 888, 889, 873, 874, 852, 853)
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "asset_items".* FROM "asset_items" WHERE "asset_items"."id" IN (291, 311, 316, 309, 323, 304, 296, 289, 328, 284, 373, 342, 330, 335, 361, 366, 354, 347, 359, 380, 400, 405, 392, 378, 397, 417, 412, 385, 436, 429, 450, 448, 431, 455, 462, 424, 443, 481, 498, 467, 501, 493, 474, 506, 486, 479, 532, 525, 520, 513)
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" IN (167, 182, 188, 203, 227, 242, 248, 263, 284, 299, 305, 320, 341, 356, 377, 392, 398, 413, 434, 449, 455, 470, 491, 506, 515, 530, 551, 566, 587, 602, 608, 623, 644, 659, 665, 680, 701, 716, 737, 752, 758, 773, 794, 809, 818, 833, 854, 875, 890, 911)
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" IN (186, 187, 246, 247, 261, 262, 240, 241, 282, 283, 225, 226, 201, 202, 180, 181, 297, 298, 165, 166, 432, 433, 339, 340, 303, 304, 318, 319, 396, 397, 411, 412, 375, 376, 354, 355, 390, 391, 453, 454, 513, 514, 528, 529, 489, 490, 447, 448, 504, 505, 564, 565, 549, 550, 468, 469, 621, 622, 600, 601, 663, 664, 657, 658, 606, 607, 678, 679, 699, 700, 585, 586, 642, 643, 756, 757, 807, 808, 714, 715, 816, 817, 792, 793, 735, 736, 831, 832, 771, 772, 750, 751, 909, 910, 888, 889, 873, 874, 852, 853)
10:19:27 web.1    |   Title Load (0.4ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 186]]
10:19:27 web.1    |   Title Load (0.2ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]
10:19:27 web.1    |   CACHE (0.0ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]
如您所见,最初标题ID 186和187加载在此处的where子句中:

10:19:27 web.1    |   Title Load (0.9ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" IN (186, 187, 246, 247, 261, 262, 240, 241, 282, 283, 225, 226, 201, 202, 180, 181, 297, 298, 165, 166, 432, 433, 339, 340, 303, 304, 318, 319, 396, 397, 411, 412, 375, 376, 354, 355, 390, 391, 453, 454, 513, 514, 528, 529, 489, 490, 447, 448, 504, 505, 564, 565, 549, 550, 468, 469, 621, 622, 600, 601, 663, 664, 657, 658, 606, 607, 678, 679, 699, 700, 585, 586, 642, 643, 756, 757, 807, 808, 714, 715, 816, 817, 792, 793, 735, 736, 831, 832, 771, 772, 750, 751, 909, 910, 888, 889, 873, 874, 852, 853)
然后在下面,我们再次看到:

10:19:27 web.1    |   Title Load (0.4ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 186]]
10:19:27 web.1    |   Title Load (0.2ms)  SELECT "titles".* FROM "titles" WHERE "titles"."id" = $1 LIMIT 1  [["id", 187]]

这就是为什么我想知道我做错了什么。如果有任何帮助,我们将不胜感激。

包含的
已经在进行急切加载时,您为什么还要调用
急切加载\u titles\u来进行
?您的
Title
记录是否与其祖先有关联?@omarvelous-因为当序列化程序正在执行asset\u item.Title.parent.parent.foo时,它导致数据库加载。eager_load_titles_for是一种通过查找层次链上的父级并将activerecord缓存来预加载该标题的尝试them@carlosramireziii-标题有祖先(和祖先栏),并且有很多:资产项目我们确定了导致n+1的确切原因,它是调用
object.parent.parent.parent.some_属性
时的视图还是
eager_load_titles_中的
祖先ID