2013-03-15 63 views
2

我有一个Django(1.4.2)的数据模型,像这样:优化访问从select_for_update记录

class CoreData(models.Model): 
    cdid = models.AutoField(primary_key=True,editable=False) 
    atr1 = # whatever 
    atr2 = # whatever 

class EnvironData(models.Model): 
    cdid = models.ForeignKey(CoreData) 
    # etc 

class TransactionData(models.Model): 
    edid = models.ForeignKey(EnvironData) 
    # etc 

我需要有一个原子事务,其中我更新etc交易数据:

tdo = TransactionData.objects.select_for_update().get(etc=criteria) 
# process transaction 
# modify tdo object 
tdo.save() 

到目前为止,这么好。但是,在process transaction的过程中,我需要检查CoreData.atr1CoreData.atr2

如果我通过tdo.edid.cdid.atr{1,2}访问那些,那么我的理解是我将有一个额外的读取数据库查询,因为Django获取缺失的数据。 (说实话,我不是100%肯定这只是一个;也可能是两个 - 甚至六个,但我会怀疑这一点)。

另一方面,如果我结合select_related()select_for_update()我不会只锁定不需要(不应该)锁定的数据,我还会为tdo.save()创建开销。

第三种方法可能是通过独立查询获取数据(与tdo无关),如果使用select_related(),将保证是单个数据库查询。另外,它可以使用values()

我认为最后一种方法是最有效的,因为查询可以从EnvironData对象开始,该对象的edid已经作为tdo.edid_id

我的观点是否合理?有更好的方法吗?

更新:这是完全没关系访问tdo.edid.cdid.atr{1,2}独立,甚至,他们可以在交易过程中发生变化,因为它们是相互独立的,它不要求他们保持整个交易的价值。 (谢谢@Uszy Wieloryba)

+1

你最终做了什么?我遇到过类似的情况,当我尝试在'select_related'中使用'select_for_update'时,我在Postgres中遇到了一个错误,更不用说我也担心这种性能(锁定是我最需要的广泛使用的功能)...这是棘手的东西:/ – orokusaki 2013-05-02 16:51:25

+0

@orokusaki是的,这是_is_棘手的东西。我必须承认我还没有优化它,所以生活在额外的数据库中,这不是性能问题。我从来不喜欢'select_related' /'select_for_update'方法,感谢您的反馈。那么看起来应该使用最后一种方法。你试过了吗? – 2013-05-02 18:07:25

+0

我还没有。我的想法:忘记表现并努力简化。如果它的N + 1问题(选择相关),这是一个大问题,但如果它只有3-5个额外的查询,我不会汗流it背。我宁愿在给定的视图中单独选择每条记录进行更新,而不是在精神开销“我必须记住在更新postgres时测试它”等等,如果它成为真正的数据库问题,另一个(更好?)解决方案可能是使用cache.add(...)来锁定记录。谷歌“使用memcached锁定”。 – orokusaki 2013-05-02 22:42:54

回答

0

如果您的# process transaction取决于CoreData.atr1CoreData.atr2,也许他们应该被锁定。

+0

你提到这种可能性是正确的。可能存在竞争条件,使得事务代码看到不一致的状态并失败。有趣的是,这两者是彼此独立的,只要在交易过程中的任何时间点检查他们每个人是否满足特定标准即可。无可否认,总体而言,情况并非总是如此。 – 2013-03-15 09:41:25