0

我们使用 heroku 作为部署服务。我们的 postgres 附加计划是 400 mb 内存限制的起重机,我们的数据库中有 460MB 数据。直到 2 天前,有时 postgres 服务器开始响应空结果集。

这是一个关于这种情况的示例,我们有一个条目模型的属性,并且在保存回调后将条目号分配给条目对象,但该条目号与 object_id 不同。这是我们的回调方法。

def assign_entry_no
  return true unless self.new_record? && !self.project.nil?
  last_entry = Entry.where(:project_id => self.project_id).last
  self.entry_no = last_entry.nil? ? 1 : (last_entry.entry_no + 1)
end

这是输出。

object_id -> id
---------|----
677467 -> 3
677466 -> 2
677465 -> 1 // empty result set
677462 -> 3
677461 -> 2
677460 -> 1 // empty result set
677459 -> 31
677458 -> 30
677457 -> 29

如您所见,有时 postgres 服务器返回空结果集。我们认为如果我们将附加计划升级到 800 mb,我们将解决问题。有没有人遇到过这个问题,是关于postgres服务器还是其他的东西?

我们的系统 => rails 3.0.2,mri ruby​​ 1.9.3

4

1 回答 1

1

Heroku Postgres 计划为您提供专用的缓存空间。您可以在 Crane 计划上超过 400mb,但您的某些查询可能响应较慢,因为数据库必须从磁盘访问数据。

我的假设是你的assign_entry_no方法没有按照你的想法做。

我将逐行剖析该方法,向您展示一些改进以及您可能遇到的问题。

  return true unless self.new_record? && !self.project.nil?

这条线应该做你认为它做的事情。但是,您可以通过将条件反转为类似if self.persisted? && self.project_id.present?. 这将使您无法执行unless然后撤消unlesson your!self.project.nil?子句。此外,使用project_id而不是为project您节省了数据库查询。

  last_entry = Entry.where(:project_id => self.project_id).last

这是问题线。首先,您在选择上没有排序,因此您最终可能会得到不一致的结果。我建议做类似的事情Entry.where(project_id: project_id).order(id: :desc).first。通过这种方式,您可以在一定程度上保证获得最后一个 id(并发问题除外)。

另一个问题是你的范围是:project_id. 我怀疑当您创建一个新项目(例如id = 44)时,您的查询是SELECT id FROM entries WHERE project_id = 44 ORDER BY id DESC LIMIT 1;. 由于项目 #44 是新项目,因此没有条目,因此您得到一个空集。这会导致下一行分配entry_no1。您可能会获得独特的[project_id, entry_no]集合,但不会获得[entry_no]属性。我说可能,因为在并发环境中,您最终可能会同时创建两个条目,它们last_entry在保存新条目之前都获得相同的记录。

  self.entry_no = last_entry.nil? ? 1 : (last_entry.entry_no + 1)

如果这是您打算做的,这条线似乎足够好。有些人更喜欢语法self.entry_no = if last_entry.nil? then 1 else last_entry.entry_no + 1 end,但逻辑是一样的。

结论

如果您真的希望entry_no每个条目记录都具有唯一性,为什么不直接使用该id列呢?它是自动递增的,并由数据库保证是唯一的。如果您想要 [project_id, entry_no] 对的唯一性,那么您的代码通常已经这样做了。运行 SQL 查询SELECT id, project_id, entry_no FROM entries;,您应该会看到这一点。如果这是你想要的,我建议在你的entries表中添加一个唯一索引[:project_id, :entry_no],这样你就可以保证不会重复。

于 2013-09-10T00:55:01.237 回答