现在,你看到问题了吗?没有?我也没有。(作者好萌)
我们有一些晚上运行的 ETL 进程,主要是在产品和用户表上做维护。这些 ETL 操作会更新字段然后插入表,这样它们也会获得了表的锁。
那么问题是什么?当 select_for_update
与 select_related
一起使用时,Django 将尝试获取查询中所有表的锁。
我们用来获取事务的代码尝试获取事务表、用户、产品、类别表的锁。一旦 ETL 在午夜锁定了后三个表,交易就开始失败。
一旦我们对问题有了更好的理解,我们就开始寻找只锁定必要表(事务表)的方法。(又)幸运的是,select_for_update
的一个新选项在 Django 2.0 中可用:
from django.db import transaction as db_transaction
…
with db_transaction.atomic():
transaction = (
Transaction.objects
.select_related(
‘user’,
‘product’,
‘product__category’,
)
.select_for_update(
of=(‘self’,)
)
.get(uid=uid)
)
…
这个 of
选项被添加到 select_for_update
,使用 of
可以指明我们要锁定的表,self
是一个特殊的关键字,表示我们要锁定我们正在处理的模型,即事务表。
目前,该功能仅适用于 PostgreSQL 和 Oracle。
7. 外键索引(FK Indexes)
创建模型时,Django 会在所有外键上创建一个 B-Tree 索引,它的开销可能相当大,而且有时候并不很必要。
典型的例子是 M2M(多对多)关系的直通模型:
class Membership(Model):
group = ForeignKey(Group)
user = ForeignKey(User)
在上面的模型中,Django 将会隐式的创建两个索引:一个用于用户,一个用于组。
M2M 模型中的另一个常见模式是在两个字段一起作为一个唯一约束。在这种情况下,意味着一个用户只能是同一个组的成员,还是那个模型:
class Membership(Model):
group = ForeignKey(Group)
user = ForeignKey(User)