Django ORM 数据库管理 提高查询、更新性能的技巧和编程习惯:
以下是一个很常见的例子(并非极端条件才发生):在配置低的服务器上,表格TableA 的记录数10w,字符串字段K无索引,一个简单查询耗时10秒,一个插入耗时50毫秒。总体上,索引带来的查询性能提升(10秒级)会远远大于插入性能的下降(毫秒级)。如果可以确保匹配结果有且只有一个(即无需处理异常),get()通常略微更高效,但几乎可以忽略不计。对于非预期结果的处理filter().first()通常更
·
在Django中使用ORM进行数据库管理时,以下是一些提高数据查询、更新和插入效率的技巧和编程习惯:
1. 索引优化 - 效果最显而易见
- 为常用的查询字段(如外键、唯一字段等)添加数据库索引,可以显著提高查询速度。
class Book(models.Model):
title = models.CharField(max_length=255, db_index=True)
以下是一个很常见的例子(并非极端条件才发生):在配置低的服务器上,表格TableA 的记录数10w,字符串字段K无索引,一个简单查询耗时10秒,一个插入耗时50毫秒。如果K建立索引,查询耗时降可到毫秒级别,插入耗时增加也只是毫秒级别。总体上,索引带来的查询性能提升(10秒级)会远远大于插入性能的下降(毫秒级)。
2. 使用only()
和defer()
only()
:仅加载指定字段,用于降低内存占用和传输开销。defer()
:延迟加载某些字段,适用于大字段,如Blob或TextField。
> 如果表中字段类型较小(例如都是int类型),而且返回的数据条数很少,其实可以忽略不使用.only()
带来的性能差异。
> 如果表中的字段是大数据类型(如长字符串或BLOB),应使用.only()
来优化查询
# Example of only()
users = User.objects.only('id', 'username').all()
# Example of defer()
books = Book.objects.defer('description').all()
3. 合理使用批量操作
- 批量插入:使用
bulk_create()
,可以一次性插入多条数据,减少数据库的连接和提交次数。 - 批量更新:使用
bulk_update()
,高效更新多条记录。 - 批量删除:使用
delete()
而不是逐条删除。
# Example of bulk_create()
Book.objects.bulk_create([
Book(title='Book 1'),
Book(title='Book 2'),
Book(title='Book 3')
])
# Example of bulk_update()
books = Book.objects.filter(published=False)
for book in books:
book.published = True
Book.objects.bulk_update(books, ['published'])
4. 分页查询
- 对大量数据进行分页处理,避免一次性加载过多数据,占用内存资源。使用
Paginator
类或iterator()
方法来进行分页和流式处理。from django.core.paginator import Paginator books = Book.objects.all() paginator = Paginator(books, 10) # 每页10条数据 page_1_books = paginator.get_page(1)
5. 使用事务(Transactions)
- 对于多条相关操作(如插入、更新、删除),使用事务来保证数据一致性和操作的原子性,同时避免多次提交的开销。
from django.db import transaction with transaction.atomic(): author = Author.objects.create(name='Author') book = Book.objects.create(title='Book', author=author)
6. 使用原生SQL和原生查询(Raw Queries)
- 对于极其复杂或高性能要求的查询,使用Django的
raw()
方法执行原生SQL语句,或者使用RawSQL
来插入自定义SQL。
from django.db import connection
books = Book.objects.raw('SELECT * FROM book WHERE title = %s', ['Django'])
7. get()
和filter()
的使用 -- 效率其实差不多
如果可以确保匹配结果有且只有一个(即无需处理异常),get()通常略微更高效,但几乎可以忽略不计。对于非预期结果的处理filter().first()通常更轻松,由于不需要try,代码更简洁,可读性更强。
# Efficient way to get the first matched record
book = Book.objects.filter(title='Django').first()
8. 使用Q
对象和F
表达式
Q
对象:用于组合复杂的查询条件。F
表达式:允许在查询或更新时直接引用字段的值,避免多次读取数据库,提高更新操作效率。from django.db.models import Q, F # Example of Q object books = Book.objects.filter(Q(title__icontains='Django') | Q(author__name='John')) # Example of F expression Book.objects.filter(id=1).update(page_count=F('page_count') + 1)
9. 缓存查询结果
- 对于频繁使用但不经常变动的数据,可以使用缓存来减少数据库访问次数。Django内置的缓存框架支持多种缓存机制,如内存、文件、数据库等。
from django.core.cache import cache
books = cache.get('all_books')
if not books:
books = Book.objects.all()
cache.set('all_books', books, 60*15) # 缓存15分钟
10. 使用select_related()
和prefetch_related()
select_related()
:用于减少多表查询的数量,适合在一对一或外键关系中使用。它在单个SQL查询中加入JOIN操作,加载相关表的数据。prefetch_related()
:适合多对多或反向外键关系,用于预取相关对象并减少SQL查询数量。- 巧妙地组合使用这两个方法,减少N+1查询问题。
# Example of select_related()
books = Book.objects.select_related('author').all()
# Example of prefetch_related()
authors = Author.objects.prefetch_related('books').all()
更多推荐
已为社区贡献3条内容
所有评论(0)