【问题标题】:Is it more efficent to assign a database query to a variable for a single view than to have multiple queries将数据库查询分配给单个视图的变量是否比具有多个查询更有效
【发布时间】:2020-07-21 17:20:54
【问题描述】:

如果我想以几种不同的方式计算数据库中的人数,将初始 People.objects.all() 分配给变量(以下版本 A)比每次查询它更有效吗?

Version A 是否会导致对 db 的一次命中,而 Version B 会导致两次?

版本 A:

people_var = People.objects.all()
last_name_filter = people_var.filter(last_name='Doe').count()
first_name_filter = people_var.filter(first_name='John').count()

版本 B:

last_name_filter = People.objects.filter(last_name='Doe').count()
first_name_filter = People.objects.filter(first_name='John').count()

【问题讨论】:

  • 没有区别,两个版本都会命中数据库两次。请注意,QuerySets 是惰性的,因此永远不会执行 people_var,即使是,.filter(..) 也会创建一个新的查询集。
  • 如何才能更好地结构化?缓存初始查询,然后使用缓存?
  • 好吧,你总是不能对同一个过滤器多次执行count()。如果由于某种原因不知道last_name 值相似或不同,您可以使用一个单独的函数,将last_name 作为参数并将lru_cache 装饰器应用于它,这样对于相同的last_name,缓存的结果将被返回。
  • 您上面的代码可能有错误。在所有情况下,您都在查询 last_name。很确定这两个版本的第一个查询应该由first_name查询请在您的问题中解决这个问题,否则请指出当前过滤器是正确的,因为这会使问题不清楚且难以回答。
  • @rdik: 因为没有缓存,People.objects.all() 不会进行查询。

标签: python django database sqlite


【解决方案1】:

实际上,版本 A 是否会导致对 db 的一次命中,而版本 B 会导致两次?

,两者都会访问数据库两次。

People.objects.all() 确实进行查询。事实上,QuerySet懒惰。这意味着,除非您对它进行迭代,在其上调用len(…) 等等,否则它不会执行 对数据库的查询。因此,它基本上是一个等待执行的查询,除非必要。

即使people_var = Person.objects.all() 被执行了——它没有被执行,这并不意味着.filter(…) 函数会使用那个缓存。事实上,如果你在QuerySet 上调用.all().filter(…),你会创建一个未评估QuerySet

最后,如果您调用.count(),您不会发出QuerySet,因此会导致发出SELECT COUNT(*) FROM … 查询。因此,您在这里进行了两个单独的查询,每个查询将计算对象的数量。即使两个查询相同,Django 也会进行两个查询。数据库可能会更快地回答第二个查询,但这在两种情况下都是一样的。

【讨论】:

  • 添加到这个答案:值得了解 Django 访问数据库的方式和时间,以及如何通过阅读 Django 文档中的 Database access optimization 页面来优化它。
猜你喜欢
  • 2011-11-19
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
  • 2011-02-22
  • 1970-01-01
相关资源
最近更新 更多