我们正在使用heroku作为部署服务。我们的postgres附加计划是具有400 MB内存限制的起重机,我们的数据库中有460MB数据。直到2天前,有时postgres服务器开始响应空结果集。 / p>
这是一个关于这种情况的例子 我们的Entry模型有一个属性,在保存回调之后为条目对象分配条目no,但是这个条目no与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
答案 0 :(得分: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
,然后撤消unless
子句中的!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_no
分配给1
。您可能会获得唯一的[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]
表格中添加唯一索引,以确保不会出现重复。