数据库访问性能优化
目录
- IO性能分析
- 数据库性能优化漏斗法则
- 1、减少数据访问(减少磁盘访问)
- (1) 正确的创建并使用索引
- 索引生效场景
- 索引失效场景
- 判断索引是否生效--执行计划
- 2、返回更少数据(减少网络传输或磁盘访问)
- (1) 数据分页处理(减少行数)
- 客户端分页
- 服务器分页
- 数据库分页
- (2) 只返回需要的字段(减少列数)
- 3、减少交互次数(减少网络传输)
- batch 操作
- in list 操作
- 设置Fetch Size
- 优化业务逻辑
- 4、减少服务器CPU开销(减少CPU及内存开销)
- 使用绑定变量
- 合理使用排序
- 大量复杂运算在客户端处理
- 5、利用更多资源(增加资源)
- 客户端多进程并行访问
- 数据库并行处理
- 参考
在基于数据库进行业务功能的开发时,如何保证数据库访问的性能是区分普通程序员和高级程序员的分水岭。这里系统的梳理下如何在程序员视角下实现数据库访问性能优化。 本文是面向程序员的数据库访问性能优化法则一文的精简版,有兴趣的同学可以参考下原文。
IO性能分析
计算机各硬件性能指标,参考如下:

上图中,主要有两个性能指标:
(1) 延时(响应时间):表示硬件的突发处理能力;
(2) 带宽(吞吐量):代表硬件持续处理能力。
从上图可以看出,计算机系统硬件性能从高到代依次为:
CPU–Cache(L1-L2-L3)–内存–SSD硬盘–网络–硬盘
目前个人PC已经从硬盘替换成SSD硬盘,但是后端服务器还是以硬盘偏多(SSD硬盘有读写次数限制,要根据业务需要合理选择)。本文的内容不涉及SSD相关应用系统。
数据库性能优化漏斗法则
根据数据库知识,可以列出每种硬件主要操作内容:
(1) CPU及内存:缓存数据访问、比较、排序、事务检测、SQL解析、函数或逻辑运算,等;
(2) 网络:结果数据传输、SQL请求、远程数据库访问(dblink),等;
(3) 硬盘:数据访问、数据写入、日志记录、大数据量排序、大表连接,等。
根据计算机硬件的基本性能指标及其在数据库中主要操作内容,可以整理出如下图所示的性能基本优化法则:

这个优化法则归纳为5个层次:
1、减少数据访问(减少磁盘访问)
2、返回更少数据(减少网络传输或磁盘访问)
3、减少交互次数(减少网络传输)
4、减少服务器CPU开销(减少CPU及内存开销)
5、利用更多资源(增加资源)
由于每一层优化法则都是解决其对应硬件的性能问题,所以带来的性能提升比例也不一样。传统数据库系统设计是也是尽可能对低速设备提供优化方法,因此针对低速设备问题的可优化手段也更多,优化成本也更低。任何一个SQL的性能优化都应该按这个规则由上到下来诊断问题并提出解决方案,而不应该首先想到的是增加资源解决问题。
以下是每个优化法则层级对应优化效果及成本经验参考:

接下来,针对5种优化法则列举常用的优化手段并结合实例分析。
1、减少数据访问(减少磁盘访问)
(1) 正确的创建并使用索引
数据库存储的数据最终是以文件的形式存储在磁盘中。在使用这些数据的时候,需要要把磁盘中的数据读到内存中。而磁盘 IO 是非常高昂的操作。一种有效的解决方案是提供一种稳定的数据结构能够满足只需要查询很少的数据就可定位到期望的数据。也即每次查询数据仅需要进行少部分的磁盘 IO 操作。这种数据结构就是索引。索引(Index)是帮助数据库高效获取数据的数据结构。 如果将数据库比作书,那么索引就相当于目录。
数据库索引的原理非常简单,但在复杂的表中真正能正确使用索引的人不多。
索引生效场景
索引在SQL中使用,具体如下:
(a) 在where子句中,查询引擎会根据where子句中涉及的字段优先选择索引查询数据。
(b) 在order by子句,当使用order by将查询结果按照某个字段排序时,如果该字段没有建立索引,那么执行计划会将查询出的所有数据使用外部排序,但是如果对该字段建立索引后,那么由于索引本身是有序的,因此直接按照索引的顺序和映射关系逐条取出数据即可。而且如果是分页的,那么只用取出索引表某个范围内的索引对应的数据,而不用取出所有数据进行排序再返回某个范围内的数据。
© 在join子句中,对join语句匹配关系(on)涉及的字段建立索引能够提高效率。
(d) 在select子句中,如果select中的查询字段存在于覆盖索引中,那么无需读取记录即可返回。
索引失效场景
在使用索引的时候,要注意索引失效的场景,尽量避免索引失效的场景。可能导致索引失效的常见场景有:
(a) like语句以%开头,会导致索引失效。模糊查询时,使用%且将其放在开头,会导致查询优化器不得不使用全表查询,从而导致索引失效。如果是"XXX%",则可以正常使用索引。
(b) 索引列参与计算,会导致索引失效(如执行算数运算或使用函数或存在类型转换)。当索引列参与计算时,因为存在中间值,所以会导致索引失效。常见的计算场景有类型转换、算数运算、使用函数等场景。 © 查询条件中有or,如果存在or相关的字段没有索引,会导致语句索引失效。如果查询条件中有or,需要确保or相关的字段都要有索引,否则会导致索引失效。
(d) 违背最左匹配原则,会导致索引失效。如果是一个多码索引(也称联合索引、组合索引),其索引匹配遵循最左匹配规则,如果违背会导致索引失效。
(e) 反向查询可能不会使用索引(如not in、not exist),如果在查询的时候,使用了反向查询相关的语句,要注意确认下索引是否生效。
判断索引是否生效–执行计划
简单SQL可以根据索引使用语法规则判断索引是否生效,但是复杂的SQL不好办,判断SQL的响应时间是一种策略,但是这会受到数据量、主机负载及缓存等因素的影响,有时数据全在缓存里,可能全表访问的时间比索引访问时间还少。如何判断一个SQL语句是否使用到了索引呢?其实可以通过该sql的"执行计划"来判断。关于MySQL执行计划的文章可以参考这篇WIKI。本文重点介绍下索引生效和失效的场景。
2、返回更少数据(减少网络传输或磁盘访问)
(1) 数据分页处理(减少行数)
客户端分页
将数据从应用服务器获取到本地应用程序后,在客户端通过本地代码进行分页处理。这种处理方式编码简单,可以减少客户端与应用服务器网络交互次数。但是,首次交互时间较长,且占用客户端内存(如果不控制数据总量,可能会导致OOM)。
服务器分页
将数据从数据库获取到本地应用程序后,在应用服务器内部再进行数据筛选。这种处理方式编码简单,只需要一次SQL交互,总数据与分页数据差不多时性能较好。但是总数据量较多时性能较差。
数据库分页
采用数据库SQL分页需要两次SQL完成:
(1) 一个SQL计算总数量;
(2) 一个SQL返回分页后的数据。
这种处理方式性能好,是主流的数据分页处理方式。但是,不同数据库的语法可能不同,且需要两次SQL交互。
(2) 只返回需要的字段(减少列数)
在数据库开发规范中,强制要求避免使用select * 语句。因为select * 会返回该表的所有字段。对于宽表来说,查询所有字段是一种灾难。使用select+特定字段,可以: 减少数据在网络上传输开销;减少服务器数据处理开销;减少客户端内存占用。而且,如果访问的所有字段刚好在一个索引里面,则可以使用覆盖索引访问提高性能。
此外,如果表中有大字段或内容较多的字段,如备注信息、文件内容等等,那在查询表时一定要注意这方面的问题,否则可能会带来严重的性能问题。如果表经常要查询并且请求大内容字段的概率很低,我们可以采用分表处理,将一个大表分拆成两个一对一的关系表,将不常用的大内容字段放在一张单独的表中。
3、减少交互次数(减少网络传输)
batch 操作
对数据写入操作,尽量使用batch操作的接口,采用batch操作一般不会减少很多数据库服务器的物理IO,但是会大大减少客户端与服务端的交互次数,从而减少了多次发起的网络延时开销,同时也会降低数据库的CPU开销。
in list 操作
很多时候需要按一些ID查询数据库记录,我们可以采用一个ID一个请求发给数据库,如下所示:
for :var in ids[] do beginselect * from mytable where id=:var;
end;
其实,这里可以做一个小的优化,如下所示,用ID INLIST的这种方式写SQL:
select * from mytable where id in(:id1,id2,...,idn);
通过这样处理可以大大减少SQL请求的数量,从而提高性能。但是,需要注意的是,在in语句里面一次放多少个值还需要考虑数据库的能力,对MySQL来说,建议in中元素的个数小于100。如果超过100个,可能会引起执行计划的不稳定性及增加数据库CPU及内存成本,这个需要专业DBA评估。
设置Fetch Size
当采用select从数据库查询数据时,数据默认并不是一条一条返回给客户端的,也不是一次全部返回客户端的,而是根据客户端fetch_size参数处理,每次只返回fetch_size条记录,当客户端游标遍历到尾部时再从服务端取数据,直到最后全部传送完成。所以如果我们要从服务端一次取大量数据时,可以加大fetch_size,这样可以减少结果数据传输的交互次数及服务器数据准备时间,提高性能。
iBatis的SqlMapping配置文件可以对每个SQL语句指定fetchsize大小,如下所示:
<select id="getAllProduct" resultMap="HashMap" fetchSize="1000">select * from employee
</select>
注意,fetchsize不能设置太大,如果一次取出的数据大于JVM的内存会导致内存溢出,所以建议不要超过1000,太大了也没什么性能提高,反而可能会增加内存溢出的危险。
优化业务逻辑
要通过优化业务逻辑来提高性能是比较困难的,这需要程序员对所访问的数据及业务流程非常清楚。
4、减少服务器CPU开销(减少CPU及内存开销)
使用绑定变量
绑定变量是指SQL中对变化的值采用变量参数的形式提交,而不是在SQL中直接拼写对应的值。非绑定变量写法:Select * from employee where id=1234567。绑定变量写法:Select * from employee where id=?。
SQL中预处理操作就是为处理绑定变量提供的对像,绑定变量有以下优点:
(1) 防止SQL注入;
(2) 提高SQL可读性;
(3) 提高SQL解析性能,不使用绑定变更我们一般称为硬解析,使用绑定变量我们称为软解析。
合理使用排序
现在CPU的性能增强,对于普通的几十条或上百条记录排序对系统的影响也不会很大。但是当你的记录集增加到上万条以上时,需要注意是否一定要这么做了,大记录集排序不仅增加了CPU开销,而且可能会由于内存不足发生硬盘排序的现象,当发生硬盘排序时性能会急剧下降,这种需求需要与DBA沟通再决定,取决于你的需求和数据,所以只有你自己最清楚,而不要被别人说排序很慢就吓倒。
以下列出了可能会发生排序操作的SQL语法:
Order by
Group by
Distinct
Exists子查询
Not Exists子查询
In子查询
Not In子查询
Union(并集),Union All也是一种并集操作,但是不会发生排序,如果你确认两个数据集不需要执行去除重复数据操作,那请使用Union All 代替Union。
Minus(差集)
Intersect(交集)
Create Index
大量复杂运算在客户端处理
什么是复杂运算,一般情况下,一秒钟CPU只能做10万次以内的运算。如含小数的对数及指数运算、三角函数、3DES及BASE64数据加密算法等等。如果有大量这类函数运算,尽量放在客户端处理,一般CPU每秒中也只能处理1万-10万次这样的函数运算,放在数据库内不利于高并发处理。
5、利用更多资源(增加资源)
客户端多进程并行访问
多进程并行访问是指在客户端创建多个进程(线程),每个进程建立一个与数据库的连接,然后同时向数据库提交访问请求。当数据库主机资源有空闲时,我们可以采用客户端多进程并行访问的方法来提高性能。如果数据库主机已经很忙时,采用多进程并行访问性能不会提高,反而可能会更慢。所以使用这种方式最好与DBA或系统管理员进行沟通后再决定是否采用。
数据库并行处理
数据库并行处理是指客户端一条SQL的请求,数据库内部自动分解成多个进程并行处理。注意,并不是所有的数据库都支持并行处理,并不是所有的SQL都可以使用并行处理。并行处理的优点是使用多进程处理,充分利用数据库主机资源(CPU,IO),提高性能。但是并行处理也有以下缺点:单个会话占用大量资源,影响其它会话,所以只适合在主机负载低时期使用;只能采用直接IO访问,不能利用缓存数据,所以执行前会触发将脏缓存数据写入磁盘操作。
需要注意的是:
(1) 并行处理在OLTP类系统中慎用,使用不当会导致一个会话把主机资源全部占用,而正常事务得不到及时响应,所以一般只是用于数据仓库平台。
(2) 一般对于百万级记录以下的小表采用并行访问性能并不能提高,反而可能会让性能更差。
参考
https://blog.csdn.net/yzsind/article/details/6059209 面向程序员的数据库访问性能优化法则
https://blog.csdn.net/solihawk/article/details/120756584 数据库系列之MySQL中的执行计划
相关文章:
数据库访问性能优化
目录 IO性能分析数据库性能优化漏斗法则1、减少数据访问(减少磁盘访问)(1) 正确的创建并使用索引索引生效场景索引失效场景判断索引是否生效--执行计划 2、返回更少数据(减少网络传输或磁盘访问)(1) 数据分页处理(减少行数)客户端…...
vue 预览 有token验证的 doc、docx、pdf、xlsx、csv、图片 并下载
预览 doc我也不会 //docx <div v-if"previewType docx" ref"iframeDom" style"border: none; width: 100%; height: 100%"></div> import { renderAsync } from "docx-preview"; let iframeDom: any ref(); axios({url…...
WPF数据视图
将集合绑定到ItemsControl控件时,会不加通告的在后台创建数据视图——位于数据源和绑定的控件之间。数据视图是进入数据源的窗口,可以跟踪当前项,并且支持各种功能,如排序、过滤、分组。 这些功能和数据对象本身是相互独立的&…...
C++ new/delete 与 malloc/free 的区别?
new/delete 与 malloc/free 的区别? 分配内存的位置 malloc是从堆上动态分配内存new是从自由存储区为对象动态分配内存。自由存储区的位置取决于operator new的实现。自由存储区不仅可以为堆,还可以是静态存储区,这都看operator new在哪里为…...
【数学建模】常微分,偏微分方程
1.常微分方程 普通边界 已知t0时刻的初值 ode45() 龙格-库塔法 一阶,高阶都一样 如下: s(1) y , s(2)y s(3) x , s(4)x //匿名函数 下为方程组 核心函数 s_chuzhi [0;0;0;0]; //初值 分别两个位移和速度的初值 t0 0:0.2:180; f (t,s)[s(2);(…...
浙大数据结构之09-排序1 排序
题目详情: 给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。 本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下: 数据1:只有1个元素;数据2…...
Pydantic 学习随笔
这里是零散的记录一些学习过程中随机的理解,因此这里的记录不成体系。如果是想学习 Pydantic 建议看官方文档,写的很详细并且成体系。如果有问题需要交流,欢迎私信或者评论。 siwa 报 500 Pydantic 可以和 siwa 结合使用,这样既…...
11 mysql float/double/decimal 的数据存储
前言 这里主要是 由于之前的一个 datetime 存储的时间 导致的问题的衍生出来的探究 探究的主要内容为 int 类类型的存储, 浮点类类型的存储, char 类类型的存储, blob 类类型的存储, enum/json/set/bit 类类型的存储 本文主要 的相关内容是 float, decimal 类类型的相关数据…...
【高效数据结构——位图bitmap】
初识位图bitmap 位图(Bitmap)是一种用于表示和操作位(bit)的数据结构。它是由一系列二进制位(0 或 1)组成的序列,每个位都可以单独访问和操作。 位图常用于以下情况: 压缩存储&…...
ArrayList LinkedList
ArrayList 和 LinkedList 区别 ArrayList和LinkedList都是Java集合框架中的实现类,用于存储和操作数据。它们在底层实现和性能特点上有一些区别。 数据结构:ArrayList底层使用数组实现,而LinkedList底层使用双向链表实现。这导致它们在内存结…...
iOS砸壳系列之三:Frida介绍和使用
当涉及从App Store下载应用程序时,它们都是已安装的iOS应用(IPA)存储在设备上。这些应用程序通常带有保护的代码和资源,以限制用户对其进行修改或者逆向工程。 然而,有时候,为了进行调试、制作插件或者学习…...
Git学习——细节补充
Git学习——细节补充 1. git diff2. git log3. git reset4. git reflog5. 提交撤销5.1 当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时5.2 当提交到了stage区后,想要退回 6. git remote7. git pull origin master --no-rebase8. 分支管理9. g…...
【设计模式】Head First 设计模式——装饰者模式 C++实现
设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 设计思想 动态地将责任附加到对象上,若要扩…...
layui实现数据列表的复选框回显
layui版本2.8以上 实现效果如图: <input type"hidden" name"id" id"id" value"{:g_val( id,0)}"> <div id"tableDiv"><table class"layui-hide" id"table_list" lay-filter…...
关于使用RT-Thread系统读取stm32的adc无法连续转换的问题解决
关于使用RT-Thread系统读取stm32的adc无法连续转换的问题解决 今天发现rt系统的adc有一个缺陷(也可能是我移植的方法有问题,这就不得而知了!),就是只能单次转换,事情是这样的: 我在stm32的RT-T…...
【启扬方案】启扬多尺寸安卓屏一体机,助力仓储物料管理系统智能化管理
随着企业供应链管理的不断发展,对仓储物料管理的要求日益提高。企业需要实时追踪和管理物料的流动,提高物流效率、降低库存成本和减少库存的风险。因此,仓储物料管理系统的实现成为必要的手段。 仓储物料管理系统一体机作为一种新型的物料管理…...
Android Glide使用姿势与原理分析
作者: 午后一小憩 简介 Android Glide是一款强大的图片加载库,提供了丰富的功能和灵活的使用方式。本文将深入分析Glide的工作原理,并介绍一些使用姿势,助你更好地运用这个优秀的库。 原理分析 Glide的原理复杂而高效。它首先基…...
管理类联考——逻辑——汇总篇——知识点突破——形式逻辑——联言选言——真假
角度——真值表 以上考点均是已知命题的真假情况做出的推理,还存在一种情况是已知肢判断P、Q的真假,断定干判断的真假,这种判断过程就是运用真值表。 P ∧ Q的真值 ①如何证明P ∧ Q为假? 由于P ∧ Q的本质是P、Q同时成立,所以只要P、Q有一个为假,整个命题就为假。 ②如…...
ChatGPT数据分析及作图插件推荐-Code Interpreter
今天打开chatGPT时发现一个重磅更新!code interpreter插件可以使用了。 去查看openai官网,发现从2023.7.6号(前天)开始,code interpreter插件已经面向所有chatGPT plus用户开放了。 为什么说code interpreter插件是一…...
说说FLINK细粒度滑动窗口如何处理
分析&回答 Flink的窗口机制是其底层核心之一,也是高效流处理的关键。Flink窗口分配的基类是WindowAssigner抽象类,下面的类图示出了Flink能够提供的所有窗口类型。 Flink窗口分为滚动(tumbling)、滑动(sliding&am…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
如何把工业通信协议转换成http websocket
1.现状 工业通信协议多数工作在边缘设备上,比如:PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发,当设备上用的是modbus从站时,采集设备数据需要开发modbus主站;当设备上用的是西门子PN协议时…...
李沐--动手学深度学习--GRU
1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...
