【问题标题】:Questionable SQL practice - Order By id rather than creation time可疑的 SQL 实践 - 按 id 排序而不是创建时间
【发布时间】:2012-12-09 22:45:26
【问题描述】:

所以我有一个有趣的问题,我不确定是否被视为“黑客”。我查看了一些问题,但没有找到重复的问题,所以在这里。基本上,我需要知道这是否不可靠或被认为是不好的做法。

我有一个非常简单的表,它有一个唯一的自动递增 id 和一个 created_at 时间戳。 (我的问题的简化版本以澄清相关概念)

+-----------+--------------------+
| id        |created_at          |
+-----------+--------------------+
| 1         |2012-12-11 20:35:19 |
| 2         |2012-12-12 20:35:19 |
| 3         |2012-12-13 20:35:19 |
| 4         |2012-12-14 20:35:19 |
+-----------+--------------------+

这两列都是动态添加的,因此可以说新的“插入”将总是具有更大的 id,而总是具有更大的日期。 p>

目标 - 非常简单地获取由 created_at 降序排列的结果

解决方案一 - 按日期降序排列的查询

SELECT * FROM tablename
ORDER BY created_at DESC

解决方案二 - 按 ID 降序排列的查询

SELECT * FROM tablename
ORDER BY id DESC

解决方案二是否被认为是不好的做法?或者解决方案二是正确的做事方式。当我试图理解这个概念时,对你的推理的任何解释都会非常有帮助,而不仅仅是简单地得到答案。提前致谢。

【问题讨论】:

  • 嗯,按 id 排序可以并且将利用索引。您应该在问题中包含架构的相关部分。
  • 虽然我不知道是否有“官方方式”来解决这个问题,但“order by”查询的存在就是为了做到这一点。按列排序。我看到的唯一缺点是,时间戳可能有重复(在同一秒内插入两次)并且由于缺少索引,查询可能会更慢。

标签: mysql sql database query-optimization


【解决方案1】:

在典型实践中,您几乎总是可以假设可以对自动增量 ID 进行排序,以便按创建顺序(任一方向)为您提供记录。但是,您应该注意,就您的数据而言,这不被认为是可移植的。您可能会将数据移动到重新创建密钥的另一个系统,但 created_at 数据是相同的。

其实有一个很不错的StackOverflow discussion这个issue。

基本总结是第一个解决方案,按 created_at 排序,被认为是最佳实践。但是,请务必正确索引 created_at 字段以提供最佳性能。

【讨论】:

  • 感谢您提供讨论链接,在我的研究中一定错过了它
  • 为什么投反对票?我希望至少看到一个解释以供将来参考。
【解决方案2】:

您不应该依赖 ID 来唯一标识一行。它是一个任意数字,仅与记录的创建顺序相对应。

假设你有这张桌子

ID  creation_date
1   2010-10-25
2   2010-10-26
3   2012-03-05

在这种情况下,按 ID 排序而不是按 creation_date 排序。

现在你意识到,哦,哎呀,你必须将记录 ID #2 的创建日期更改为 2010-09-17。您使用 ID 的排序现在以相同的顺序报告记录:

1   2010-10-25
2   2010-09-17
3   2012-03-05

即使有了新的日期,它们也应该是:

2   2010-09-17
1   2010-10-25
3   2012-03-05

短版:根据创建目的使用数据列。不要依赖数据的副作用。

【讨论】:

    【解决方案3】:

    这两个选项之间存在一些差异。


    首先是它们可以给出不同的结果。

    created_at 的值可能会受到服务器上正在调整的时间的影响,但id 列将不受影响。如果时间向后调整(手动或通过时间同步软件自动),您可以获得稍后插入的记录,但时间戳在较早插入的记录之前。在这种情况下,您将获得不同的顺序,具体取决于您订购的列。您认为哪个顺序“正确”取决于您。


    第二个是性能。 ORDER BY 你的 clustered index 可能会更快。

    聚集索引如何加快查询速度

    通过聚集索引访问一行速度很快,因为行数据位于索引搜索所引导的同一页面上。

    默认情况下,聚集键是主键,在您的情况下大概是 id 列。您可能会发现ORDER BY idORDER BY created_at 稍快。

    【讨论】:

    • MySQL 不关心聚集索引。 InnoDB 表不太可能按创建顺序存储记录。
    • @Javier:感谢您的评论。我添加了指向有关聚集索引的文档的链接,并从文档中引用。
    • 嗯...我的立场是正确的。他们一定是趁我不注意的时候潜入了 InnoDB 实现。
    【解决方案4】:

    ordering by id orders by insertion order.

    如果您有可能延迟插入的用例,例如批处理,那么您必须按 created_at 排序才能按时间排序。

    如果满足您的需要,两者都是可以接受的。

    【讨论】:

      【解决方案5】:

      主键,尤其是代理类型的主键,通常不代表任何类型的有意义的数据,除了它们的功能是允许唯一可识别的记录。由于在这种情况下日期确实代表了有意义的数据,这些数据在其主要功能之外具有意义,我想说根据日期进行排序是一种更合乎逻辑的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-12
        • 2018-10-05
        • 1970-01-01
        • 2020-01-21
        相关资源
        最近更新 更多