我如何确定在 Django 中向 `prefetch_related` 提供哪些 "key path" 参数?
How do I determine what "key path" arguments to provide to `prefetch_related` in Django?
注意:下面,我将把提供给 prefetch_related
的参数称为“关键路径”。我不知道那是不是 best/correct 术语 - 所以让我知道是否有更好的术语可以使用,我会更新问题。
我在 Django 中创建了一个高级搜索页面,它从 6 个不同的 table 中搜索许多字段中的任何一个(并非所有这些都是单个直接外键路径)并显示所有这些字段中的选定字段table 结果 table。包含的“关键路径”是:
msrun__sample
msrun__sample__tissue
msrun__sample__animal
msrun__sample__animal__tracer_compound
msrun__sample__animal__studies
(注意:搜索或显示中不包含 ms运行 字段。该特定模型 class 在该特定视图中仅用作模型 classes参与了视图。)
当我包含像 .prefetch_related("msrun__sample__animal__studies")
这样的预取时,运行 时间有很大的不同,但是当我包含任何额外的预取“关键路径”时,我看不出有什么明显的区别。
我的问题是:如何确定要在 prefetch_related
的参数中包含哪个“关键路径”或“关键路径”?我似乎不明白该决定的标准。 IE。例如,为什么我会或不会在 prefetch_related
个参数中包含所有相关的“关键路径”?
使用以下模型进行了尝试:
class A(models.Model):
name = models.CharField(max_length=100)
my_b_set = models.ManyToManyField('B', related_name='my_a')
class B(models.Model):
name = models.CharField(max_length=100)
my_c_set = models.ManyToManyField('C', related_name='my_b')
my_d_set = models.ManyToManyField('D', related_name='my_c')
class C(models.Model):
name = models.CharField(max_length=100)
class D(models.Model):
name = models.CharField(max_length=100)
并像这样填充关系:
a = A.objects.create(name='a1')
b1 = B.objects.create(name='b1')
b2 = B.objects.create(name='b2')
c1 = C.objects.create(name='c1')
c2 = C.objects.create(name='c2')
d1 = D.objects.create(name='d1')
d2 = D.objects.create(name='d2')
a.my_b_set.add(b1)
a.my_b_set.add(b2)
b1.my_c_set.add(c1, c2)
b1.my_d_set.add(d1, d2)
b2.my_c_set.add(c1, c2)
b2.my_d_set.add(d1, d2)
然后 运行 这个查询:
A.objects.prefetch_related('my_b_set', 'my_b_set__my_c_set', 'my_b_set__my_d_set')
正如预期的那样,它进行了 4 次查询:
-- Get all A's
SELECT "changelog_a"."id", "changelog_a"."name" FROM "changelog_a"
-- Get all the related B's of A mapped with A's id
SELECT ("changelog_a_my_b_set"."a_id") AS "_prefetch_related_val_a_id", "changelog_b"."id", "changelog_b"."name"
FROM "changelog_b" INNER JOIN "changelog_a_my_b_set" ON ("changelog_b"."id" = "changelog_a_my_b_set"."b_id")
WHERE "changelog_a_my_b_set"."a_id" IN (2)
-- Get all the related C's of B mapped with B's id
SELECT ("changelog_b_my_c_set"."b_id") AS "_prefetch_related_val_b_id", "changelog_c"."id", "changelog_c"."name"
FROM "changelog_c" INNER JOIN "changelog_b_my_c_set" ON ("changelog_c"."id" = "changelog_b_my_c_set"."c_id")
WHERE "changelog_b_my_c_set"."b_id" IN (3, 4)
-- Get all the related D's of B mapped with B's id
SELECT ("changelog_b_my_d_set"."b_id") AS "_prefetch_related_val_b_id", "changelog_d"."id", "changelog_d"."name"
FROM "changelog_d" INNER JOIN "changelog_b_my_d_set" ON ("changelog_d"."id" = "changelog_b_my_d_set"."d_id")
WHERE "changelog_b_my_d_set"."b_id" IN (3, 4)
因此在此示例中,具有新关系的重叠键路径不会重复 B 的查询,并且只会为这些新关系创建新查询。
注意:下面,我将把提供给 prefetch_related
的参数称为“关键路径”。我不知道那是不是 best/correct 术语 - 所以让我知道是否有更好的术语可以使用,我会更新问题。
我在 Django 中创建了一个高级搜索页面,它从 6 个不同的 table 中搜索许多字段中的任何一个(并非所有这些都是单个直接外键路径)并显示所有这些字段中的选定字段table 结果 table。包含的“关键路径”是:
msrun__sample
msrun__sample__tissue
msrun__sample__animal
msrun__sample__animal__tracer_compound
msrun__sample__animal__studies
(注意:搜索或显示中不包含 ms运行 字段。该特定模型 class 在该特定视图中仅用作模型 classes参与了视图。)
当我包含像 .prefetch_related("msrun__sample__animal__studies")
这样的预取时,运行 时间有很大的不同,但是当我包含任何额外的预取“关键路径”时,我看不出有什么明显的区别。
我的问题是:如何确定要在 prefetch_related
的参数中包含哪个“关键路径”或“关键路径”?我似乎不明白该决定的标准。 IE。例如,为什么我会或不会在 prefetch_related
个参数中包含所有相关的“关键路径”?
使用以下模型进行了尝试:
class A(models.Model):
name = models.CharField(max_length=100)
my_b_set = models.ManyToManyField('B', related_name='my_a')
class B(models.Model):
name = models.CharField(max_length=100)
my_c_set = models.ManyToManyField('C', related_name='my_b')
my_d_set = models.ManyToManyField('D', related_name='my_c')
class C(models.Model):
name = models.CharField(max_length=100)
class D(models.Model):
name = models.CharField(max_length=100)
并像这样填充关系:
a = A.objects.create(name='a1')
b1 = B.objects.create(name='b1')
b2 = B.objects.create(name='b2')
c1 = C.objects.create(name='c1')
c2 = C.objects.create(name='c2')
d1 = D.objects.create(name='d1')
d2 = D.objects.create(name='d2')
a.my_b_set.add(b1)
a.my_b_set.add(b2)
b1.my_c_set.add(c1, c2)
b1.my_d_set.add(d1, d2)
b2.my_c_set.add(c1, c2)
b2.my_d_set.add(d1, d2)
然后 运行 这个查询:
A.objects.prefetch_related('my_b_set', 'my_b_set__my_c_set', 'my_b_set__my_d_set')
正如预期的那样,它进行了 4 次查询:
-- Get all A's
SELECT "changelog_a"."id", "changelog_a"."name" FROM "changelog_a"
-- Get all the related B's of A mapped with A's id
SELECT ("changelog_a_my_b_set"."a_id") AS "_prefetch_related_val_a_id", "changelog_b"."id", "changelog_b"."name"
FROM "changelog_b" INNER JOIN "changelog_a_my_b_set" ON ("changelog_b"."id" = "changelog_a_my_b_set"."b_id")
WHERE "changelog_a_my_b_set"."a_id" IN (2)
-- Get all the related C's of B mapped with B's id
SELECT ("changelog_b_my_c_set"."b_id") AS "_prefetch_related_val_b_id", "changelog_c"."id", "changelog_c"."name"
FROM "changelog_c" INNER JOIN "changelog_b_my_c_set" ON ("changelog_c"."id" = "changelog_b_my_c_set"."c_id")
WHERE "changelog_b_my_c_set"."b_id" IN (3, 4)
-- Get all the related D's of B mapped with B's id
SELECT ("changelog_b_my_d_set"."b_id") AS "_prefetch_related_val_b_id", "changelog_d"."id", "changelog_d"."name"
FROM "changelog_d" INNER JOIN "changelog_b_my_d_set" ON ("changelog_d"."id" = "changelog_b_my_d_set"."d_id")
WHERE "changelog_b_my_d_set"."b_id" IN (3, 4)
因此在此示例中,具有新关系的重叠键路径不会重复 B 的查询,并且只会为这些新关系创建新查询。