Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django Postgres迁移:在一个有1亿行的表中回填列的最快方法_Django_Postgresql_Large Data_Bulkupdate - Fatal编程技术网

Django Postgres迁移:在一个有1亿行的表中回填列的最快方法

Django Postgres迁移:在一个有1亿行的表中回填列的最快方法,django,postgresql,large-data,bulkupdate,Django,Postgresql,Large Data,Bulkupdate,我在Postgres中有一个表,它有1亿行 我有一个随时间填充的列,其中存储了一些键。密钥在存储之前已加上前缀。我们称之为前缀键 我的任务是使用此列的值填充另一列,该列具有相同的值,但前缀已被删除。让我们称之为简单的按键 我尝试了以下迁移: from django.db import migrations import time def backfill_simple_keys(apps, schema_editor): Thing = apps.get_model('thing',

我在Postgres中有一个表,它有1亿行

我有一个随时间填充的列,其中存储了一些键。密钥在存储之前已加上前缀。我们称之为前缀键

我的任务是使用此列的值填充另一列,该列具有相同的值,但前缀已被删除。让我们称之为简单的按键

我尝试了以下迁移:

from django.db import migrations
import time


def backfill_simple_keys(apps, schema_editor):
    Thing = apps.get_model('thing', 'Thing')

    batch_size = 100000
    number_of_batches_completed = 0
    while Thing.objects.filter(simple_key__isnull=True).exists():
        things = Thing.objects.filter(simple_key__isnull=True)[:batch_size]
        for tng in things:
            prefixed_key = tng.prefixed_key
            if prefixed_key.startswith("prefix_A"):
                simple_key = prefixed_key[len("prefix_A"):]
            elif prefixed_key.startswith("prefix_BBB"):
                simple_key = prefixed_key[len("prefix_BBB"):]
            tng.simple_key = simple_key
        Thing.objects.bulk_update(
            things,
            ['simple_key'],
            batch_size=batch_size
        )
        number_of_batches_completed += 1
        print("Number of batches updated: ", number_of_batches_completed)
        sleep_seconds = 3
        time.sleep(sleep_seconds)

class Migration(migrations.Migration):

    dependencies = [
        ('thing', '0030_add_index_to_simple_key'),
    ]

    operations = [
         migrations.RunPython(
            backfill_simple_keys,
        ),
    ]
每批大约需要7分钟才能完成。这意味着需要几天才能完成!
它还增加了在生产中使用的数据库的延迟。

因为您无论如何都要遍历该表中的每条记录,所以使用服务器端游标一次性遍历它是有意义的。 使命感 Thing.objects.filtersimple\u key\u isnull=True[:批处理大小] 这将是昂贵的,尤其是随着指数开始增长。 此外,上面的调用从该表中检索所有字段,即使您只打算使用2-3个字段

update\u query=update table SET simple\u key=data.key 从作为数据id的值%s开始,键入其中的table.id=data.id conn=psycopg2.connectDSN,游标\工厂=RealDictCursor cursor=conn.cursorname=key\u server\u side\u有名称的crs使其成为SSC 更新\u cursor=conn.cursor常规光标 cursor.itersize=5000一次要检索多少条记录 cursor.executeSELECT id,带前缀的\u键,表中的简单\u键 计数=0 批次=[] 对于光标中的行: 如果不是行[简单_键]: 简单密钥=计算简单密钥行[前缀密钥] batch.append[行[id],简单\u键] 如果lenbatch>=1000,一次更新多少条记录 执行\u valuesupdate\u游标,更新\u查询,批处理,页面大小=1000 批次=[] 时间。睡眠0.1允许分贝呼吸 计数+=1 如果计数%100000==0:每100K行打印一次进度 打印已处理%d行,计数 以上内容未经测试,因此建议先创建数百万行表的副本,并对其进行测试。
您还可以测试用于检索和更新的各种批量大小设置。

我没有尝试这种方法,因为我认为这种方法仍然与批量设置值相同。允许DB呼吸此评论建议。我很感谢您的回复,但我们的系统正在生产中,流量不断,因此我们不能允许db的延迟下降,只能在非高峰时间小幅下降几个小时