【问题标题】:Should I reverse order a queryset before slicing the first N records, or count it to slice the last N records?我应该在对前 N 条记录进行切片之前对查询集进行反向排序,还是对它进行计数以对最后 N 条记录进行切片?
【发布时间】:2017-05-09 03:44:21
【问题描述】:

假设我想在一个有 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 条记录),答案是否会改变?

【问题讨论】:

  • 当你使用.filter 时,Django 是否强加了一个有意义的顺序?通常,在 SQL 数据库中,最后 50 行 仅在使用 order by 或其等效项时才有意义。再次运行相同的查询可能不会以相同的顺序返回行。
  • 我在创建仪表板的背景下提出这个问题,我只想在其中显示一些合理的近期客户评论。对于这种特殊情况,排序严格性并不重要。
  • 相当近的在没有order by或类似的情况下也毫无意义。
  • 你说得对,我依赖于由自动增量 pk 排序返回的查询集,但它可能不是。同样,对于这个应用程序来说已经足够了。

标签: sql django postgresql


【解决方案1】:

这个会很慢

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

为什么是因为它翻译成

 SELECT * FROM myapp_mymodel OFFEST (index-50)

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

OTH,这个会很快

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]

按主键排序的成本非常低。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-25
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    • 2019-03-15
    相关资源
    最近更新 更多