在查询参数中跟踪关系还是在 Django 模型中使用模型属性查找更快?
Is it faster to follow relations in a query parameter or using model attribute lookup in Django Models?
假设我有三个 Django 模型:
User
,
Staff
与 User
, 一对一
Thing
与 'owner' 字段上的 Staff
是多对一的。
使用 MySQL 数据库,其中哪个性能更好?
Thing.objects.filter(owner=user.staff) # A
Thing.objects.filter(owner__user=user) # B
如果我要检查我想要的 Thing
属于 User
:
怎么办?
try:
Thing.objects.get(id=some_id, owner=user.staff) # D
Thing.objects.get(id=some_id, owner__user=user) # E
except Thing.DoesNotExist:
return None
else:
pass # do stuff
# Or F:
thing = Thing.objects.get(id=some_id)
if thing.owner.user != user:
return None
pass # do stuff
这两个查询最终可能会相同 SQL,具体取决于您的设置、模型、索引和数据库驱动程序。您可以使用 .query
成员变量来验证这一点。如果它们不同,唯一真正的测试将是经验性的。我可以推荐 django-devserver and ipython 作为分析工具。
Thing.objects.filter(owner=user.staff) # A
Thing.objects.filter(owner__user=user) # B
我认为第二个"better"。假设您从请求中获得了用户记录:
- B 将仅针对事物生成 1 个 SQL 查询。
- 我认为 A 会为 user.staff 生成一个查询,然后在 Thing 上生成一个查询。 (这也可能需要更多内存用于员工实例)
为了确保尝试这个并使用调试工具栏检查时间和生成的查询:
for i in range(0, 100):
things = Thing.objects.filter(owner=user.staff) # A
#things = Thing.objects.filter(owner__user=user) # B
# that will execute the queries
for thing in things.all():
print thing.name
然后替换成B...
这在很大程度上取决于您如何获得原始对象以及此后您对它们所做的工作。如果您已经访问过 user.staff
,或者您最初使用 select_related
查询用户,那么第一个查询更好,因为它是一个 table 上的简单 SELECT,而第二个将执行 JOIN 以获取用户 table.
但是,如果您还没有访问过 user.staff
并且最初不是通过 select_related
获取它,第一个表达式将导致 user.staff
被计算,这会触发一个单独的查询,甚至在进行 Thing 查找之前。因此,在这种情况下,第二个查询将更可取,因为带有 JOIN 的单个查询优于两个简单查询。
但请注意,这几乎可以肯定是微优化,对您的总体 运行 时间影响很小。
假设我有三个 Django 模型:
User
,Staff
与User
, 一对一
Thing
与 'owner' 字段上的Staff
是多对一的。
使用 MySQL 数据库,其中哪个性能更好?
Thing.objects.filter(owner=user.staff) # A
Thing.objects.filter(owner__user=user) # B
如果我要检查我想要的 Thing
属于 User
:
try:
Thing.objects.get(id=some_id, owner=user.staff) # D
Thing.objects.get(id=some_id, owner__user=user) # E
except Thing.DoesNotExist:
return None
else:
pass # do stuff
# Or F:
thing = Thing.objects.get(id=some_id)
if thing.owner.user != user:
return None
pass # do stuff
这两个查询最终可能会相同 SQL,具体取决于您的设置、模型、索引和数据库驱动程序。您可以使用 .query
成员变量来验证这一点。如果它们不同,唯一真正的测试将是经验性的。我可以推荐 django-devserver and ipython 作为分析工具。
Thing.objects.filter(owner=user.staff) # A
Thing.objects.filter(owner__user=user) # B
我认为第二个"better"。假设您从请求中获得了用户记录:
- B 将仅针对事物生成 1 个 SQL 查询。
- 我认为 A 会为 user.staff 生成一个查询,然后在 Thing 上生成一个查询。 (这也可能需要更多内存用于员工实例)
为了确保尝试这个并使用调试工具栏检查时间和生成的查询:
for i in range(0, 100):
things = Thing.objects.filter(owner=user.staff) # A
#things = Thing.objects.filter(owner__user=user) # B
# that will execute the queries
for thing in things.all():
print thing.name
然后替换成B...
这在很大程度上取决于您如何获得原始对象以及此后您对它们所做的工作。如果您已经访问过 user.staff
,或者您最初使用 select_related
查询用户,那么第一个查询更好,因为它是一个 table 上的简单 SELECT,而第二个将执行 JOIN 以获取用户 table.
但是,如果您还没有访问过 user.staff
并且最初不是通过 select_related
获取它,第一个表达式将导致 user.staff
被计算,这会触发一个单独的查询,甚至在进行 Thing 查找之前。因此,在这种情况下,第二个查询将更可取,因为带有 JOIN 的单个查询优于两个简单查询。
但请注意,这几乎可以肯定是微优化,对您的总体 运行 时间影响很小。