【发布时间】:2015-12-01 20:37:57
【问题描述】:
感谢 django 调试工具栏,我注意到每个 django 管理列表页面总是在我的所有查询中添加一个“ORDER BY id DESC”,即使我手动覆盖了 admin.ModelAdmin 的 get_queryset 方法(我通常这样做是因为我想在我的一些管理页面上进行自定义排序)
我想这并不是真正值得担心的事情,但这是数据库需要执行的额外排序操作,即使它根本没有意义。
有什么办法可以防止这种情况发生吗?似乎在某些模型上(即使不是全部),如果我添加排序元数据,那么它不会自动按 id 添加订单,但它会按该字段添加,这也是我不这样做的'不想要,因为这样做会将该顺序添加到我在代码中的所有其他查询中。
编辑:似乎罪魁祸首在 ChangeList 的 django.contrib.admin.views.main 上,在第 316 行的函数 get_ordering 上(django 1.7.10)
pk_name = self.lookup_opts.pk.name
if not (set(ordering) & set(['pk', '-pk', pk_name, '-' + pk_name])):
# The two sets do not intersect, meaning the pk isn't present. So
# we add it.
ordering.append('-pk')
我想知道这背后的原因是什么......
编辑: 为了提高性能,并且由于 MySQL(和 InnoDB)在没有给出 order by 时以聚集索引顺序返回数据,我可以安全地删除附加的 id。 这样做很简单,我刚刚扩展了 django 的 ChangeList 并修改了 get_ordering 方法。之后,只需创建一个自定义的管理模型,该模型从 ModelAdmin 扩展并覆盖 get_changelist 方法以返回上述类。
我希望它可以帮助任何人:)
【问题讨论】:
-
从技术上讲,任何没有
ORDER BY的 SQL 查询在结果顺序方面都受 RDMBS 的影响,因为根据定义,无序的结果是无序的……但 MySQL 倾向于以某种可预测的方式排序结果;然而,可预测性和确定性并不等同。这可能是在未指定排序时保持结果确定性的尝试,但我在推测。 -
我想排序需要能够对结果进行分页,但是,如果根本没有提供 odering 是有道理的,如果已经设置了排序,我认为 django 没有理由再添加另一个订购到最后
-
如果没有排序则不添加pk字段,如果不存在则添加。这正在扼杀我在具有巨大表的 MySQL 数据库上的性能,其中仅按我想要的字段排序非常快,但是在 order by 中添加额外的 pk 会使它慢 4 倍,因为 mysql 必须获取所有数据然后排序.
-
我怀疑他们为什么会这样做,因为非唯一列的排序在理论上仍然是模棱两可的(你如何定义具有相同值的多行的顺序?折腾PK)...实际上,在大多数情况下这不应该受到伤害,因为 PK 是免费的——它总是被复制到 MySQL 中的索引行中(呃,至少在 InnoDB 中)——但在其他情况下,特别是在选择标准和排序不能同时使用相同索引的情况下,它可能会扭曲优化器对查询计划的选择。
-
查询变得非常慢,基本上是按连接字段排序的(有一个巨大的表与一个较小的表以 1-N 关系连接,因为巨大的表需要关系中的一个字段),连接字段被索引并且在where条件下,因此仅按此字段排序会使查询非常快,但是在顺序中添加额外的'id'只会杀死查询性能。唯一的选择是使用子查询来模拟后期行查找,但这会破坏 django 管理分页,或者无法使用它
标签: python mysql django django-admin