【问题标题】:Finding most recent record: left outer join vs. sort descending查找最新记录:左外连接与降序排序
【发布时间】:2016-07-11 22:19:54
【问题描述】:

我需要在 table/Rails 模型中找到最近创建的记录,并且我想以一种有效的方式来完成它。我的主键是 UUID,因此使用 Rails Samples.last 方法将不起作用。对此进行谷歌搜索,Rails 的顶级答案使用sort ordered in descending order with a limit of 1。当然这不是唯一的方法,几年前我参加数据库课程时,我们经常用左外连接做这种事情。

我在 SQLServer 中尝试了这两种方法,但我对解释不太熟悉,无法判断哪种方法更好。我试过了:

SELECT TOP 1 * FROM samples ORDER BY created_at DESC;

这个解释显示了使用聚集索引扫描的排序。

SELECT * FROM samples s1 
LEFT OUTER JOIN samples s2 ON s1.created_at < s2.created_at 
WHERE s2.user_id IS NULL;

对此的解释显示了一个带有嵌套循环的过滤器,该过滤器使用两次聚集索引扫描。

这些中哪一个更好,或者它们是否具有可比性?还是我应该使用其他方法?排序版本对我来说似乎更清晰,所以我倾向于使用那个(我团队中的其他开发人员对 SQL 和数据库的了解甚至比我还少),但这将用于大型表,因此它需要高效。

另外,如果这很重要,我使用了 SQLServer,但我也有 MySQL 数据库,所以如果可能的话,我希望得到一个与数据库无关的答案。

【问题讨论】:

  • 那么 TOP 不是不可知论者
  • 我知道这一点。在 MySQL 中,它显然会使用 limit 重写。
  • 这对我来说并不明显 ;-)

标签: mysql sql ruby-on-rails sql-server


【解决方案1】:

假设您的 id 列有一个索引并且是一个主键,您可以安全地(?)假设最新的记录将是具有最高 ID 号的记录?

查询将是:

SELECT * FROM samples ORDER BY id DESC LIMIT 1;

或者,您可以使用Sample.last,它会为您完成。

编辑:

由于您的iduuid,我建议向created_at 列添加索引,以避免全表扫描。然后,为了让您的生活更轻松,您可以将以下范围添加到您的模型中:

scope :first, -> { order("created_at").first }
scope :last, -> { order("created_at DESC").first }

希望这会有所帮助!

【讨论】:

  • stackoverflow.com/questions/9780169/… 假定主键为整数。我的是一个UUID。我将编辑问题以反映这一事实。
  • 问题不是“我如何在 Rails 中做到这一点”。我已经知道该怎么做了。问题是“什么是最有效的方法”。默认的 Rails 做事方式不一定会产生最有效的数据库查询。
  • 正如我所说,我建议在您的created_at 列中添加索引。我看到您添加了 left join 查询,但我看不出它比列上的普通索引更快。
  • 我认为这是最有效的方法。 LEFT OUTER JOIN 本身不可能是一种有效的方法。不过,我并不完全确定全表扫描点。此外,您提到需要database-agnostic 方法,这绝对是这样。
【解决方案2】:

由于您使用的是 Ruby on Rails,您是否尝试过使用 Sample.last

您可以在这里阅读更多内容:Finder Methods: Last

【讨论】:

【解决方案3】:

我认为你可以做到:

Sample.order(created_at: :desc).first

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 2010-10-18
    • 2013-09-12
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    相关资源
    最近更新 更多