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 QuerySet以块方式处理数据库的最佳方法?_Django_Postgresql_Django Models_Database Optimization - Fatal编程技术网

使用Django QuerySet以块方式处理数据库的最佳方法?

使用Django QuerySet以块方式处理数据库的最佳方法?,django,postgresql,django-models,database-optimization,Django,Postgresql,Django Models,Database Optimization,我正在对数据库中的所有行运行批处理操作。这涉及到选择每一个模型并对其进行一些改进。把它分成几块,一块一块地做是有意义的 我目前正在使用Paginator,因为它很方便。这意味着我需要对值进行排序,以便可以按顺序分页。这确实会生成包含order和limit子句的SQL语句,对于每个块,我认为Postgres可能会对整个表进行排序,尽管我不能声称自己对内部结构有任何了解。我所知道的是,数据库大约有50%的CPU,我认为这太高了,不适合做选择 以RDMBS/CPU友好的方式迭代整个表的最佳方式是什么

我正在对数据库中的所有行运行批处理操作。这涉及到选择每一个模型并对其进行一些改进。把它分成几块,一块一块地做是有意义的

我目前正在使用Paginator,因为它很方便。这意味着我需要对值进行排序,以便可以按顺序分页。这确实会生成包含order和limit子句的SQL语句,对于每个块,我认为Postgres可能会对整个表进行排序,尽管我不能声称自己对内部结构有任何了解。我所知道的是,数据库大约有50%的CPU,我认为这太高了,不适合做选择

以RDMBS/CPU友好的方式迭代整个表的最佳方式是什么


假设数据库的内容在批处理操作期间没有更改。

根据您的描述,您实际上并不关心所处理行的排序顺序。如果您的表中有我期望的主键!,这种粗略的分区方法会快得多:

这对任何偏移执行相同的操作,对任何大小的表执行几乎相同的操作。 相应地检索主键和分区的最小值和最大值:

SELECT min(id), max(id) from tbl; -- then divide in suitable chunks
与之相反:

SELECT * FROM tbl ORDER BY id LIMIT 1000;
SELECT * FROM tbl ORDER BY id LIMIT 1000 OFFSET 1000;
...

这通常比较慢,因为所有的行都必须进行排序,而且随着偏移量的增加和表的增大,性能会进一步降低。

以下代码实现了Erwin在上面使用BETWEEN对Django查询集的回答:

对任意Django QuerySet执行此操作的实用程序函数如下所示。它默认假定“id”是用于between子句的合适字段

def chunked_querysetqs,批次大小,索引='id': 生成一个查询集,该查询集被拆分为最大大小为“batch_size”的批。 queryset上的任何排序都将被丢弃。 qs=qs.order_通过清晰排序 min_max=qs.aggregatemin=models.Minindex,max=models.Maxindex min_id,max_id=min_max['min'],min_max['max'] 对于范围为最小id、最大id+1的i,批次大小: filter_args={{0}\u range'.formatindex:i,i+批处理大小-1} 产量Q.过滤器**过滤器参数 它的用法如下:

对于chunked_querysetSomeModel.objects.all中的chunk,20: `chunk`是一个查询集 对于区块中的项目: `item`是一个SomeModel实例 通过 您还可以更改接口,这样就不需要额外的嵌套循环,但可以对chunked_querysetq中的项执行以下操作:

def chunked_querysetqs,批次大小,索引='id': 生成将成批评估的查询集 qs=qs.order_通过清晰排序 min_max=qs.aggregatemin=models.Minindex,max=models.Maxindex min_id,max_id=min_max['min'],min_max['max'] 对于范围为最小id、最大id+1的i,批次大小: filter_args={{0}\u range'.formatindex:i,i+批处理大小-1} 对于qs.filter**filter_参数中的项目: 收益项目
这假设记录以相同的顺序返回,没有sort子句。这是正确的吗?另外,如果我的元类中有一个默认的排序,我可以为查询删除它吗?@Joe:基本上你得到的是相同的记录,但没有排序。如果ID空间中存在间隙,则返回的记录数可能会少于每次调用的预期数。使用LIMIT/OFFSET时,除了每个表的最后一次调用之外,您可以获得固定数量的排序行。我不知道如何处理这个元类,但是您需要为LIMIT/OFFSET排序行。Erwin,我真的很抱歉我没有正确阅读您的答案。你确定这会更快吗?between子句肯定只能在ID已经排序或者每次都执行整个表扫描的情况下工作?@Joe:表中没有自然顺序。当然,如果行的物理顺序与索引匹配,这可能会加快操作,因为需要读取的块更少。您可能会感兴趣,但不会,如果id被索引,但仅当您读取的块是表的一小部分时,我的查询将导致索引扫描。查询计划器决定哪个更快:索引扫描还是顺序扫描。你自己去试试看。
SELECT * FROM tbl ORDER BY id LIMIT 1000;
SELECT * FROM tbl ORDER BY id LIMIT 1000 OFFSET 1000;
...