Django数据层提供各种途径优化数据的访问,一个项目大量优化工作一般是放在后期来做,早期的优化是“万恶之源”,这是前人总结的经验,不无道理。如果事先理解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处理:

1 使用 filter and exclude 过滤不需要的记录,这两个是最常用语句,相当是SQL的where。

2 同一实体里使用F()表达式过滤其他字段。

3 使用annotate对数据库做聚合运算。

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

使用QuerySet.extra():
extra虽然扩展性不太好,但功能很强大,如果实体里需要需要增加额外属性,不得已时,通过extra来实现,也是个好办法。

使用原生的SQL语句:
如果发现Django的ORM已经实现不了你的需求,而extra也无济于事的时候,那就用原生SQL语句吧,用Djangoango.db.connection.queries去实现你需要的东西。

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

单一动作(如:同一个页面)需要多次连接数据库时,最好一次性取出所有需要的数据,减少连接数据库次数。此类需求推荐使用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实在强得太多了。

当然一样的结果,在缓存里已经存在,就别滥用count(),exists(),all()函数了。

五 懂减少数据库的连接数:

使用 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)

此文原链接:http://my.oschina.net/012345678/blog/162436

Django 数据库查询优化的更多相关文章

  1. Django数据库查询优化与AJAX

    目录 数据库设计三大范式 orm相关的数据库查询优化 惰性查询 all.only与defer select_related与prefetch_related MTV与MVC模型 MTV(models ...

  2. Django数据库查询优化-事务-图书管理系统的搭建

    数据库查询优化 优化:虽然减轻了数据库的压力,但查询速度大大的减慢 ORM内所有的语句操作,默认都是惰性查询,只有你在真正的需要数据的时候才会走数据, 如果你只是写ORM语句时,是不会走数据库的,这样 ...

  3. Django常用字段及参数、事务、数据库查询优化

    常用字段 注意: Django中没有设置对应char类型的字段,但可以支持自己定义. 自定义对应于数据库的char类型字段: from django.db.models import Field cl ...

  4. ORM中聚合函数、分组查询、Django开启事务、ORM中常用字段及参数、数据库查询优化

    聚合函数 名称 作用 Max() 最大值 Min() 最小值 Sum() 求和 Count() 计数 Avg() 平均值 关键字: aggregate 聚合查询通常都是配合分组一起使用的 关于数据库的 ...

  5. Python之路【第十九章】:Django 数据库对象关系映射

    Django ORM基本配置 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去 ...

  6. 数据库查询优化器的艺术:原理解析与SQL性能优化

    数据库查询优化器的艺术 作者:李海翔 Oracle公司MySQL全球开发团队.资深专家 简单的浏览了一遍,由于以前没有接触过SQL优化这些知识,读起来还是非常吃力的,不过收获还是很大的. 作者通过对M ...

  7. 从命令行运行django数据库操作

    从命令行运行django数据库操作,报错: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_T ...

  8. Django数据库操作(增删改查)

    Django数据库操作(增删改查) 创建数据库中的一个表 class Business(models.Model): #自动创建ID列 caption = models.CharField(max_l ...

  9. Django数据库操作性能相关

    Django数据库操作性能相关 案例: 现在我们的数据库中有两张表如下: 1.职员表: class UserInfo(models.Model): name = models.CharField(ma ...

随机推荐

  1. Android5.0之CoordinatorLayout的使用

    CoordinatorLayout,中文译作协调者布局,光听这名字你可能很难判断出协调者布局有什么特点,那么我们来看看下面一张图片: 由于CSDN对图片大小的要求,我只能录制一个快速播放的动画,请大家 ...

  2. Winedt10 添加自定义宏

    Winedt10 添加自定义功能,并在toolbar上添加快捷命令 功能描述: 用宏实现latex+bib参考文献的一键编译. Remark: The toolbar is the most visi ...

  3. Java并发——线程安全、线程同步、线程通信

    线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...

  4. C++学习(五)

    一.拷贝构造函数和拷贝赋值运算符1.拷贝构造:用一个已有的对象,构造和它同类型的副本对象——克隆.2.形如class X {  X (const X& that) { ... }};的构造函数 ...

  5. 通过js实时检测文本框内容

    思路 1,在获取文本框焦点后,启动定时器,每隔100毫秒来查看文本内容的改变 2,在文本框失去焦点后,清除定时器 下面是一个简单的例子 <!DOCTYPE html> <html&g ...

  6. android实现倒计时

    前言  在打开爱奇艺等app的欢迎界面的时候,右上角有一个倒计时的控件.倒计时完了以后进入主界面.现在我们来实现这个功能. 方法一 利用java的类Timer,TimerTask还有android的H ...

  7. Java_Iterator-------迭代器配合Listarray使用,具有更多的功能(转载)

    转载自:http://www.cnblogs.com/amboyna/archive/2007/09/25/904804.html 迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可 ...

  8. ASP.NET页面生命周期总结(2)

    HttpAplicationFactory获取一个HttpApplication对象: 内部:1.如果是第一次请求过来,那么就把global文件编译成一个类型.(后续请求来的,就可以直接获取这个类型) ...

  9. Cookie / Session / URL重写

    Cookie //创建一个Cookie对象 Cookie cookie = new Cookie("username","JACK"); //在客户端存储的时间 ...

  10. redis基本数据类型【2】-Hash类型

    一.概述 1.散列是一种典型的字典结构,filed和value的映射,但value只能存储字符串,不支持其他类型 2.一个散列类型最多包含 2^32 -1个字段 3.散列适合存储对象:使用对象和ID构 ...