我应该在切割前N个记录之前反转命令查询集,还是将其计数以分割最后N个记录?

时间:2016-12-23 12:16:35

标签: sql django postgresql

假设我想在一个包含1M记录的表中获取返回大约10k条记录的查询的最后50条记录。我能做(以订购的计算成本):

data = MyModel.objects.filter(criteria=something).order_by('-pk')[:50]

我也可以(以2次数据库命中为代价):

# assume I don't care about new records being added between
# the two queries being executed
index = MyModel.objects.filter(criteria=something).count()
data = MyModel.objects.filter(criteria=something)[index-50:]

对于只有criteria没有索引的普通关系数据库哪个更好(例如我的情况下是postgres;没有柱状存储或任何花哨的东西)?最重要的是, 为什么?

如果表或查询集明显更大(例如10M行表中的100k记录),答案是否会改变?

1 个答案:

答案 0 :(得分:5)

这个会很慢

 data = MyModel.objects.filter(criteria=something)[index-50:]

为什么因为它转化为

 SELECT * FROM myapp_mymodel OFFEST (index-50)

您没有在此强制执行任何排序,因此服务器将不得不对结果集进行计算并跳转到结尾,并且这将涉及大量读取并且将非常慢。我们不要忘记count()查询也不是那么热。

其他,这个会很快

data = MyModel.objects.filter(criteria=something).order_by('-pk')[:50]

您在主键上反向排序并获得前50个。而前50个您可以使用

快速获取
data = MyModel.objects.filter(criteria=something).order_by('pk')[:50]

所以这就是你真正应该做的事情

data1 = MyModel.objects.filter(criteria=something).order_by('-pk')[:50]
data2 = MyModel.objects.filter(criteria=something).order_by('pk')[:50]

主键订购的成本非常低。