背景

python项目中使用了peewee这款orm框架,在对数据库更新时有两种语法,分别是saveupdate方法。有同事说从peewee的日志来看,update比save更快,于是做了一个简单的比较实验,看看真实情况如何。

基础环境:

python: 3.8.10

peewee: 3.16.2

数据库:sqlite

准备

插入1w条数据

import datetime
from peewee import AutoField, DateTimeField, Model, SqliteDatabase, TextField, IntegerField class BaseModel(Model):
"""A base model that will use our Sqlite database."""
id = AutoField()
update_time = DateTimeField(default=datetime.datetime.now) class Meta:
database = db class User(BaseModel):
name = TextField()
age = IntegerField() class Meta:
table_name = "user" if __name__ == "__main__":
User.truncate_table()
db.connect()
db.create_tables([User]) data = []
for i in range(10000):
data.append({"name": f"person_P{i}", "age": i})
print(i) User.insert_many(data).execute()

update 更新

if __name__ == "__main__":
import logging
import time logger = logging.getLogger('peewee')
logger.propagate = False
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG) start = time.time()
for user in users:
User.update(age=6012).where(User.id==user.id).execute()
print(user.id, user.name, user.age)
end = time.time()
print(f"total: {end-start}")

peewee:日志

('UPDATE "user" SET "update_time" = ?, "name" = ?, "age" = ? WHERE ("user"."id" = ?)', [datetime.datetime(2023, 8, 29, 17, 30, 36, 719081), 'person_P9996', 12341, 10024])
('UPDATE "user" SET "update_time" = ?, "name" = ?, "age" = ? WHERE ("user"."id" = ?)', [datetime.datetime(2023, 8, 29, 17, 30, 36, 719088), 'person_P9997', 12341, 10025])
('UPDATE "user" SET "update_time" = ?, "name" = ?, "age" = ? WHERE ("user"."id" = ?)', [datetime.datetime(2023, 8, 29, 17, 30, 36, 719096), 'person_P9998', 12341, 10026])
('UPDATE "user" SET "update_time" = ?, "name" = ?, "age" = ? WHERE ("user"."id" = ?)', [datetime.datetime(2023, 8, 29, 17, 30, 36, 719103), 'person_P9999', 12341, 10027])

结果:67.96582674980164 s

save更新

if __name__ == "__main__":
import logging
import time logger = logging.getLogger('peewee')
logger.propagate = False
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG) start = time.time()
for user in users:
user.age = 12341
user.save()
print(user.id, user.name, user.age)
end = time.time()
print(f"total: {end-start}")

peewee日志:

('UPDATE "user" SET "age" = ? WHERE ("user"."id" = ?)', [2000, 10025])
10025 person_P9997 3000
('UPDATE "user" SET "age" = ? WHERE ("user"."id" = ?)', [2000, 10026])
10026 person_P9998 3000
('UPDATE "user" SET "age" = ? WHERE ("user"."id" = ?)', [2000, 10027])

结果:67.52418804168701 s

结果分析

从三个方面来分析:

  • 从打印的日志来看,save会更新记录全部字段,update只会更新指定的字段。
  • 从结果来看,1w行以内的更新操作两者没有性能的差别。
  • 从方法实现来看,update方法是底层方法,save方法调用了update方法或insert方法实现更新操作。

所以理论上来说updatesave 更底层,效率略高。实际使用中save写法较为方便,个人更喜欢save方法。

update 方法

    def __sql__(self, ctx):
super(Update, self).__sql__(ctx) with ctx.scope_values(subquery=True):
ctx.literal('UPDATE ') expressions = []
for k, v in sorted(self._update.items(), key=ctx.column_sort_key):
if not isinstance(v, Node):
if isinstance(k, Field):
v = k.to_value(v)
else:
v = Value(v, unpack=False)
elif isinstance(v, Model) and isinstance(k, ForeignKeyField):
# NB: we want to ensure that when passed a model instance
# in the context of a foreign-key, we apply the fk-specific
# adaptation of the model.
v = k.to_value(v) if not isinstance(v, Value):
v = qualify_names(v) expressions.append(NodeList((k, SQL('='), v))) (ctx
.sql(self.table)
.literal(' SET ')
.sql(CommaNodeList(expressions))) if self._from:
with ctx.scope_source(parentheses=False):
ctx.literal(' FROM ').sql(CommaNodeList(self._from)) if self._where:
with ctx.scope_normal():
ctx.literal(' WHERE ').sql(self._where)
self._apply_ordering(ctx)
return self.apply_returning(ctx)

update方法可以看到是拼接出一个sql语句,update xx set xx=xx where

save 方法

    def save(self, force_insert=False, only=None):
field_dict = self.__data__.copy()
if self._meta.primary_key is not False:
pk_field = self._meta.primary_key
pk_value = self._pk
else:
pk_field = pk_value = None
if only is not None:
field_dict = self._prune_fields(field_dict, only)
elif self._meta.only_save_dirty and not force_insert:
field_dict = self._prune_fields(field_dict, self.dirty_fields)
if not field_dict:
self._dirty.clear()
return False self._populate_unsaved_relations(field_dict)
rows = 1 if self._meta.auto_increment and pk_value is None:
field_dict.pop(pk_field.name, None) if pk_value is not None and not force_insert:
if self._meta.composite_key:
for pk_part_name in pk_field.field_names:
field_dict.pop(pk_part_name, None)
else:
field_dict.pop(pk_field.name, None)
if not field_dict:
raise ValueError('no data to save!')
rows = self.update(**field_dict).where(self._pk_expr()).execute()
elif pk_field is not None:
pk = self.insert(**field_dict).execute()
if pk is not None and (self._meta.auto_increment or
pk_value is None):
self._pk = pk
# Although we set the primary-key, do not mark it as dirty.
self._dirty.discard(pk_field.name)
else:
self.insert(**field_dict).execute() self._dirty -= set(field_dict) # Remove any fields we saved.
return rows

save方法是调用update方法或insert方法间接实现更新。

peewee update和save性能分析的更多相关文章

  1. Oracle Update 语句语法与性能分析 - 多表关联

    Oracle Update 语句语法与性能分析 - 多表关联   为了方便起见,建立了以下简单模型,和构造了部分测试数据: 在某个业务受理子系统BSS中, SQL 代码 --客户资料表 create ...

  2. Yolov4性能分析(上)

    Yolov4性能分析(上) 一.目录 实验测试 1) 测试介绍 2) Test 3) Train 二.   分析 1.实验测试 1. 1  实验测试方法 Yolov4训练train实验方法(Darkn ...

  3. SQL Server-聚焦INNER JOIN AND IN性能分析(十四)

    前言 本节我们来讲讲联接综合知识,我们在大多教程或理论书上都在讲用哪好,哪个性能不如哪个的性能,但是真正讲到问题的实质却不是太多,所以才有了本系列每一篇的篇幅不是太多,但是肯定是我用心去查找许多资料而 ...

  4. Java 性能分析工具 , 第 1 部分: 操作系统工具

    引言 性能分析的前提是将应用程序内部的运行状况以及应用运行环境的状况以一种可视化的方式更加直接的展现出来,如何来达到这种可视化的展示呢?我们需要配合使用操作系统中集成的程序监控工具和 Java 中内置 ...

  5. MYSQL索引结构原理、性能分析与优化

    [转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...

  6. 性能分析神器VisualVM

    VisualVM 是一款免费的,集成了多个 JDK 命令行工具的可视化工具,它能为您提供强大的分析能力,对 Java 应用程序做性能分析和调优.这些功能包括生成和分析海量数据.跟踪内存泄漏.监控垃圾回 ...

  7. MySQL性能分析及explain的使用

    MySQL性能分析及explain用法的知识 1.使用explain语句去查看分析结果 如explain select * from test1 where id=1;会出现:id  selectty ...

  8. WireShark网络性能分析

    最近生产上出现一个性能问题,表现为:行情延时5s左右.从log一路追查下去,发现是我们自己写的一个行情网关(部署在xx.xx.xx.132)<->第三方的中转网关(部署在xx.xx.xx. ...

  9. Linux性能分析工具的安装和使用

    转自:http://blog.chinaunix.net/uid-26488891-id-3118279.html Normal 0 7.8 磅 0 2 false false false EN-US ...

  10. 由浅入深探究mysql索引结构原理、性能分析与优化 转

    第一部分:基础知识 第二部分:MYISAM和INNODB索引结构 1. 简单介绍B-tree B+ tree树 2. MyisAM索引结构 3. Annode索引结构 4. MyisAM索引与Inno ...

随机推荐

  1. Senparc 基础库全面适配 .NET 8.0

    概要 Senparc 全家桶中的基础库已经全面适配 .NET 8.0,目前随着 .NET 8.0 的 RC 版本不断发布,对应的版本号也将同步进行更新,直到本月 Ignite 大会微软官方发布 .NE ...

  2. FPGA常用IP核

    前言: 芯片行业中的IP,一般称为IP(Intellectual Property)核,是具有知识产权核的集成电路芯核的总称.说白了就是厂家实现的具有特定功能工具,然后我们可以直接调用,就相当于是函数 ...

  3. 为什么 Django 后台管理系统那么“丑”?

    哈喽大家好,我是咸鱼 相信使用过 Django 的小伙伴都知道 Django 有一个默认的后台管理系统--Django Admin 它的 UI 很多年都没有发生过变化,现在看来显得有些"过时 ...

  4. ASM字节码操作类库(打开java语言世界通往字节码世界的大门)

    前言:授人以鱼不如授人以渔,应用asm的文章有很多,简单demo的也很多,那么ASM都具备哪些能力呢?如何去学习编写ASM代码呢?什么样的情景需要用到ASM呢?让我们带着这些问题阅读这篇文章吧. 这里 ...

  5. 3款高评价的.Net开发的WMS系统推荐

    本文简介 WMS仓库管理系统是一款专业的仓库管理系统,旨在帮助企业实现仓储管理的智能化.信息化和自动化.通过该系统,企业可以实现对仓库的进货.出货.库存等各个环节的全面把控,提高仓储管理水平,降低运营 ...

  6. Vue04-vue-router

    vue-router 目前前端流行的三大框架, 都有自己的路由实现: Angular:ngRouter React:ReactRouter Vue:vue-router Vue Router 是 Vu ...

  7. Stable Diffusion扩散模型

    人像生成模型 1.模型理论基础 扩散模型(Diffusion Model): 1.1 Diffusion Model 原理 首先,Denoise Model 需要一个起始的噪声图像作为输入.这个噪声图 ...

  8. 如何用excel制作图表?

    Excel是一个非常强大的电子表格软件,其中包含了很多绘制图表的功能.下面是一些基本步骤,可以帮助你用Excel制作图表: 打开Excel并输入数据.在Excel中,首先需要输入需要制作图表的数据.可 ...

  9. Fast ORM 读写分离功能使用方式

    Fast Framework 作者 Mr-zhong 代码改变世界.... 一.前言 Fast Framework 基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer O ...

  10. H5自适应

    一.设置html的font-size,使用rem作为单位 假设设计稿宽度750px,屏幕宽高750px, 1.1rem=屏幕宽度/设计稿宽度*100px,适合用px表示宽度 1rem=100px re ...