Django的性能优化实现解析


Posted in Python onJuly 30, 2019

一 利用标准数据库优化技术

传统数据库优化技术博大精深,不同的数据库有不同的优化技巧,但重心还是有规则的。在这里算是题外话,挑两点通用的说说:

索引,给关键的字段添加索引,性能能更上一层楼,如给表的关联字段,搜索频率高的字段加上索引等。Django建立实体的时候,支持给字段添加索引,具体参考Django.db.models.Field.db_index。按照经验,Django建立实体之前应该早想好表的结构,尽量想到后面的扩展性,避免后面的表的结构变得面目全非。

使用适当字段类型,本来varchar就搞定的字段,就别要text类型,小细节别不关紧要,后头数据量一上去,愈来愈多的数据,小字段很可能是大问题。

二 了解Django的QuerySets

了解Django的QuerySets对象,对优化简单程序有至关重要的作用。QuerySets是有缓存的,一旦取出来,它就会在内存里呆上一段时间,尽量重用它。

# 了解缓存属性:
>>> entry = Entry.objects.get(id=1)
>>> entry.blog  # 博客实体第一次取出,是要访问数据库的
>>> entry.blog  # 第二次再用,那它就是缓存里的实体了,不再访问数据库
>>> entry = Entry.objects.get(id=1)
>>> entry.authors.all()  # 第一次all函数会查询数据库
>>> entry.authors.all()  # 第二次all函数还会查询数据库

all,count exists是调用函数(需要连接数据库处理结果的),注意在模板template里的代码,模板里不允许括号,但如果使用此类的调用函数,一样去连接数据库的,能用缓存的数据就别连接到数据库去处理结果。还要注意的是,自定义的实体属性,如果调用函数的,记得自己加上缓存策略。

利用好模板的with标签:

模板中多次使用的变量,要用with标签,把它看成变量的缓存行为吧。

使用QuerySets的iterator():

通常QuerySets先调用iterator再缓存起来,当获取大量的实体列表而仅使用一次时,缓存行为会耗费宝贵的内存,这时iterator()能帮到你,iterator()只调用iterator而省 去了缓存步骤,显著减少内存占用率,具体参考相关文档。

三 数据库的工作就交给数据库本身计算,别用Python处理

  • 使用 filter and exclude 过滤不需要的记录,这两个是最常用语句,相当是SQL的where
  • 同一实体里使用F()表达式过滤其他字段
  • 使用annotate对数据库做聚合运算

不要用python语言对以上类型数据过滤筛选,同样的结果,python处理复杂度要高,而且效率不高, 白白浪费内存

  • 使用QuerySet.extra() extra虽然扩展性不太好,但功能很强大,如果实体里需要需要增加额外属性,不得已时,通过extra来实现,也是个好办法
  • 使用原生的SQL语句 如果发现Django的ORM已经实现不了你的需求,而extra也无济于事的时候,那就用原生SQL语句

四 如果需要就一次性取出你所需要的数据

单一动作(如:同一个页面)需要多次连接数据库时,最好一次性取出所有需要的数据,减少连接数据库次数。

此类需求推荐使用QuerySet.select_related() (主动连表)和 prefetch_related()(被动连表)

相反,别取出你不需要的东西,模版templates里往往只需要实体的某几个字段而不是全部,这时QuerySet.values() 和 values_list(),对你有用,它们只取你需要的字段,返回字典dict和列表list类型的东西,在模版里够用即可,这可减少内存损耗,提高性能

同样QuerySet.defer()和only()对提高性能也有很大的帮助,一个实体里可能有不少的字段,有些字段包含很多元数据,比如博客的正文,很多字符组成,Django获取实体时(取出实体过程中会进行一些python类型转换工作),我们可以延迟大量元数据字段的处理,只处理需要的关键字段,这时QuerySet.defer()就派上用场了,在函数里传入需要延时处理的字段即可;而only()和defer()是相反功能

使用QuerySet.count()代替len(queryset),虽然这两个处理得出的结果是一样的,但前者性能优秀很多。同理判断记录存在时,QuerySet.exists()比if queryset实在强得太多了

五 懂减少数据库的连接数

使用 QuerySet.update() 和 delete(),这两个函数是能批处理多条记录的,适当使用它们事半功倍;如果可以,别一条条数据去update delete处理。

对于一次性取出来的关联记录,获取外键的时候,直接取关联表的属性,而不是取关联属性,如:

entry.blog.id
优于
entry.blog__id


# 善于使用批量插入记录,如:
Entry.objects.bulk_create([
  Entry(headline="Python 3.0 Released"),
  Entry(headline="Python 3.1 Planned")
])
优于
Entry.objects.create(headline="Python 3.0 Released")
Entry.objects.create(headline="Python 3.1 Planned")
# 前者只连接一次数据库,而后者连接两次


# 还有相似的动作需要注意的,如:多对多的关系,
my_band.members.add(me, my_friend)
优于
my_band.members.add(me)
my_band.members.add(my_friend)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python使用内存zipfile对象在内存中打包文件示例
Apr 30 Python
Pyhthon中使用compileall模块编译源文件为pyc文件
Apr 28 Python
Python使用reportlab将目录下所有的文本文件打印成pdf的方法
May 20 Python
编写Python脚本抓取网络小说来制作自己的阅读器
Aug 20 Python
python基于http下载视频或音频
Jun 20 Python
Python中xml和json格式相互转换操作示例
Dec 05 Python
python画双y轴图像的示例代码
Jul 07 Python
flask框架url与重定向操作实例详解
Jan 25 Python
python的列表List求均值和中位数实例
Mar 03 Python
使用pycharm和pylint检查python代码规范操作
Jun 09 Python
Python Mock模块原理及使用方法详解
Jul 07 Python
Pytorch distributed 多卡并行载入模型操作
Jun 05 Python
Python爬虫学习之获取指定网页源码
Jul 30 #Python
django-初始配置(纯手写)详解
Jul 30 #Python
django 单表操作实例详解
Jul 30 #Python
Apache部署Django项目图文详解
Jul 30 #Python
Python 使用list和tuple+条件判断详解
Jul 30 #Python
用python wxpy管理微信公众号并利用微信获取自己的开源数据
Jul 30 #Python
Python实现二叉搜索树BST的方法示例
Jul 30 #Python
You might like
php遍历所有文件及文件夹的方法深入解析
2013/06/08 PHP
UTF-8正则表达式如何匹配汉字
2015/08/03 PHP
[企业公众号]升级到[企业微信]之后发送消息失败的解决方法
2017/06/30 PHP
基于ThinkPHP5.0实现图片上传插件
2017/09/25 PHP
ASP中用Join和Array,可以加快字符连接速度的代码
2007/08/22 Javascript
javascript闭包的理解和实例
2010/08/12 Javascript
jQuery EasyUI API 中文文档 - Documentation 文档
2011/09/29 Javascript
javascript获取下拉列表框当中的文本值示例代码
2013/07/31 Javascript
JS实现切换标签页效果实例代码
2013/11/01 Javascript
浅析return false的正确使用
2013/11/04 Javascript
jquery 中的each()跳出循环的语句
2014/05/23 Javascript
js中将String转换为number以便比较
2014/07/08 Javascript
举例详解JavaScript中Promise的使用
2015/06/24 Javascript
Windows 系统下设置Nodejs NPM全局路径
2016/04/26 NodeJs
不使用script导入js文件的几种方法
2016/10/27 Javascript
微信小程序开发之好友列表字母列表跳转对应位置
2017/09/26 Javascript
vue的mixins属性详解
2018/03/14 Javascript
详解Vue文档中几个易忽视部分的剖析
2018/03/24 Javascript
vue实现自定义多选与单选的答题功能
2018/07/05 Javascript
AngularJS自定义表单验证功能实例详解
2018/08/24 Javascript
Electron-vue开发的客户端支付收款工具的实现
2019/05/24 Javascript
Python编程实现的简单神经网络算法示例
2018/01/26 Python
Python 加密与解密小结
2018/12/06 Python
Python3.5面向对象与继承图文实例详解
2019/04/24 Python
Python实现的企业粉丝抽奖功能示例
2019/07/26 Python
Python检查 云备份进程是否正常运行代码实例
2019/08/22 Python
Python获取当前脚本文件夹(Script)的绝对路径方法代码
2019/08/27 Python
python 使用while写猜年龄小游戏过程解析
2019/10/07 Python
Pandas时间序列:重采样及频率转换方式
2019/12/26 Python
python查找特定名称文件并按序号、文件名分行打印输出的方法
2020/04/24 Python
filter使用python3代码进行迭代元素的实例详解
2020/12/03 Python
摄影实习自我鉴定
2013/09/20 职场文书
教师反腐倡廉演讲稿
2014/09/03 职场文书
幼儿教师自我剖析材料
2014/09/29 职场文书
2015年“七七卢沟桥事变”纪念活动总结
2015/03/24 职场文书
在redisCluster中模糊获取key方式
2021/07/09 Redis