Gil*_*tes 7 python sql django orm bulk
业务:
我遇到了一个问题 - 当使用Django ORM处理大型数据集时,规范的方法是使用每个元素进行操作.但当然这种方式效率很低.所以我决定使用原始SQL.
实质:
我有一个基本代码,它形成SQL查询,更新表的行,并提交它:
from myapp import Model
from django.db import connection, transaction
COUNT = Model.objects.count()
MYDATA = produce_some_differentiated_data() #Creating individual value for each row
cursor = connection.cursor()
str = []
for i in xrange(1, COUNT):
str.append("UPDATE database.table\n"
"SET field_to_modify={}\n"
"WHERE primary_key_field={};\n".format(MYDATA, i))
str = ''.join(str)
cursor.execute(str)
transaction.commit_unless_managed() #This cause exception
Run Code Online (Sandbox Code Playgroud)
在最后一个声明中我得到了这个,即使SIZE它很小:
_mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now")
Run Code Online (Sandbox Code Playgroud)
也许Django不允许一次执行多个SQL查询?
ps在提交之前关闭游标有助于避免异常,但这是正确的吗?
我的期望:
我正在为批量操作寻找所有可能的可靠解决方案(最好是在Django内部).我不关心它是ORM还是原始SQL,我会支持上面粘贴的代码,如果我能避免错误的话.如果没有解决方案,至少,只是为了好奇,才能知道这个例外的原因.
除了答案我还学到了什么:
在Django 1.4中引入bulk_create了高效的多重INSERT操作
Django 1.4+对它的ORM中的批量操作有相当不错的支持,你应该看看你是否可以使用它 - 它是最便携的方式,也非常适合使用它.
它不仅允许更新所有对象中的字段的相同值(这是微不足道的),而且还允许基于其他字段更新字段值以及执行一些有限的计算.我不确定它是否符合您的需要(取决于"produce_some_differentiated_data"如何工作) - 您可以做的一些计算,其中一些可能不行.一些例子:
image_id_list = [1,5,6]
Image.objects.filter(image_id__in=image_id_list).
update(views_number=F('views_number') + 1)
Run Code Online (Sandbox Code Playgroud)
上面的例子将转换为SQL类似于:
UPDATE image SET views_number = views_number + 1 WHERE image_id IN (1,5,6);
Run Code Online (Sandbox Code Playgroud)
这是进行批量更新的最快方式 - 比运行多个查询更快.在单个SQL语句中运行多个查询并不能真正提高操作速度.改进它的方法是使像上面这样的单个查询同时在许多行上运行.您可以在update语句中构建相当复杂的公式,以便最好能够以这种方式表达"produce_some_differentiated_data"方法.即使不能直接完成,您也可以对模型进行一些修改并添加一些额外的字段来实现.如果经常执行这种批量操作,这可能会有所回报.
从Django的文档:
Django支持对F()对象使用加法,减法,乘法,除法和模运算,包括常量和其他F()对象.
更多关于它的信息:https: //docs.djangoproject.com/en/dev/topics/db/queries/#updating-multiple-objects-at-once
cursor.executemany(query, param_list)如果需要原始SQL,请使用.
param_list = [("something_1", 1), ("something_2", 2),...]
# or everything like [(some_number_1, 1)...]. Apostrophes around the substituted
# "%s" and the complete necessary escaping is added automatically for string
# parameters.
cursor.executemany("""UPDATE database.table
SET field_to_modify=%s
WHERE primary_key_field=%s""",
param_list)
Run Code Online (Sandbox Code Playgroud)
它有很多优点:
这是虽然这两种方法的方法无证execute(self, sql, params=())和executemany(self, sql, param_list)自Django的0.96由所有天然分贝后端(MySQL和postgesql_psycopg2,sqlite3的,Oracle)的长时间都支持光标对象到当前1.5-β.一个有用的类似答案是/sf/answers/427107551/.
executemany方法有两个与前几年异常处理相关的固定问题.因此,如果您故意导致数据库异常,太多%s或太少等等,请验证您的Django版本是否会收到有用的错误消息.然而,几分钟的初始修补/测试比等待慢速方法的许多小时要快.
| 归档时间: |
|
| 查看次数: |
4816 次 |
| 最近记录: |