Django轻量级"更新"庞大的数据集

时间:2018-05-18 09:28:49

标签: python sql django postgresql orm

我有一个非常大的数据集,我需要尽快更新。我做了我的计算,并在最后有一个需要更新的事项列表:

updates = [(instance_pk, value_to_update), (instance_pk, value_to_update), ..]

模型在整个过程中都是一样的,正在更新的列。

过去我使用过Django Bulk Update - 而且我非常确定我能在这里 - 但即便如此,这样一个简单的过于强大(并因此处理太多的处理,因为它处理完整的实例)写道,我需要快速发生。我提到速度在这里很重要吗?

Django是否提供任何可以使这更容易,而无需编写原始SQL?

PostgreSQL 10是数据库,如果证明它是相关的。

我已经测试了原始SQL,这可以预见性能,但是这里看起来很像,所以你要清楚我在Django中尝试做什么。< / p>

with connection.cursor() as c:
    c.executemany(
        'UPDATE app_model SET column_a = %s WHERE id = %s',
        [(value_to_update, instance_pk), ...]
    )

可能有更高效的SQL而不是执行许多(我认为在一次交易中会抛出许多查询)。

2 个答案:

答案 0 :(得分:2)

虽然Kos正在撰写他们的优秀答案,但我仍在努力改进原始SQL方法,只是为了加快速度。

cursor.executemany()并不聪明。它只是立即执行大量查询。 PostsgreSQL有一个UPDATE FROM VALUES(..)子句,但与它接口是很棘手的。值得庆幸的是,psycopg2有一个特殊的execute_values用于制作这些值集,它们甚至记录了一个更新示例。

如果您正在使用psycopg2 + Postgres,Django会将您的原始psycopg2连接传回给您,所以这一切都非常容易使用:

from django.db import connection
from psycopg2.extras import execute_values

with connection.cursor() as c:
    execute_values(
        c,
        'UPDATE app_model SET column_a = v.sid FROM (VALUES %s) as v (sid, bid) WHERE id = v.bid',
        [(value_to_update, instance_pk), ...]
    )

而且速度难以想象。我认为它不会比这更好。

答案 1 :(得分:1)

给定一个键值对列表,您可以通过几种方法在SQL中运行UPDATE:

只是很多查询

UPDATE app_model SET column_a = %s WHERE id = %s
UPDATE app_model SET column_a = %s WHERE id = %s
UPDATE app_model SET column_a = %s WHERE id = %s
UPDATE app_model SET column_a = %s WHERE id = %s

这很容易在Django中表示:

for key, value in updates:
    Model.objects.filter(id=key).update(column_a=value)

一个带案例的查询

UPDATE app_model SET column_a = CASE
    WHEN id = %s THEN %s
    WHEN id = %s THEN %s
    WHEN id = %s THEN %s
    WHEN id = %s THEN %s
    ...
WHERE id IN (%s, %s, %s, %s, ...)

这应该更快,因为数据库可以更有效地找到所有行。查询最终将超长,我建议批量使用此方法(比如100或1000行,进行实验,看看会发生什么)。

在Django中,您可以via the ORM

执行此操作
Model.objects.filter(id__in=ids).update(
    column_a=Case(
        When(id=..., then=Value(...)),
        When(id=..., then=Value(...)),
        When(id=..., then=Value(...)),
        When(id=..., then=Value(...)),
        When(id=..., then=Value(...)),
        ...
    )
)

或通过使用更好的API执行django-bulk-update的第三方a similar thing包。

使用SELECT FROM

进行一次查询
  

注意:这是PostgreSQL特有的。其他数据库可能会提供其他类似的SQL扩展。

如果您可以制作包含要更新的所有data对的表(key, value),那么您就可以使用优雅的单一查询方法:

UPDATE app_model
SET column_a = data.value
FROM data
WHERE app_model.id = data.key;

如果更简单,您还应该能够替换子查询,而不是表格。

无论如何,我还没有找到使用Django ORM构建UPDATE FROM查询的方法,所以这需要在我能说的时候放弃原始SQL。