Django4 中文入门教程 Django4.0 数据库访问优化-不要检索你不需要的东西

2024-02-25 开发教程 Django4 中文入门教程 匿名 4

使用 QuerySet.values() 和 values_list()

当你只想得到字典或列表的值,并且不需要 ​ORM ​模型对象时,可以适当使用 ​values()​ 。这些对于替换模板代码中的模型对象非常有用——只要你提供的字典具有与模板中使用时相同的属性就行。

使用 QuerySet.defer() 和 only()

如果你明确不需要这个数据库列(或在大部分情况里不需要),使用 ​defer()​ 和 ​only()​ 来避免加载它们。注意如果你使用它们,​ORM ​将必须在单独的查询中获取它们,如果你不恰当的使用,会让事情变得糟糕。
不要在没有分析的情况下过分使用延迟字段,因为数据库必须从磁盘中读取结果中单行的大部分非文本、非VARCHAR数据,即使它最终只使用的几列。当你不想加载许多文本数据或需要大量处理来转换回 Python的字段, ​defer()​ 和 ​only()​ 方法最有用。总之,先分析,再优化。

使用 QuerySet.contains(obj)

如果您只想找出 obj 是否在查询集中,而不是 obj 在查询集中。

使用 QuerySet.count()

如果你只想计数,不要使用 ​len(queryset)​。

使用 QuerySet.exists()

若你只想要确认是否有至少存在一项满足条件的结果,而不是​if queryset​。

不要过度使用 contains()、count() 和 exists()

如果你需要查询集中的其他数据,请立即对其进行评估。

假设 Group 模型与 User 具有多对多关系,则以下代码是最佳的:

members = group.members.all()
if display_group_members:
if members:
if current_user in members:
print("You and", len(members) - 1, "other users are members of this group.")
else:
print("There are", len(members), "members in this group.")
for member in members:
print(member.username)
else:
print("There are no members in this group.")

这是最佳的,因为:

  • 由于 ​QuerySet ​是惰性的,因此如果 ​display_group_members​ 为 ​False​,则不会进行数据库查询。
  • 将 ​group.members.all()​ 存储在 ​members ​变量中可以重用其结果缓存。
  • if members​: 导致 ​QuerySet.__bool__()​ 被调用,这导致 ​group.members.all()​ 查询在数据库上运行。 如果没有任何结果,它将返回 ​False​,否则返回 ​True​。
  • if current_user in members​:检查用户是否在结果缓存中,因此不会发出额外的数据库查询。
  • len(members)​ 的使用调用了 ​QuerySet.__len__()​,重用了结果缓存,因此再次没有发出数据库查询。
  • for member​循环遍历结果缓存。

使用 QuerySet.update() 和 delete()

如果要设置一些值并单独保存它们,而不是检索对象,那么可以通过 ​QuerySet.update()​ 使用批量 SQL ​UPDATE ​语句。类似地,尽可能使用批量删除( ​bulk deletes​ )。
注意,尽管这些批量更新方法不会调用单独实例的 ​save()​ 或 ​delete()​ 方法,这意味着你为这些方法添加的任何自定义行为都不会执行,包括来自正常数据库对象信号( ​signals​ )的任何内容。

直接使用外键值

如果只需要外键值,那么使用已有对象上的外键值,而不是获取所有相关对象并获取它的主键。比如:

entry.blog_id

替换成:

entry.blog.id

如无需要,不要排序结果

排序是耗时的;对每个字段的排序是数据库必须执行的操作。如果模型有一个默认排序( ​Meta.ordering​ )并且不需要它,那么可以通过调用没有参数的 ​order_by()​ 在查询集上删除它。
添加索引到你的数据库上可以帮助改进排序性能。