我想以并发安全的方式删除数量为零的行。可以想象的是,该行在即将被删除之前可能变为非零。
模型看起来像这样:
class Stock(models.Model):
product = models.ForeignKey(Product)
location = models.ForeignKey(Location)
quantity = models.IntegerField()
要删除它,我使用:
Stock.objects.filter(product=product, quantity=0).delete()
我希望SQL是:
DELETE FROM app_stock WHERE product=product AND quantity=0
但它正在进行优化,以:
DELETE FROM "app_stock" WHERE "app_stock"."id" IN (5)
这种优化在某种意义上是非常合理的,因为要删除的对象的ID是5,这是更有效的。不幸的是,这将是不安全的,因为股票可能会增加另一个过程在任何时候。
我可以用原始SQL解决这个问题。我也尝试过其他查询,但它总是以同样的方式优化。
1条答案
按热度按时间7d7tgy0s1#
这种优化在某种意义上是非常合理的,因为要删除的对象的ID是5,这是更有效的。
否,这不是出于性能原因,特别是为了首先知道主键是什么,Django执行另一个查询。因此,为了删除,至少进行两次查询。
发生这种情况的原因是因为Django本身执行
on_delete=…
查询。因此,它首先需要将被移除的对象,并且如果存在ForeignKey
s等。它还将获取指向这些对象的相关查询集以相应地执行触发器。通过手动执行触发器,在单个查询中(几乎)不可能做到这一点。最好的办法可能是将这些内容 Package 在 transactions 中,这样最终的删除是原子地完成的:它要么完全成功,要么根本不成功。