0%

Django-查询优化方法

最近负责的项目后台访问接口贼慢,有时候慢到没有反应的地步,经过多方排查最终把问题源头确定到数据库性性能上。
因为通过尝试,同样的数据同样的代码使用本地数据库和使用云数据库查询速度相差将近百倍。然而提升云数据库性能需要资金,资金不充裕只能从后台代码下手,这个不需要资金支持。

首先因为访问数据库很慢,所以尽量减少对数据库的操作。参看django框架和自己的思考主要优化方面如下:

代码层面

  1. 在不使用到关联表字段的情况下,尽量使用此表字段名,否则会产生多余的查询

    例如有表关系:

    1
    2
    3
    4
    5
    6
    class Author(models.Model):
    name = models.TextField()

    class Book(models.Model):
    title = models.TextField()
    author = models.ForeignKey(Author, on_delete=models.PROTECT, related_name='books', null=True)

    当检查某个某本书的某个作者是否存在时,尽量通Book里面的字段来判断
    即:
    使用if(book.author_id)
    不使用if(book.author)

  2. 正确使用count(),exists()和len(),if判断queryset
    如果不使用查询的数据,则使用count(),exists()方法

    例:

    1
    2
    3
    books = Books.objects.filter()
    if(len(books) > 5):
    do_something_with_books(books)
    1
    2
    3
    books = Book.objects.filter()
    if books.count() > 5:
    do_something_without_books()
  3. 使用values()或values_list()只获取需要的数据
    例:

    1
    Book.objects.values('title')
  4. 处理很多记录时,使用iterator()
    当获得一个queryset的时候,Django会缓存这些数据。
    例如:

    1
    2
    for book in Books.objects.all():
    do_something_with_book()

    此项查询会将所有Books的对象存入内存
    当我们想要保持这个数据库connection时每可以使用iterator()关键字
    例如:

    1
    2
    for book in Books.objects.all().iterator():
    do_something_with_book()
  5. 关联查询select_related, prefetch_related
    这样可以减少查询次数
    (select_related, prefetch_related使用)[https://www.cnblogs.com/linkenpark/p/8866089.html]

    以上可参考Django ORM

数据表设计方面

  1. 为查询到的字段添加索引

项目结构方面

使用redis将常用的数据存储下来
因为有一些表采用的是父子表的关系,要查询到所有的数据并保持数据结构,从代码层面是无从下手了,但是这样的数据又必须取到,
所以只能使用终极大招,缓存
对于需要频繁使用且数据量很大的表,在查询时去redis缓存中找,若没有找到则此时建立一个。
需要注意的是,使用缓存要保证缓存数据和数据表数据一致,这里采用的策略是在执行更新操作时更新相应的缓存数据