wordpress哪个版本 最快,怎样优化网站自然排名,济南网上房地产,哈尔滨工程信息网前言
对于网站和Web APP来说#xff0c;相同的类型的产品#xff0c;响应速度越好#xff0c;那么用户量就越高。不可否认的是#xff0c;响应速度是用户黏粘性最好的方式之一#xff0c;但往往不知道如何下手解决#xff0c;希望这篇文章可以给予你一些思路 对于网站和…前言
对于网站和Web APP来说相同的类型的产品响应速度越好那么用户量就越高。不可否认的是响应速度是用户黏粘性最好的方式之一但往往不知道如何下手解决希望这篇文章可以给予你一些思路 对于网站和Web APP来说最影响网站性能的就是数据库查询了因为而查询返回的数据集非常大时还会占据很多内存。这里从django orm的角度来探索数据库查询的优化
一、依据减少缓存的角度优化利用QuerySet惰性
网站和Web APP对于数据的常规处理方式肯定是数据库存储查询反复从数据库读写数据很耗时间和计算资源。也因此开发者们设计制作出了多个数据库连接方式其中在Django框架中ORM(语法有哪些)占很大比重。通过它可以使用filter, exclude, get等方法进行数据库查询从数据库中查询出来的结果一般是一个集合这个集合叫就做 QuerySet。QuerySet是惰性的QuerySet自带缓存
注Object Relational Mapping即对象关系映射是在pymysq之上又进行了一层封装对于数据的操作我们无需再去编写原生sql取代代之的是基于面向对象的思想去编写类、对象、调用相应的方法等ORM会将其转换/映射成原生SQL然后交给pymysql执行
惰性即为当被执行(print、if、len)时才会进行数据库查询这样做的目的是防止无效数据库操作。减少数据库交互
# 惰性查询如果只是书写了orm语句在后面根本没有用到该语句所查询出来的参数那么orm会自动识别出来直接不执行。# 举例res models.Book.objects.all() # 这时orm是不会走数据库的print(res) # 只有当要用到的上述orm语句的结果时才回去数据库查询。
QuerySet被执行后其查询结果会载入内存并保存在QuerySet内置的cache中。再次使用就不需要重新去查询了。减少缓存如果查出的 QuerySet只用一次可以使用 iterator() 去来防止占用太多的内存if与exists()都可以判断查询结果是否存在但两者使用却又很大的不相同。if会触发整个queryset的缓存而exists()只会返回True或False检视查询结果是否存在而不会缓存查询结果len()与count()方法均能统计查询结果数量。count()是从数据库层面直接获取查询结果数量而不需要返回整个queryset数据集一般来说会更快。len()会导致queryset的执行需要先将整个数据集载入内存方可计算但如果queryset数据集已经缓存在内存当中了len()则会更快当查询到的queryset非常大时会占用大量的内存使用values和values_list按需提取数据(1个或个别多字段而非全字段)。values和values_list返回的是字典形式字符串数据而不是对象集合only(A)包含与查A走一次数据库查B走多次数据库。defer(A)不包含与,查A走多次数据库查B走一次数据库相比于使用save()方法update()不需要先缓存整个querysetaggregate和annotate方法主要用于组合查询我们使用aggregate完成对查询集(queryset)的某些字段进行计算使用annotate进行分组并追加统计字段,如
class Student(models.Model):name models.CharField(max_length20)age models.IntegerField()hobbies models.ManyToManyField(Hobby)class Hobby(models.Model):name models.CharField(max_length20)from django.db.models import Max, Min, Avg, Sum, Count
#####################aggregate应用###############################
# 学生平均年龄, 自定义key
Student.objects.aggregate(average_age Avg(age)) # { average_age: 12 }# 同时获取学生年龄均值, 最大值和最小值, 返回字典
Student.objects.aggregate(Avg(age‘), Max(age‘), Min(age‘))
# { age__avg: 12, age__max: 18, age__min: 6, }# 根据Hobby反查学生最大年龄。查询字段student和age间有双下划线
Hobby.objects.aggregate(Max(student__age)) # { student__age__max: 12 }#####################annotate应用###############################
# 按学生分组统计每个学生爱好数量并自定义key
Student.objects.annotate(hobby_count_by_studentCount(hobbies))# 按爱好分组再统计每组学生最大年龄
Hobby.objects.annotate(Max(student__age))#####################annotatefilter应用###############################
# 先按爱好分组再统计每组学生数量, 然后筛选出学生数量大于1的爱好。
Hobby.objects.annotate(student_numCount(student)).filter(student_num__gt1)# 先按爱好分组筛选出以d开头的爱好再统计每组学生数量。
Hobby.objects.filter(name__startswithd).annotate(student_numCount(student‘))#####################annotateorder_by应用###############################
# 先按爱好分组再统计每组学生数量, 然后按每组学生数量大小对爱好排序。
Hobby.objects.annotate(student_numCount(student‘)).order_by(student_num)# 统计最受学生欢迎的5个爱好。
Hobby.objects.annotate(student_numCount(student‘)).order_by(-student_num)[:5]#####################annotatevalues应用###############################
# 按学生名字分组统计每个学生的爱好数量。
Student.objects.values(name).annotate(Count(hobbies))你还可以使用values方法从annotate返回的数据集里提取你所需要的字段如下所示:
# 按学生名字分组统计每个学生的爱好数量。
Student.objects.annotate(hobby_countCount(hobbies)).values(name, hobby_count)select_relatedprefetch_related使用
假设现在有文章表(Article)、类别表(Category)、标签表(Tag)。它们关系是文章与类别是一对多关系文章与标签是多对多关系 常规写法错倒是没错。然而使用Article.objects.all()查询得到的只是Article表的数据并没有包含Category表和Tag表的数据。因此每一次打印article.category.name和tag.name都会重新去查询一遍Category表和Tag表造成了很大不必要的浪费
# 查询类别、标签信息
articles Article.objects.all()
for article in articles:print(article.title)print(article.category.name)for tag in article.tags.all():print(tag.name)标准写法select_related可查询一对多、一对一的关系不可以多对多关系。处理的方式是inner join连表。实现打印类别是无需再去查数据库因为数据已经一次性获取出来了
# 查询类别
articles Article.objects.all().select_related(category)# 获取id13的文章对象同时获取其相关category信息
Article.objects.select_related(category).get(id13)# 获取id13的文章对象同时获取其相关作者名字信息
Article.objects.select_related(author__name).get(id13)# 获取id13的文章对象同时获取其相关category和相关作者名字信息。下面方法等同
Article.objects.select_related(category, author__name).get(id13)
Article.objects.select_related(category).select_related(author__name).get(id13)# 使用select_related()可返回所有相关主键信息,all()非必需
Article.objects.all().select_related()# 获取Article信息同时获取blog信息,filter方法和selected_related方法顺序不重要
Article.objects.filter(pub_date__gttimezone.now()).select_related(blog)
Article.objects.select_related(blog).filter(pub_date__gttimezone.now())标准写法prefetch_related弥补多对多下的数据查询
# 查询类别及标签
articles Article.objects.all().select_related(category).prefecth_related(tags)# 文章列表及每篇文章的tags对象名字信息
Article.objects.all().prefetch_related(tags__name)# 获取id13的文章对象同时获取其相关tags信息
Article.objects.prefetch_related(tags).get(id13)用Prefetch方法可以给prefetch_related方法额外添加额外条件和属性
# 获取文章列表及每篇文章相关的名字以P开头的tags对象信息
Article.objects.all().prefetch_related(Prefetch(tags, querysetTag.objects.filter(name__startswithP))
)# 文章列表及每篇文章的名字以P开头的tags对象信息, 放在article_p_tag列表
Article.objects.all().prefetch_related(Prefetch(tags, querysetTag.objects.filter(name__startswithP)), to_attrarticle_p_tag
)F函数不引入内存 更新数据时
例1
article Article.objects.get(title文章2)
article.thumb_count 1
article.save()例2 使用F()函数
Article.objects.filter(title文章1).update(thumb_countF(thumb_count)1)# 很明显使用F()函数的执行效率会更高只需要一条sql完全的数据库操作而例1则需要先查询缓存然后再更新
# 例1的方法是存在竞态条件的如第一个线程完成取值、更新值、保存新值而第二个线程操作还是使用就的值来进行操作使用F()函数的话因为是数据库层面的原子操作第二个线程再来取值那也是取到更新后的值了表达式应用时
# 同一数据不同字段比较
article Article.objects.filter(thumb_count__gtF(view_count))# 两个操作数都是常数和F()函数的加、减、乘、除、取模、幂计算等算术操作
article Article.objects.filter(view_count__gtF(thumb_count) * 2)# 配合annotate使用
article Article.objects.annotate(all_countF(view_count) F(thumb_count))二、利用索引
合适的索引可以加快数据的检索速度。无论是在Django还是在原生SQL查询上都支持检查某条语句是否有用到索引语法为explain
2.1、Django中
Blog.objects.filter(titleMy Blog).explain(verboseTrue)2.2、原生SQL中
explain select * from user where user_no 00022139三、ORM相较于原生SQL语法有性能欠缺
注Django也支持原生SQL语法:raw
结束