1. 使用 select_related
和 prefetch_related
select_related
:适用于 一对一 或 多对一 关系,通过 JOIN 查询一次性获取关联数据。prefetch_related
:适用于 一对多 或 多对多 关系,通过多个查询预先加载关联数据,并在内存中进行匹配。
(详情请看之前的文章)
2. 使用 only
和 defer
减少数据加载
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. 使用 values
和 values_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. 使用 aggregate
和 annotate
执行聚合操作
使用 聚合查询(aggregate
和 annotate
)可以让数据库在查询过程中直接计算统计结果,减少数据传输量。
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_create
和 bulk_update
如果需要对大量数据进行插入或更新,使用 批量操作(bulk_create
和 bulk_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})