Django数据库性能优化之 - 使用Python集合操作
前言
最近有个新需求:
- 人员基础信息(记作人员A),10w
- 某种类型的人员信息(记作人员B),1000
要求在后台上(Django Admin)分别展示:已录入A的人员B列表、未录入的人员B列表
团队的DBA提议使用视图可以解决这个问题(不愧是搞数据库的)
PS:起先我觉得Django的Model是直接管理数据库表的,使用Model来映射数据库模型怕是有一定的麻烦,不过查了一下资料发现并不会~
只需要在Model的Meta子类中添加
managed = False即可,同时将db_table属性设置为视图名称
但这项目是Django写的,我认为既然有这么好用的ORM,何必多此一举去用SQL实现功能逻辑呢
于是大手一挥,不行,咱用Python来搞!
粗略实现
想想有挺多种方式来实现的,可以在Model中加一个方法,例如is_in_a(),然后在里面判断该人员B是否在人员A中
也可以在admin的配置中增加一个字段~
最终我是在Model中增加了新的方法,当然思路不必局限,Django还是很灵活的。
这个方法大概写成这样
def is_in_a(self) -> bool:
from apps.people.models import PersonA
queryset = PersonA.objects.filter(id_number=self.id_number)
return queryset.exists()
is_in_a.short_description = '是否已录入'
is_in_a.boolean = True
OK,没啥问题,接着配置一下admin
@admin.register(PersonB)
class PersonBAdmin(admin.ModelAdmin):
list_display = ['name', 'id_number', 'is_in_a']
这样就可以在后台上正常展示了,is_in_a就和普通的model字段一样使用
不过如果要加一个筛选功能的话,就不行,admin默认的list_filter只能支持数据库字段
要把我们自定义的字段加入筛选,就只能自己写一个Filter
首先来看一个错误的示范
class IsInAFilter(admin.SimpleListFilter):
title = '是否已录入'
parameter_name = 'is_in_a'
def lookups(self, request, model_admin):
return (
('true', '已录入'),
('false', '未录入')
)
def queryset(self, request, queryset):
raw_ids = []
if self.value() == 'true':
for item in queryset:
if item.is_in_a():
raw_ids.append(item.pk)
if self.value() == 'false':
for item in queryset:
if not item.is_in_a():
raw_ids.append(item.pk)
return queryset if self.value() is None else queryset.filter(pk__in=raw_ids)
写完了在admin的filter配置写上就行
list_filter = [IsInAFilter]
实现是实现了,但筛选的时候速度奇慢,因为渲染列表的时候,每一项都要访问一次数据库(恕我直言,这种代码就是shit)
PS:很遗憾,这代码是从我前年写的一个项目里copy过来的(逃
优化思路
这我肯定不能忍啊
最讨厌的就是有人写了屎山代码
更何况这是自己写的shit,更不能忍了
立刻开始着手优化代码!
冷静下来,稍加思索
这个东西慢在于列表中的每一项都要去判断id_number在不在人员A中,那我改成批量判断不就好了?
一想到批量,我就想到values_list,用它来生成俩id_number的列表,既然有俩列表了,那这不就是集合操作了?
完事,开搞!
集合
首先复习一下集合哈
这应该是高中数学知识
集合,就是将数个对象归类而分成为一个或数个形态各异的大小整体。 一般来讲,集合是具有某种特性的事物的整体,或是一些确认对象的汇集。构成集合的事物或对象称作“元素”或“成员”。集合的元素可以是任何事物,可以是人,可以是物,也可以是字母或数字等。
集合的三大特性
无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的。
- 集合上可以定义序关系,定义了序关系后,元素之间就可以按照序关系排序。但就集合本身的特性而言,元素之间没有必然的序。(参见序理论)
互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。
- 有时需要对同一元素出现多次的情形进行刻画,可以使用多重集,其中的元素允许出现多次。
确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现。
数学概念不用深究,编程语言中的集合与数学的集合也有些许不同,不过互异性是都有的,也就是集合中没有重复的元素。
集合操作
为了实现前文提到的性能优化,这里我们只需要掌握集合的几种运算就行
设a、b是两个不同的集合
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
四种操作直接看表格
| 计算 | 代码 | 说明 |
|---|---|---|
| 差集 | a - b |
集合a中包含而集合b中不包含的元素 |
| 并集 | `a | b` |
| 交集 | a & b |
集合a和b中都包含了的元素 |
| 对称差集 | a ^ b |
不同时包含于a和b的元素 |
为了便于理解,再来画个图

| 操作 | 结果 | 所得新集合元素 |
|---|---|---|
a - b |
(1) | {1, 2} |
| `a | b` | (1) + (2) + (3) |
a & b |
(2) | {3, 4} |
a ^ b |
(1) + (3) | {1, 2, 5, 6} |
这下就很清楚了吧~
所以上面那个问题,简化成集合操作就是分别取交集和差集
最终实现
最终实现的代码不仅性能高起来了,代码量也比原来少,简直完美
def queryset(self, request, queryset):
from apps.people.models import PersonA
# 使用集合操作提高性能
set1 = set(PersonA.objects.values_list('id_number', flat=True))
set2 = set(queryset.values_list('id_number', flat=True))
id_numbers = set()
# 选择已录入的,取交集
if self.value() == 'true':
id_numbers = set1 & set2
# 选择未录入的,取差集
elif self.value() == 'false':
id_numbers = set2 - set1
return queryset if self.value() is None else queryset.filter(id_number__in=id_numbers)
搞定~!
等等
最后推荐一下我查资料过程中发现的好东西
Django ORM Cookbook
中文版地址:https://django-orm-cookbook-zh-cn.readthedocs.io/zh_CN/latest/index.html
这是一本书,顾名思义教你使用DjangoORM的,里面有50个例子,感觉挺不错的,可以查缺补漏~
Intermediate Python
中文版地址:https://eastlakeside.gitbook.io/interpy-zh/
也是一本书,中文名“Python进阶”,所以你应该知道里面讲啥了吧~
参考资料
- 集合 (数学) - 维基百科:https://zh.m.wikipedia.org/zh/集合_(数学)
- python set集合运算(交集,并集,差集,对称差集):https://blog.csdn.net/sxingming/article/details/51922776
- Python集合(Set)常用操作:https://www.jianshu.com/p/f60fabfefc09
- https://www.runoob.com/python3/python3-set.html
Django数据库性能优化之 - 使用Python集合操作的更多相关文章
- Django的性能优化
Django的性能优化 一,利用标准数据库优化技术 传统数据库优化技术博大精深,不同的数据库有不同的优化技巧,但重心还是有规则的.在这里算是题外话,挑两点通用的说说: 索引,给关键的字段添加索引, ...
- mysql数据库性能优化(包括SQL,表结构,索引,缓存)
优化目标减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当 ...
- SqlServer数据库性能优化详解
数据库性能优化详解 性能调节的目的是通过将网络流通.磁盘 I/O 和 CPU 时间减到最小,使每个查询的响应时间最短并最大限度地提高整个数据库服务器的吞吐量.为达到此目的,需要了解应用程序的需求和数据 ...
- MySQL数据库性能优化:表、索引、SQL等
一.MySQL 数据库性能优化之SQL优化 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础 优化目标 减少 IO 次数IO永远是数据库最容易瓶颈的地 ...
- SQL Server数据库性能优化之SQL语句篇【转】
SQL Server数据库性能优化之SQL语句篇http://www.blogjava.net/allen-zhe/archive/2010/07/23/326927.html 近期项目需要, 做了一 ...
- 数据库性能优化:SQL索引
SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱. 1.1 什么是索引? SQL索引有两种,聚集索引和非聚集索引 ...
- MySQL 数据库性能优化之索引优化
接着上一篇 MySQL 数据库性能优化之表结构,这是 MySQL数据库性能优化专题 系列的第三篇文章:MySQL 数据库性能优化之索引优化 大家都知道索引对于数据访问的性能有非常关键的作用,都知道索引 ...
- DB2数据库性能优化介绍
DB2数据库性能优化介绍 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 前段时间,我从CSDN得到了这本书<DB2数据库性能调整和优化(第2版)& ...
- 数据库性能优化一:SQL索引一步到位
SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱. 1.1 什么是索引? SQL索引有两种,聚集索引和非聚集索引 ...
随机推荐
- 为什么HttpContextAccessor要这么设计?
前言 周五在群里面有小伙伴问,ASP.NET Core这个HttpContextAccessor为什么改成了这个样子? 在印象中,这已经是第三次遇到有小伙伴问这个问题了,特意来写一篇记录,来回答一下这 ...
- 团队Beta5
队名:观光队 链接 组长博客 作业博客 组员实践情况 王耀鑫 **过去两天完成了哪些任务 ** 文字/口头描述 学习 展示GitHub当日代码/文档签入记录 无 接下来的计划 无 **还剩下哪些任务 ...
- 详解六大国产CPU处理器
一个执着于技术的公众号 CPU作为计算机设备的运算和控制核心,负责指令读取.译码与执行,因研发门槛高.生态构建难,被认为是集成电路产业中的"珠穆朗玛峰". 纵观全球,Intel.A ...
- Caused by: java.lang.Exception: No native library is found for os.name=Mac and os.arch=aarch64. path=/org/sqlite/native/Mac/aarch64
编译项目报错: Caused by: java.lang.Exception: No native library is found for os.name=Mac and os.arch=aarch ...
- Nginx的常用配置
Nginx配置文件结构 设置worker进程的用户,指的linux中的用户,会涉及到nginx操作目录或文件的一些权限,默认为 nobodyuser root; worker进程工作数设置,一般来说C ...
- Hive 3.x 配置&详解
Hive 1. 数据仓库概述 1.1 基本概念 数据仓库(英语:Data Warehouse,简称数仓.DW),是一个用于存储.分析.报告的数据系统. 数据仓库的目的是构建面向分析的集成化数据环境,分 ...
- logging日志模块详细,日志模块的配置字典,第三方模块的下载与使用
logging日志模块详细 简介 用Python写代码的时候,在想看的地方写个print xx 就能在控制台上显示打印信息,这样子就能知道它是什么 了,但是当我需要看大量的地方或者在一个文件中查看的时 ...
- Web Api源码(路由注册)
这篇文章只是我学习Web API框架的输出,学习方法还是输出倒逼输入比较行得通,所以不管写的好不好,坚持下去,肯定有收获.篇幅比较长,仔细思考阅读下来大约需要几分钟. 做.NET开发有好几年时间了,从 ...
- Vue的Vuex的使用
一.Vuex是什么? 1:Vuex是一个专为vue.js应用程序开发的状态管理模式,核心就是一个store仓库,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化 ...
- 使用VPLS跨地域多站点建立二层交换网络
VLL解决方案 https://www.cnblogs.com/darkchen/p/14652540.html 接上篇文档引出VPLS VLL可以跨地域建立二层交换网络,但有个缺陷是只支持两个sit ...