-
count()与len()性能比较
Django-ORM查询queryset数据集是惰性查询的,只有使用到数据集时,ORM才会真正去执行查询语句,然后ORM会把查询到的数据集缓存到内存中,下次我们使用数据集时是从缓存中取值的。
- 1.如果queryset数据集被使用然后缓存,我们使用queryset对象结果集count()时其底层源码如下图是用len()计算结果集长度的,所以在此场景有缓存的情况下用len()和count()来计算查询结果集的效果是一样的;
- 2.如果只想获得queryset数据的长度而不做其他操作,count()底层实现用的是数据库的聚合函数查询计算结果,然后取其结果时间复杂度是O(1),空间复杂度为O(1),而len()底层实现是是需要获取整个queryset数据集时间复杂度为O(n),并且空间复杂度也为O(n),这种情况下使用count()更好;
- 3.如果既要计算queryset数据集的长度,又要对queryset数据集做其他操作(如获取每个queryset对象的属性等),使用len()计算长度时会比count()会更有优势,因为此时少了一次对数据的聚合查询操作。
- 4.如果对还未使用的queryset数据集,使用len()或者count()来计算结果集的长度,然后使用分页组件对数据集进行分页处理,最后使用我们分页后的结果集。此场景需要考虑以下几个因素:
- (1)如果此时我们使用的是len()的话我们会缓存整个queryset结果集,并相当于遍历了整个结果集时间复杂度为O(n),空间复杂度为O(n),分页操作对于我们后端的时间或者空间来说都没什么太大帮助了;
- (2)如果此时我们使用的是count()来计算长度的话,我们会多一次数据库查询操作,但是分页操作相当于查询结果集时sql语句然后limit 10(数字取决于我们分页的size),这样我们的时间复杂度和空间复杂度都可以降到O(1);
- 个人倾向的话可能在此种情况使用count(),通过多一次数据库查询操作来降低时间和空间的复杂度还是挺划算的。
-
嵌套查询
在使用嵌套查询时要谨慎,一些数据库后端(例如MySQL)不能很好地优化嵌套查询。在这种情况下,查询完毕后提取值列表然后将其传递到第二个查询中会比将两个查询嵌套更有效。也就是说,执行两个查询而不是一个:
values = Blog.objects.filter(
name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))
- 内存执行
由于最初的MySQL性能太慢,因此在Python中而不是数据库中执行第二步甚至可能更快:(但如果数据数量巨大回大量占用内存,时间与空间需要衡量)
names = masterQuery.filter(name__contains='test').values_list('name')
count = sum('9' in n for n in names)
欢迎讨论