我正在使用Django 1.9.我有一个Django表,表示按月组织的特定度量值,原始值和百分位数:
class MeasureValue(models.Model):
org = models.ForeignKey(Org, null=True, blank=True)
month = models.DateField()
calc_value = models.FloatField(null=True, blank=True)
percentile = models.FloatField(null=True, blank=True)
Run Code Online (Sandbox Code Playgroud)
每月通常有10,000左右.我的问题是我是否可以加快在模型上设置值的过程.
目前,我通过使用Django过滤器查询检索一个月的所有度量值,将其转换为pandas数据帧,然后使用scipy rankdata来设置排名和百分位数来计算百分位数.我这样做是因为pandas rankdata是高效的,能够忽略空值,并能够以我想要的方式处理重复的值,所以我很满意这个方法:
records = MeasureValue.objects.filter(month=month).values()
df = pd.DataFrame.from_records(records)
// use calc_value to set percentile on each row, using scipy's rankdata
Run Code Online (Sandbox Code Playgroud)
但是,我需要从数据框中检索每个百分位值,并将其设置回模型实例.现在我通过迭代数据帧的行并更新每个实例来做到这一点:
for i, row in df.iterrows():
mv = MeasureValue.objects.get(org=row.org, month=month)
if (row.percentile is None) or np.isnan(row.percentile):
row.percentile = None
mv.percentile = row.percentile
mv.save()
Run Code Online (Sandbox Code Playgroud)
毫不奇怪,这很慢.是否有任何有效的Django方法来加速它,通过单个数据库写入而不是数万个?我检查了文档,但看不到一个.
ahm*_*med 19
原子事务可以减少循环中花费的时间:
from django.db import transaction
with transaction.atomic():
for i, row in df.iterrows():
mv = MeasureValue.objects.get(org=row.org, month=month)
if (row.percentile is None) or np.isnan(row.percentile):
# if it's already None, why set it to None?
row.percentile = None
mv.percentile = row.percentile
mv.save()
Run Code Online (Sandbox Code Playgroud)
Django的默认行为是在自动提交模式下运行.除非事务处于活动状态,否则每个查询都会立即提交到数据库.
通过使用with transaction.atomic() 所有插入被分组到单个事务中.提交事务所需的时间在所有随附的insert语句中分摊,因此每个insert语句的时间大大减少.
从Django 2.2开始,您可以使用bulk_update()queryset方法有效地更新所提供的模型实例上的给定字段,通常使用一个查询:
objs = [
Entry.objects.create(headline='Entry 1'),
Entry.objects.create(headline='Entry 2'),
]
objs[0].headline = 'This is entry 1'
objs[1].headline = 'This is entry 2'
Entry.objects.bulk_update(objs, ['headline'])
Run Code Online (Sandbox Code Playgroud)
在旧版本的Django的,你可以使用update()带Case/ When,如:
from django.db.models import Case, When
Entry.objects.filter(
pk__in=headlines # `headlines` is a pk -> headline mapping
).update(
headline=Case(*[When(pk=entry_pk, then=headline)
for entry_pk, headline in headlines.items()]))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8425 次 |
| 最近记录: |