Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql ActiveRecordfirst方法是否总是返回ID最小的记录?_Postgresql_Ruby On Rails 4_Activerecord - Fatal编程技术网

Postgresql ActiveRecordfirst方法是否总是返回ID最小的记录?

Postgresql ActiveRecordfirst方法是否总是返回ID最小的记录?,postgresql,ruby-on-rails-4,activerecord,Postgresql,Ruby On Rails 4,Activerecord,环境:Rails 4.2.4,Postgres 9.4.1.0 是否可以保证ActiveRecordfirst方法将始终返回ID最小的记录和ID最大的ActiveRecordlast 我可以从Rails控制台看到,对于这两种方法,适当的顺序ASC/DESC被添加到生成的SQL中。但另一个SO线程的作者告诉我们,第一个方法返回的不是第一条记录 ActiveRecord优先: 2.2.3:001>账户优先 帐户加载1.3ms选择帐户。*从帐户顺序按帐户。id ASC限制1 ActiveRecord上

环境:Rails 4.2.4,Postgres 9.4.1.0

是否可以保证ActiveRecordfirst方法将始终返回ID最小的记录和ID最大的ActiveRecordlast

我可以从Rails控制台看到,对于这两种方法,适当的顺序ASC/DESC被添加到生成的SQL中。但另一个SO线程的作者告诉我们,第一个方法返回的不是第一条记录

ActiveRecord优先:

2.2.3:001>账户优先 帐户加载1.3ms选择帐户。*从帐户顺序按帐户。id ASC限制1

ActiveRecord上次:

2.2.3:002>Account.last 帐户加载0.8ms选择帐户。*从帐户按帐户排序。id描述限制1

==========

稍后添加:

所以,我根据D-side的答案做了自己的调查,答案是否定的。一般来说,唯一的保证是第一个方法将返回集合中的第一条记录。它可能会产生副作用,将ORDER BY PRIMARY_KEY条件添加到SQL中,但这取决于记录是否已加载到缓存/内存中

以下是从Rails 4.2.4中提取的方法: /activerecord/lib/active\u record/relation/finder\u methods.rb

现在,示例与有很多关系:

Account有多个AccountStatus,AccountStatus属于Account

a = Account.first
a.account_statuses # No ordering

a.account_statuses.first
# Here is a tricky part: sometimes it returns @record[index] entry, sometimes it may add ORDER BY ID (if records were not loaded before)
以下是我的结论: 将方法first视为从已加载的集合返回第一条记录,该集合可以按任意顺序加载,即无序加载。若我想确保第一个方法将返回ID最小的记录,那个么我应用第一个方法的集合应该在之前进行适当的排序

关于第一种方法的Rails文档是错误的,需要重写。

1.1.3首先


第一个方法查找按主键排序的第一条记录 我认为您引用的答案甚至与它所涉及的问题都不相关,因为它指的是非有序查询,而第一个和最后一个确实应用了基于id的顺序

在某些情况下,如果要对查询应用自己的组,则不能使用first或last,因为如果分组不包含id,则无法应用order by,但可以使用take来只返回第一行


我记得,有一些版本的first和/或last没有在PostgreSQL上应用最新Rails 3的顺序1,但它们都是错误的。

它可能会根据您的数据库引擎而变化,它总是使用first方法返回mysql中的最小ID,但对PostgreSQL不起作用,当我还是nobai的时候,我有几个问题,我的应用程序在本地mysql中正常工作,但是当使用postgresql部署到heroku时,一切都乱七八糟,因此为了避免postgresql出现问题,请在查询之前始终按id排序记录:

SELECT  `accounts`.* FROM `accounts`  ORDER BY `accounts`.`id` ASC LIMIT 1
帐户。订单:id优先

以上确保了mysql、postgresql和任何其他数据库引擎的最小ID,如查询中所示:

SELECT  `accounts`.* FROM `accounts`  ORDER BY `accounts`.`id` ASC LIMIT 1
如果未选择排序,则将以未指定的方式返回行 顺序这种情况下的实际顺序将取决于扫描和连接 计划类型和磁盘上的顺序,但不能依赖它。A. 只有在执行排序步骤时,才能保证特定的输出顺序 明确选择

重点矿山

所以ActiveRecord实际上增加了主键排序,以保持结果的确定性。相关的源代码很容易找到,但以下是Rails 4.2.4的摘录:

# show-source Thing.all.first
def first(limit = nil)
  if limit
    find_nth_with_limit(offset_index, limit)
  else
    find_nth(0, offset_index)
  end
end

# show-source Thing.all.find_nth
def find_nth(index, offset)
  if loaded?
    @records[index]
  else
    offset += index
    @offsets[offset] ||= find_nth_with_limit(offset, 1).first
  end
end

# show-source Thing.all.find_nth_with_limit    
def find_nth_with_limit(offset, limit)
  relation = if order_values.empty? && primary_key
               order(arel_table[primary_key].asc) # <-- ATTENTION
             else
               self
             end

  relation = relation.offset(offset) unless offset.zero?
  relation.limit(limit).to_a
end
所以,相信first会返回ID最低、ID最高的记录安全吗?high是指last,但是的。
# show-source Thing.all.first
def first(limit = nil)
  if limit
    find_nth_with_limit(offset_index, limit)
  else
    find_nth(0, offset_index)
  end
end

# show-source Thing.all.find_nth
def find_nth(index, offset)
  if loaded?
    @records[index]
  else
    offset += index
    @offsets[offset] ||= find_nth_with_limit(offset, 1).first
  end
end

# show-source Thing.all.find_nth_with_limit    
def find_nth_with_limit(offset, limit)
  relation = if order_values.empty? && primary_key
               order(arel_table[primary_key].asc) # <-- ATTENTION
             else
               self
             end

  relation = relation.offset(offset) unless offset.zero?
  relation.limit(limit).to_a
end