Bootstrap

Django ORM 数据库管理 提高查询、更新性能的技巧和编程习惯:

在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()

;