首页 > 数据库 >Django当中的数据库查询优化

Django当中的数据库查询优化

时间:2023-03-09 12:22:52浏览次数:39  
标签:缓存 数据库 related 查询 Django select

了解Django框架中进行数据查询优化,需要了解几点:

1.查询集是惰性的,这意味着在你对查询集执行某些操作(例如对其进行迭代)之前,不会发出相应的数据库请求;

2.始终通过指定要返回的值的数量来限制数据库查询的结果;

3.在 Django 中,查询集可以通过迭代、切片、缓存和 python 方法(例如len()等)进行评估count()。确保充分利用它们;

4.Django 查询集被缓存,因此如果你重复使用相同的查询集,将不会发出多个数据库请求,从而最大限度地减少数据库访问;

5.一次检索你需要的所有内容,但请确保你只检索你需要的内容。

 

Django中的查询优化

数据库索引

# models.py

from django.db import models

class Sale(models.Model):
    sold_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True, #DB Indexing
    )
    charged_amount = models.PositiveIntegerField()

如果你为此模型运行迁移,Django 将在表 Sales 上创建一个数据库索引,并且它将被锁定直到索引完成。在本地开发设置中,数据量很少,连接很少,这种迁移可能感觉是瞬间的,但是当我们谈论生产环境时,有很多并发连接的大型数据集可能会导致停机,如获取锁和创建数据库索引可能需要很长时间。

数据库缓存

Django 提供了一种缓存机制,可以使用不同的缓存后端,如 Memcached 和 Redis,让你避免多次运行相同的查询。

Memcached 是一个开源的内存系统,可保证在不到一毫秒的时间内提供缓存结果。它易于设置和扩展。另一方面,Redis 是一种开源缓存解决方案,具有与 Memcached 相似的特性。大多数离线应用程序使用以前缓存的数据,这意味着大多数查询永远不会到达数据库。

要在 Django 中使用 Memcache,我们需要定义以下内容:

  • BACKEND:定义要使用的缓存后端。
  • LOCATION:ip:port 值 where ip 是 Memcached 守护程序的 IP 地址, port 是运行 Memcached 的端口,或者是指向你的 Redis 实例的 URL,使用适当的方案。

要使用 Memcached 启用数据库缓存,请pymemcache使用以下命令使用 pip 进行安装:

pip install pymemcache

然后,你可以settings.py按如下方式配置缓存设置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

在上面的示例中,Memcached 使用以下 pymemcache 绑定在 localhost (127.0.0.1) 端口 11211 上运行:

同样,要使用 Redis 启用数据库缓存,请使用以下命令使用 pip 安装 Redis:

pip install redis

settings.py然后通过添加以下代码来配置你的缓存设置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379',
    }
}

尽可能使用迭代器

Django 中的查询集通常会在评估发生时缓存其结果,对于该查询集的任何进一步操作,它首先检查是否有缓存的结果。但是,当你使用 时iterator(),它不会检查缓存并直接从数据库中读取结果,也不会将结果保存到查询集。

现在,你一定想知道这有什么帮助。考虑一个查询集,它返回大量具有大量内存的对象进行缓存,但只能使用一次,在这种情况下,你应该使用iterator()。

queryset = Product.objects.all().iterator()
for each in queryset:
    do_something(each)

上述中我们使用了iterator(),Django 将保持 SQL 连接打开并读取每条记录,并 do_something() 在读取下一条记录之前调用。

使用持久性数据库连接

Django 为每个请求创建一个新的数据库连接,并在请求完成后关闭它。这种行为是由 引起的CONN_MAX_AGE,它的默认值为 0。但是应该设置多长时间呢?这取决于你网站上的流量;音量越高,维持连接所需的秒数就越多。通常建议从较低的数字开始,例如 60。

你需要将额外的选项包装在 中 OPTIONS,如留档中详细说明:

DATABASES = {
  'default': {
       'ENGINE': 'django.db.backends.mysql',
       'NAME': 'dashboard',
       'USER': 'root',
       'PASSWORD': 'root',
       'HOST': '127.0.0.1',
       'PORT': '3306',
       'OPTIONS': {
            'CONN_MAX_AGE': '60',
       }
  }
}

使用查询表达式

查询表达式定义了可以在更新、创建、过滤、排序、注释或聚合操作中使用的值或计算。Django 中常用的内置查询表达式是 F 表达式。让我们看看它是如何工作的并且很有用。

在 Django Queryset API 中,F()表达式用于直接引用模型字段值。它允许你引用模型字段值并对它们执行数据库操作,而无需从数据库中获取它们并进入 Python 内存。相反,Django 使用该F()对象来生成定义所需数据库活动的 SQL 短语。

例如,假设我们想将所有产品的价格提高 20%,那么代码将如下所示:

from django.db.models import F

Product.objects.update(price=F('price') * 1.2)

上述使用了F()查询表达式

使用 select_related() 和 prefetch_related()

Django 通过最小化数据库请求的数量来提供优化查询集select_related()的prefetch_related()参数。

根据官方 Django 文档:

select_related() “遵循”外键关系,在执行查询时选择其他相关对象数据。

prefetch_related() 对每个关系进行单独的查找,并在 Python 中进行“加入”。

select_related()

我们select_related()在要选择的项目是单个对象时使用,这意味着 forward ForeignKey、OneToOne和 backOneToOne字段。

你可以使用select_related()创建单个查询,该查询返回单个实例的所有相关对象,用于一对多和一对一连接。执行查询时,select_related()从外键关系中检索任何额外的相关对象数据。

select_related()通过生成 SQL 连接并在SELECT表达式中包含相关对象的列来工作。因此,select_related()在同一数据库查询中返回相关项目。

虽然select_related()会产生更复杂的查询,但获取的数据会被缓存,因此处理获取的数据不需要任何额外的数据库请求。

语法看起来像这样:

queryset = Tweet.objects.select_related('owner').all()

prefetch_related()

相反,prefetch_related()用于多对多和多对一连接。它生成一个查询,其中包括查询中给出的所有模型和过滤器。

语法看起来像这样:

Book.objects.prefetch_related('author').get(id=1).author.first_name

使用bulk_create()和bulk_update()

bulk_create() 是一种通过一次查询将提供的对象列表创建到数据库中的方法。类似地,bulk_update() 是一种使用一个查询更新提供的模型实例上的给定字段的方法。

例如,如果我们有一个如下所示的帖子模型:

#articles
articles  = [Post(title="Hello python"), Post(title="Hello django"), Post(title="Hello bulk")]

#insert data
Post.objects.bulk_create(articles)

如果我们想更新数据,那么我们可以bulk_update()这样使用:

update_queries = []

a = Post.objects.get(id=14)
b = Post.objects.get(id=15)
c = Post.objects.get(id=16)

#set update value
a.title="Hello python updated"
b.title="Hello django updated"
c.title="Hello bulk updated"

#append
update_queries.extend((a, b, c))

Post.objects.bulk_update(update_queries, ['title'])

 

参考自:https://www.51cto.com/article/717666.html

 

标签:缓存,数据库,related,查询,Django,select
From: https://www.cnblogs.com/shaoyishi/p/17197929.html

相关文章

  • mysql 数据库小工具: 小写转大写
    SELECTconcat( 'renametable',TABLE_NAME,'to',UCASE(TABLE_NAME),';')AS'修改脚本sql'FROMinformation_schema.TABLEStWHERETABLE_SCHEMA='newal......
  • day88 - 数据库函数设计-插入100w条数据
    数据库插入100w条数据CREATETABLE`app_user`(`id`BIGINT(20)UNSIGNEDNOTNULLAUTO_INCREMENT,`name`VARCHAR(50)DEFAULT''COMMENT'用户昵称',`email`V......
  • MySQL数据库如何在SQL语句中显式的使用排序规则?
    大家都知道,MySQL数据库在SQL语句中都是使用ORDERBY子句来进行排序,可以使用ASC或DESC关键字来指定排序的方式,即升序或降序。那如果要在排序时指定特定的排序规则,该怎么写......
  • VS error C2471: 无法更新程序数据库vc90.pdb的解决办法
    修改项目属性右击项目-->"属性”  1.“C/C++”-->"常规”-->”调试信息格式”设置为“C7兼容(/Z7)”  2.“C/C++”-->"代码生成”-->”启用字符串池......
  • 1310. 子数组异或查询 (Medium)
    问题描述1310.子数组异或查询(Medium)有一个正整数数组arr,现给你一个对应的查询数组queries,其中queries[i]=[Lᵢ,Rᵢ]。对于每个查询i,请你计算从Lᵢ到Rᵢ......
  • Django 实现WebSocket
    要在Django中实现WebSocket,你需要使用一个称为DjangoChannels的第三方库。安装DjangoChannels:pipinstallchannels创建DjangoChannels配置:在你的项目目录下,创建一......
  • 查询数据库中的所有学生或员工信息,出现乱码时
    1.在测试计划中建立一个线程,再建立一个http请求和一个查看结果树2.在http请求中填写需要用到的信息   3。执行该http请求,在就察看结果树上显示的信息时乱码; ......
  • 11.数据库行锁
    定义介绍:行锁偏向innoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION)......
  • 数据库的数值函数
    1.ceil(x)向上取整2.floor(x)向下取整3.mod(x,y)返回 x/y的模4.rand 返回0-1随机数5.round(x,y) 求参数x的四舍五入的值,保留y位小数    练......
  • 【MySQL】多表的查询
    为什么需要多表查询1、单表查询在WEB要经过几次http交互,再不同表之间才能查找到数据。会浪费很多时间,因此需要多表查询。2、如果多张表合在一张表中,会导致会多字段不......