Django的性能优化实现解析
一 利用标准数据库优化技术
传统数据库优化技术博大精深,不同的数据库有不同的优化技巧,但重心还是有规则的。在这里算是题外话,挑两点通用的说说:
索引,给关键的字段添加索引,性能能更上一层楼,如给表的关联字段,搜索频率高的字段加上索引等。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)
以上就是本文的全部内容,希望对大家的学习有所帮助
您可能感兴趣的文章:
- 动态调整TLS record size优化性能原理及实现
- Tomcat8启用gzip压缩实现网页性能优化
- Android性能优化全方面解析
- Android性能优化—— Apk瘦身的实现
- Spark性能优化之通过YDB实现比原生Spark性能高100倍的多表关联
- [C++] 测试硬件popcnt(位1计数)指令与各种软件算法,利用模板实现静态多态优化性能
- 解析Tomcat性能优化N种方法
- Apache+Django性能优化之mod_wsgi篇
- 网站性能优化,使用velocity实现页面静态化,实现实时更新静态页面
- Android性能优化:Volley使用及其原理解析
- 解析MySQL数据库性能优化的六大技巧
- UBB解析优化的心得:Regex构造函数的性能
- 【安卓】MAT工具实现安卓性能的优化 更新中
- 性能优化:用FreeMarker实现页面静态化
- 【nginx网站性能优化篇(3)】反向代理实现负载均衡
- 提高PHP性能的编码技巧以及性能优化详细解析
- BP神经网络python简单实现2(性能优化)
- web前端性能优化——DNS预解析和浏览器并发连接数
- 秋色园QBlog技术原理解析:性能优化篇:打印页面SQL,全局的SQL语句优化(十三)
- Spark 重分区函数:coalesce和repartition区别与实现,可以优化Spark程序性能