【问题标题】:MySQL Select efficient first and last rowMySQL选择高效的第一行和最后一行
【发布时间】:2016-04-08 13:14:06
【问题描述】:

我想从 MySQL 数据库中的表中获取两行。这两行必须是我订购后的第一行和最后一行。为了实现这一点,我做了两个查询,这两个:

SELECT dateBegin, dateTimeBegin FROM worktime ORDER BY dateTimeBegin ASC LIMIT 1;";
SELECT dateBegin, dateTimeBegin FROM worktime ORDER BY dateTimeBegin DESC LIMIT 1;";

我决定不获取整个集合,而是在 PHP 中选择第一个和最后一个,以避免可能非常大的数组。我的问题是,我有两个查询,我真的不知道这有多有效。例如,我想将它们与 UNION 结合起来,但是我仍然需要对未排序的列表进行两次排序,这也是我想避免的,因为第二次排序与第一次排序完全相同

我想订购一次,然后选择这个有序列表的第一个和最后一个值,但我不知道比两个查询更有效的方法。我知道性能收益不会很大,但是我知道列表正在增长,并且随着它们变得越来越大,我为一些表执行这部分,我需要最有效的方法来做到这一点。 我发现了几个类似的主题,但没有一个涉及这个特定的性能问题。

非常感谢任何帮助。

【问题讨论】:

  • 为什么不像select datebegin, max(datetimebegin), min(datetimebegin) ...这样的?
  • 我读过类似的东西,但无法弄清楚它的工作原理。为什么我不选择这些是因为我不确定它们是否排序两次?
  • 根本没有排序。你会得到最大/最小的 datetimebegins 值,以及第一个计数的 datebegin。
  • 好吧,现在我觉得自己很愚蠢。万分感谢。我在排序问题上是如此固定,以至于我也将其误解为一个问题。如果您愿意,可以将您的第一条评论作为答案,我会接受。非常感谢,有时只是需要另一个头脑:)
  • @JRsz 如果 dateBegin 的值不重要,则没有问题。

标签: php mysql sql performance processing-efficiency


【解决方案1】:

您的查询很好。你想要的是worktime(dateTimeBegin) 上的索引。 MySQL 应该足够聪明,可以将这个索引用于ASC 和DESC 排序。如果您对其进行测试,但事实并非如此,那么您将需要两个索引:worktime(dateTimeBegin asc) 和 worktime(dateTimeBegin desc)。

是否运行一个或两个查询取决于您。一次查询(由UNION ALL 连接)效率稍高一些,因为您只有一次到数据库的往返行程。但是,两个可能更容易融入您的代码,并且性能差异对于大多数用途而言并不重要。

【讨论】:

    【解决方案2】:

    (这既是“答案”,也是对某些 cmets 错误的反驳。)

    INDEX(dateTimeBegin)
    

    将促进SELECT ... ORDER BY dateTimeBegin ASC LIMIT 1和另一端的相应行,使用DESC。

    MAX(dateTimeBegin) 将仅找到该列的最大值;它不会直接找到该行中的其余列。这需要一个子查询或JOIN。

    INDEX(... DESC) -- DESC 被 MySQL忽略。这几乎从来都不是一个缺点,因为优化器愿意通过索引向任一方向前进。重要的情况是ORDER BY x ASC, y DESC不能使用INDEX(x, y),也不能使用INDEX(x ASC, y DESC)。这是 MySQL 的不足之处。 (除此之外,我同意戈登的“回答”。)

    ( SELECT ... ASC )
    UNION ALL
    ( SELECT ... DESC )
    

    与两个单独的选择相比,不会提供太多(如果有的话)性能优势。选择让您的代码更简单的技术。

    拥有一个DATETIME(或TIMESTAMP)字段几乎总是比拆分DATE 和/或TIME 更好。 SELECT DATE(dateTimeBegin), dateTimeBegin ... 工作简单,而且“足够快”。另见函数DATE_FORMAT()。我建议删除dateBegin 列并相应地调整代码。请注意,缩小表实际上可能比DATE() 的成本更快地加快处理速度。 (差异将是无穷小的。)

    如果没有以dateTimeBegin 开头的索引,任何技术都会变慢,并且随着表的增大而变慢。 (我很确定它可以both在一个完整的通行证中找到MIN() 和MAX(),并且不进行排序。这对ORDER BYs 将需要两个完整的通行证,加上两种排序;5.6 可能有一个优化,几乎消除了排序。)

    如果有两行具有完全相同的最小值dateTimeBegin,您将无法预测哪一行。

    【讨论】:

    • 感谢您的回答。您提到的最后一点很好,因为我只对最低值感兴趣,因此它们可能会随心所欲地出现。由于 dateTimeBegin 的值对我来说是唯一有趣的值(我实际上不再使用另一个,所以这引起了一些混乱,并将从我的问题中删除)这个查询对我有用:SELECT MIN(dateTimeBegin) AS min, MAX(dateTimeBegin) AS max FROM worktime;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2015-03-13
    • 2015-10-10
    • 2013-12-09
    相关资源
    最近更新 更多