Code前端首页关于Code前端联系我们

Django ORM 实现和惰性查询优化

terry 2年前 (2023-09-24) 阅读数 51 #后端开发

1。操作


Module from django.db import transaction

1 开启交易:with transaction.atomic()

from django.db import transaction
class MyView(View):
    def post(self, request):
        # 在with代码块中开启事务,出了with自动结束事务
        with transaction.atomic()
        	pass

开启交易:@transaction.atomic

class MyView(View):
    @transaction.atomic
    def post(self, request):
        # 整个post方法都在事务中
        pass

2 设置交易返回点

sid = transaction.savepoint() # 可以设置多个

交易返回提交

# 提交整个事务  但是不能在自动提交的事务中使用
transaction.commit() 

# 释放保存点 sid ,自保存点被创建依赖执行的更改成为事务的一部分
transaction.savepoint_commit(sid)

# atomic的事务,只有在事务结束后,才会自动提交到数据库,进行数据的持久化

4 设置隔离

确认可用性

import psycopg2.extensions

# 根据需要设置隔离级别,如下配置是READ_COMMITTED
# 但是配置PostgreSQL,不能配置mysql,否则会报错
DATABASES = {
    # ...
    'OPTIONS': {
        'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED,
    },
}

2. 惰性 ORM 查询


即减轻数据库中的工作,缓解惰性 ORM 压力

# 提交整个事务  但是不能在自动提交的事务中使用
transaction.commit() 

# 释放保存点 sid ,自保存点被创建依赖执行的更改成为事务的一部分
transaction.savepoint_commit(sid)

# atomic的事务,只有在事务结束后,才会自动提交到数据库,进行数据的持久化

4 所有 ORM 中的 SQL 查询语句为惰性操作,即当需要使用查询结果时,才会真正执行SQL语句来访问数据,否则请求将无法得到满足。

可以使用代码验证:

2 配置配置文件,以便在执行 SQL 语句时,将 SQL 命令打印到终端

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level': 'DEBUG',
        },
    }
}

3 验证

# 只查询,不使用查询结果
models.User.objects.all()

# 将查询结果赋值给变量res,并使用res
res = models.User.objects.all()
print(res)

# 分别执行,查看终端的打印结果

仅并延迟

3.仅问题

  • 当您指定要询问的字段时,所有答案将立即可用。以后访问现场数据时,可以直接从内存中访问。不再需要操作数据库。返回 QuerySet[obj1, obj2]。

defer查询

  • 是指一次获取除指定字段之外的所有数据,插入到一个对象中。以后访问这些字段数据的时候,如果数据库不行的话,可以直接从内存中访问。
class UserTest(models.Model):
    id = models.AutoField(primary_key = True)
    name = models.CharField(max_length = 32)
    age = models.IntegerField()
    def __str__(self):
        return 'name: %s, age: %s' %(self.name, self.age)

models.UserTest.objects.create(name = '小慧',age = '18')
models.UserTest.objects.create(name = '小嘉',age = '19')
models.UserTest.objects.create(name = '小甜',age = '17')
models.UserTest.objects.create(name = '小妞',age = '16')

# all 查询
# 访问一次数据库,打印一条sql命令,获取所有的 UserTest 表中的数据
res = models.UserTest.objects.all()  
print(res)

# only 查询
# 访问一次数据库,打印一条sql命令,仅仅获取 name 的所有数据到内存
res = models.UserTest.objects.only("name")  
print(res)

for user_obj in res:
    print(user_obj.name)  # 直接从内存中获取,不访问数据库,不打印 SQl 命令
    print(user_obj.age)   # 每执行一次,就访问一次数据库,打印一次 SQl 命令
    
# defer 查询
# 访问一次数据库,打印一条 SQl 命令,获取除了 name 之外的所有数据到内存
res = models.User.objects.defer("name")  
for user_obj in res:
    print(user_obj.name)  # 每执行一次,访问一次数据库,打印一条 SQl 命令
    print(user_obj.age)   # 直接从内存中获取,不访问数据库,不打印 SQl 命令

注意:单独进行 要查看结果,请注意打印

IV。 select_lated 和 prefetch_lated


都支持表匹配查询。这些规则类似于基于对象的来回问题。正向:'外键',反向:'子表名称_集'

select_lated:插入外键,插入表查询(内连接),将所有数据插入内存,多连接的外键不可用。

res = models.Book.objects.select_related('publish')

prefetch_lated:设置一个外键,先查询这个表中的所有数据,然后根据外键查询对应数据表中的所有数据。它类似于子查询。可以定义多个外键,即多个子查询

res = models.Book.objects.prefetch_related('publish')

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门