Django优化查询

1. 使用 select_relatedprefetch_related

  • select_related:适用于 一对一多对一 关系,通过 JOIN 查询一次性获取关联数据。
  • prefetch_related:适用于 一对多多对多 关系,通过多个查询预先加载关联数据,并在内存中进行匹配。

(详情请看之前的文章)

2. 使用 onlydefer 减少数据加载

  • only:只加载指定字段,减少查询数据量。
  • defer:延迟加载指定字段,避免不必要的数据传输。
# 只加载 title 和 author 字段,避免加载其他大字段
books = Book.objects.only('title', 'author').all()



# 延迟加载 description 字段
books = Book.objects.defer('description').all()

print(book.title)
print(book.author)
print(descipption) # 这里会触发额外的查询来加载 description 字段

defer()only() 的区别:only是选择加载,而defer是选择不需要加载的。

3. 使用 valuesvalues_list 提取特定字段

  • values:返回字典列表,只包含指定字段。
  • values_list:返回元组列表或平铺列表(使用 flat=True),更高效。
  • 注意:values与values_list返回的是一个字典和元组或者列表,而defer和only返回的是一个模型示例对象,可以正常使用update() save()等方法。

详情可以看django的高效查询文章。

4. 使用 exists 快速检查数据存在

当只需要知道某条数据是否存在时,使用 exists() 会比 count() 更高效,因为它会在找到符合条件的第一条记录时立即返回True,若都不存在则是false。

# 检查是否存在价格大于 100 的书籍
if Book.objects.filter(price__gt=100).exists():
    print("There are expensive books!")

5. 使用 count 而不是 len

如果只需要查询记录的数量,使用 count()len() 高效。count() 会在数据库中直接执行 COUNT 查询,而 len() 会加载所有对象到内存中

# 查询价格大于 50 的书籍数量
expensive_books_count = Book.objects.filter(price__gt=50).count()

6. 避免重复查询

使用 缓存或者将查询结果存储在变量中,避免在同一请求内对相同数据重复查询。

# 避免重复查询
book = Book.objects.get(id=1)
# 后续使用同一个 book 实例,避免再次查询
print(book.title)
print(book.author)

7. 使用 aggregateannotate 执行聚合操作

使用 聚合查询aggregateannotate)可以让数据库在查询过程中直接计算统计结果,减少数据传输量。

from django.db.models import Avg, Count

# 计算所有书籍的平均价格
average_price = Book.objects.aggregate(Avg('price'))

# 获取每个作者的书籍数量
author_books_count = Book.objects.values('author').annotate(book_count=Count('id'))

8. 使用数据库索引

为高频查询的字段(如外键、经常用于过滤的字段)添加 数据库索引,可以显著提高查询速度。可以在模型字段上使用 db_index=True 或者创建 多字段组合索引

# 在模型中创建索引
class Book(models.Model):
    title = models.CharField(max_length=255, db_index=True)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    
    class Meta:
        indexes = [
            models.Index(fields=['author', 'title']),  # 创建组合索引
        ]

9. 使用批量查询方法 bulk_createbulk_update

如果需要对大量数据进行插入或更新,使用 批量操作bulk_createbulk_update)比逐条操作更高效。

# 批量创建书籍
Book.objects.bulk_create([
    Book(title="Book 1", author=author1),
    Book(title="Book 2", author=author2),
    ...
])

# 批量创建书籍
Book.objects.bulk_update([
    Book(title="Book 1", author=author1),
    Book(title="Book 2", author=author2),
    ...
])

10. 使用缓存

对于频繁访问的查询结果,可以使用 Django 的 缓存框架将结果存储在缓存中,减少数据库查询次数。

from django.core.cache import cache

# 尝试从缓存中获取数据,如果不存在则查询数据库并存入缓存
books = cache.get('all_books')
if not books:
    books = Book.objects.all()
    cache.set('all_books', books, timeout=60*15)  # 缓存 15 分钟

11. 使用分页减少大查询的数据量

在处理大量数据时,可以使用 Django 的分页器(Paginator)对数据进行分页,减少一次查询的数据量。

from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Book

def book_list(request):
    books = Book.objects.all()  # 获取所有书籍
    paginator = Paginator(books, 10)  # 每页显示 10 本书
    page_number = request.GET.get('page')  # 获取当前页码
    page_obj = paginator.get_page(page_number)  # 获取分页对象
    
    return render(request, 'book_list.html', {'page_obj': page_obj})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值