Django bulk_create()、update()与数据库事务的效率对比分析


Posted in Python onMay 15, 2020

下面以创建10000个对象为例进行测试:

# 用for循环挨个创建,共花费37秒
  for i in range(10000):
    name="String number %s"%i
    Record.objects.create(name=name)
 
# 用django事务只提交一次,共花费2.65秒
@transaction.commit_manually
def manual_transaction():
  for i in range(10000):
    name="String number %s"%i
    Record.objects.create(name=name)
  transaction.commit()
 
# 用bulk_create创建,共花费0.47秒
def builtin():
  insert_list =[]
  for i in range(10000):
    name="String number %s"%i
    insert_list.append(Record(name=name))
  Record.objects.bulk_create(insert_list)
 
# 用for循环挨个更新,共花费72秒:
def auto_transaction():
  for record inRecord.objects.all():
    record.name ="String without number"
    record.save()
 
# 用django事务只提交一次,共花费17秒
@transaction.commit_manually
def manual_transaction():
  for record inRecord.objects.all():
    record.name ="String without number"
    record.save()
  transaction.commit()
 
# 用update更新,共花费0.33秒
def builtin():
  Record.objects.all().update(name="String without number")

补充知识:django的model使用上容易遇到的坑,default=datetime.now和auto_now、null和blank、save和update、bulk_create

一、django设置字段动态默认时间的四种方式:

from django.db import models
from datetime import datetime

class User(models.Model):
  id = models.BigAutoField('主键', primary_key=True)
 
  name = models.CharField('名字', max_length=20, db_index=True, default='')
 
  create_time_one = models.DateTimeField('创建时间', default=datetime.now())
  update_time_one = models.DateTimeField('更新时间', default=datetime.now)
 
  create_time_tow = models.DateTimeField('创建时间', auto_now_add=True)
  update_time_tow = models.DateTimeField('更新时间', auto_now=True)

1. default=datetime.now()

model每次初始化,都会自动设置该字段的默认值为初始化时间。

2. default=datetime.now

model每次进行新增或修改操作,都会自动设置该字段的值为操作时间。设置后仍可以使用ORM手动修改该字段。

3. auto_now_add=True

默认值为False,若设置为True,model每次进行新增操作,都会自动设置该字段的值为操作时间。设置为True后无法使用ORM手动修改该字段,哪怕填充了字段的值也会被覆盖。

4. auto_now=True

默认值为False,若设置为True,model每次进行新增或修改操作,都会自动设置该字段的值为操作时间。设置为True后无法使用ORM手动修改该字段,哪怕填充了字段的值也会被覆盖。

5. 要注意的点

除非想设置动态默认时间为项目的启动时间,否则default=datetime.now()这种用法是错误的,会得到期望之外的结果。

使用User.objects.update方法时,设置的default=datetime.now和auto_now=True都不会生效,由于设置了auto_now=True的字段不能手动修改,此时只能使用save方法修改数据,这对于多个数据的更新是不友好的。

因此如果设置动态默认时间的字段,应该使用default=datetime.now和auto_now_add=True来实现。

二、null=True和blank=True的区别

1. null针对数据库,如果null=True,表示数据库的该字段可以为空。

2. blank针对表单的,如果blank=True,表示表单填写该字段时可以不填。

mysql中空值不占用空间,NULL占用空间,而且使用NULL会使索引的效率下降。因此从性能上来说,不建议使用null=True,最好使用default=''。

三、save和build_create的区别

1. 使用save方法:

names = ['张三', '李四']
for name in names:
  user = User(name=name)
  user.save()
  print(user.id) # 此时user对象有id的值

2. 使用bulk_create方法:

names = ['张三', '李四']
users = [User(name=name) for name in names]
users = User.objects.bulk_create(users)
print([user.id for user in users]) # 此时user对象没有id的值

bulk_create的优点:

批量操作时只与数据库进行一次交互,效率高。

bulk_create的缺点:

对于设置了自增的字段,返回值中不会有该字段的值,如上例2中的user对象。

对于设置了动态默认时间的字段,如设置了auto_now=True,同一批处理的记录中该字段的时间将会相同。

四、上面的知识点使用的例子

1. 定义模型

from django.db import models
from datetime import datetime
 
class User(models.Model):
  id = models.BigAutoField('主键', primary_key=True)
  name = models.CharField('名字', max_length=20, db_index=True, blank=False, default='')
  create_time = models.DateTimeField('创建时间', auto_now_add=True)
  update_time = models.DateTimeField('更新时间', default=datetime.now)

2. 插入数据

# 方法一
names = ['张三', '李四']
users = [User(name=name) for name in names]
users = User.objects.bulk_create(users)
 
# 方法二
names = ['张三', '李四']
users = [User(name=name) for name in names]
[user.save() for user in users]

3. 修改数据

# 方法一
names = ['张三', '李四']
User.objects.filter(name__in=names).update(name='changed', update_time=datetime.now()) # 这里必须显式对update_time赋值
 
# 方法二
names = ['张三', '李四']
users = User.objects.filter(name__in=names)
for use in users:
  user.name = 'changed'
  user.save() # 这里会自动更新update_time,但是多次save效率低

以上这篇Django bulk_create()、update()与数据库事务的效率对比分析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 命令行参数sys.argv
Sep 06 Python
详细介绍Python语言中的按位运算符
Nov 26 Python
python教程之用py2exe将PY文件转成EXE文件
Jun 12 Python
Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计
Jul 04 Python
不要用强制方法杀掉python线程
Feb 26 Python
Python 通过URL打开图片实例详解
Jun 01 Python
深入理解Python爬虫代理池服务
Feb 28 Python
对Python的zip函数妙用,旋转矩阵详解
Dec 13 Python
python实现字符串加密成纯数字
Mar 19 Python
详解Python 定时框架 Apscheduler原理及安装过程
Jun 14 Python
Tensorflow:转置函数 transpose的使用详解
Feb 11 Python
python3中apply函数和lambda函数的使用详解
Feb 28 Python
Python实现aes加密解密多种方法解析
May 15 #Python
django 数据库 get_or_create函数返回值是tuple的问题
May 15 #Python
重写django的model下的objects模型管理器方式
May 15 #Python
Python基于pip实现离线打包过程详解
May 15 #Python
Django在Model保存前记录日志实例
May 14 #Python
django 连接数据库出现1045错误的解决方式
May 14 #Python
Django ORM filter() 的运用详解
May 14 #Python
You might like
php中实现记住密码自动登录的代码
2011/03/02 PHP
php去除重复字的实现代码
2011/09/16 PHP
在windows服务器开启php的gd库phpinfo中未发现
2013/01/13 PHP
IIS6.0中配置php服务全过程解析
2013/08/07 PHP
PHP中的流(streams)浅析
2015/07/02 PHP
修复ShopNC使用QQ 互联时提示100010 错误
2015/11/08 PHP
Symfony2实现在controller中获取url的方法
2016/03/18 PHP
PHP Callable强制指定回调类型的方法
2016/08/30 PHP
Centos 6.5下PHP 5.3安装ffmpeg扩展的步骤详解
2017/03/02 PHP
为何说PHP引用是个坑,要慎用
2018/04/02 PHP
iframe的onload在Chrome/Opera中执行两次Bug的解决方法
2011/03/17 Javascript
js带点自动图片轮播幻灯片特效代码分享
2015/09/07 Javascript
JavaScript中的原始值和复杂值
2016/01/07 Javascript
JavaScript实现弹出DIV层同时页面背景渐变成半透明效果
2016/03/25 Javascript
jQuery ajax中使用confirm,确认是否删除的简单实例
2016/06/17 Javascript
Input文本框随着输入内容多少自动延伸的实现
2017/02/15 Javascript
Vue下路由History模式打包后页面空白的解决方法
2018/06/29 Javascript
JS通过位运算实现权限加解密
2018/08/14 Javascript
vue单页缓存方案分析及实现
2018/09/25 Javascript
vue项目中使用bpmn为节点添加颜色的方法
2020/04/30 Javascript
微信小程序实现点赞业务
2021/02/10 Javascript
Python中利用Scipy包的SIFT方法进行图片识别的实例教程
2016/06/03 Python
Windows下的Jupyter Notebook 安装与自定义启动(图文详解)
2018/02/21 Python
python实现简单的单变量线性回归方法
2018/11/08 Python
python调用c++返回带成员指针的类指针实例
2019/12/12 Python
HTML+CSS3+JS 实现的下拉菜单
2020/11/25 HTML / CSS
台湾森森购物网:U-mall
2017/10/16 全球购物
Hotels.com越南:酒店预订
2019/10/29 全球购物
个人找工作求职简历的自我评价
2013/10/20 职场文书
仓库保管员岗位职责
2013/12/20 职场文书
文艺晚会主持词
2014/03/24 职场文书
《称象》教学反思
2014/04/25 职场文书
Vue详细的入门笔记
2021/05/10 Vue.js
彻底解决MySQL使用中文乱码的方法
2022/01/22 MySQL
优化Mysql查询的示例
2022/04/26 MySQL
利用Java连接Hadoop进行编程
2022/06/28 Java/Android