关于数据库:数据库查询性能优化指南

50次阅读

共计 3734 个字符,预计需要花费 10 分钟才能阅读完成。

数据库查问性能优化始终是程序员绕不开的话题,当咱们遇到业务刷新报表迟缓或者查问获取后果提早太大,能够采纳发问法来思考如何进行优化。

1. 什么样的环境

硬件环境

query 执行的速度和咱们的硬件非亲非故,以后用的什么样的 CPU,有多少核多少线程,内存有多大都间接影响了运算速度,磁盘是 SSD 还是 HDD,网卡什么速率都间接影响了咱们数据读取的时延

软件环境

软件环境尽管不像硬件一样,各种参数看的见摸得着,但依然影响着咱们的查问性能。没一套零碎实际上都在特定的场景有着各自的劣势。咱们的查问零碎是什么样的架构,适宜什么样的 query,在线还是离线,计算多还是数据读取多,这些在咱们做优化的时候都应该了然于心。

上面咱们依据这种思路来看看如何做性能优化

2. 什么样的 query

首先咱们优化查问的时候,须要看看 query 到底是哪种类型。写入还是查问(这里鉴于篇幅只谈查问),CPU 密集还是 IO 密集。如果咱们的零碎是适宜 OLTP 低延时点查的场景,想要在这种零碎上做 OLAP 大规模剖析很显然就不太适宜,OLTP 个别专一于数据一致性较高的点查,而 OLAP 因为数据量宏大,个别都须要采纳向量并发查问。OLAP 不专一于毫秒级的低提早,而 OLTP 不专一于上亿级的数据统计。

3. 如何寻找性能瓶颈

3.1 vmstat 查看零碎状况

整体零碎不晓得以后的瓶颈在哪里时,咱们能够先用 vmstat 工具来简略的看一下零碎的大抵状况。如下图所示,2 示意每个两秒采集一次服务器状态。

procs : 查看过程状态

r : 运行队列,即以后可运行(正在运行或者期待运行)的过程数量。目前 CPU 比拟闲暇,这个数量很小,当这个值超过了 CPU 数目,就会呈现 CPU 瓶颈了。

b : 阻塞的过程, 即处在不可中断 sleep 状态下的过程数量。

memory : 查看内存状态

swpd : 已应用的虚拟内存大小,如果大于 0,示意机器开始应用虚拟内存了,虚拟内存运行会很慢。这里数值为 0 示意咱们敞开了虚拟内存性能。

free : 闲暇的物理内存的大小。

buff : 内存做为零碎 buffers 的大小。

cache : 内存做为零碎 cache 的大小。

swap : 磁盘和内存做数据交换的状态

nesi : 每秒从磁盘读入虚拟内存的大小,如果这个值大于 0,示意物理内存不够。

so : 每秒虚拟内存写入磁盘的大小。

io:磁盘的 io 信息

bi : 每秒从块设施接管的块数量。

bo : 每秒发送给块设施的块数量。

如果这两个值较大,示意 IO 比拟频繁,能够思考 IO 优化。

system : 零碎状态信息

in : 每秒 CPU 的中断次数(包含时钟中断)

cs : 每秒上下文切换次数,咱们调用零碎函数、线程的切换,就须要上下文切换,这个值要太大就能够思考 缩小零碎的上下文切换,比方协程代替多线程等形式。

CPU : CPU 信息

us : 包含用户工夫和 nice 工夫,跑非内核的代码(或者用户代码)的工夫。

sy : 零碎占用工夫,跑内核代码(比方零碎调用)占用的工夫。

id : 破费在 idle 上的 CPU 工夫。

wa : 期待 IO CPU 工夫。如果这个值太大,示意 IO 零碎瓶颈在 IO 上。

如果 CPU 占用高示意零碎在 CPU 上,如果零碎的 swap 比拟频繁,很可能是零碎内存泄露或者内存不够用,须要扩大内存,如果是 IO 期待较多则零碎瓶颈呈现在 IO 上,如果上下文切换,或者零碎调用占比太大,则咱们须要思考下咱们程序的设计,缩小零碎调用或者上下文切换。

3.2 CPU 占用过高

咱们能够通过 uptime、top、mpstat 或者 sar 等一些工具来查看以后 CPU 占用过高的状况.

咱们能够通过 uptime 看看以后零碎的整体状况,以后的零碎工夫和运行工夫,登陆的用户数量,还有最近 5、10 和 15 分钟的零碎均匀负载。

top 则能够显示较具体的信息。head 局部有 CPU 占用的详细信息,上面的列表也有记录每个过程占用的 CPU 状况。

如果是多线程,咱们还能够通过 top -H -p pid 来查看过程的每个线程的 CPU 占用状况

咱们找到哪个线程占用的比例多之后,能够依据这个线程的线程名查看该线程是用来做什么解决的。大抵理解下是什么样的解决让 CPU 比拟高。

mpstat 则能够查看零碎每个核的运行状态。

sar 的性能比拟全,这里不再做科普。

CPU 用户态的占用比拟高,个别就是咱们的程序编写的效率太低,具体哪里低,咱们能够通过 perf 工具或者 Intel 的 vtunes 来查看性能瓶颈。perf top 的执行后果如下图所示,咱们拿到对应的堆栈信息之后,就能够针对性的打消 CPU 瓶颈了。(vtune 的用法能够自行谷歌)。

鉴于上述工具查看进去的状况,如果 CPU 的确水位很高,则 CPU 根本就是性能瓶颈。如果不高则,须要进行下一步来判断性能瓶颈。

3.3 IO 占用过高的状况

IO 定位的工具多种多样,个别查看 IO 问题咱们能够应用 iostat、pidstat 和 iotop 工具。当然咱们也能够应用其余的工具,大家能够本人搜寻相干的工具应用,这里次要介绍罕用的几种工具。

pidstat

pidstat 是 sysstat 工具的一个命令,用于监控全副或指定过程的 cpu、内存、线程、设施 IO 等系统资源的占用状况。用户能够通过指定统计的次数和工夫来取得所需的统计信息。

咱们通过这个命令能够晓得哪个过程占用的 IO 比拟多。而后咱们能够通过指定过程号的形式查看更具体的信息。

这样咱们就能够晓得是哪个过程中的哪个线程占用了较多的 IO 资源,而后咱们能够通过对应的 TID,找到对应的执行代码进行剖析。

iostat

iostat 是 I /O statistics(输出 / 输入统计)的缩写,它能够对系统的磁盘操作流动进行监控, 汇报磁盘流动统计状况。然而 iostat 仅对系统的整体状况进行统计,不能对某个过程进行深入分析,独自的过程剖析咱们能够用 iotop 工具,应用办法和 top 相似。

1 示意每秒打印一次以后磁盘的统计信息。咱们须要留神的是前面几个指标。

avgrq-sz均匀每次 IO 操作的数据量(扇区数为单位)
avgqu-sz均匀期待解决的 IO 申请队列长度
await均匀每次 IO 申请等待时间(包含等待时间和解决工夫,毫秒为单位)
svctm均匀每次 IO 申请的解决工夫(毫秒为单位)
%util采纳周期内用于 IO 操作的工夫比率,即 IO 队列非空的工夫比率

avgrq-sz 间接反馈了以后 io 的品种,比方大块数据读取还是小数据量的读取。

avgqu-sz 反馈了以后 IO 的忙碌状况,如果队列长度太长,阐明 IO 当初很忙很多任务处理不过去,换句话说 I,IO 成为了瓶颈。

await 也是一样,如果期待比拟高,阐明 IO 成了累赘。

svctm 则和 avgrq-sz 一样,反馈了 IO 操作的解决规模,如果是大块数据读写,这个工夫就会拉长。

iotop

iotop 能够用于查看哪些过程执行占用了的 I/O, 应用形式和 top 相似, 这里不再做过多形容。

3.4 其余状况

如果 TOP 占用不高,IO 也不是瓶颈,则可能处在程序架构上,比方并发管制的不够好有较多的线程在 sleep 状态。这种状况能够通过 pstack 看看以后所有线程的堆栈。

4. 优化性能瓶颈

CPU 瓶颈型

面对这种类型,个别咱们须要通过 perf 配合对应的代码去进行优化,核心思想就是缩小计算的量。具体方法以下仅供参考:

  1. 多采纳 SIMD 来代替老式的计算指令或者 C ++ 的操作运算符。能够引进相似 Intel 的 MKL 库来辅助计算。
  2. 缩小不必要的反复计算,缩小 for 循环的次数。比方有些 std 库的数据结构都有 find 函数都带有起始坐标,善用起始坐标防止从 0 坐标反复查问。
  3. 如果是零碎调用过多,比方分配内存之类的,能够思考预分配内存的形式,或者间接应用 tcmalloc 等相似的内存治理库进行兜底,有条件的能够基于这类库再开发适宜本人的内存管理体系

IO 瓶颈型

IO 瓶颈个别都是和磁盘相干的,网络上,因为网卡降级,速度下来比拟快,相比来说,限度的 io 根本都是磁盘上的 io. 上面也只说说磁盘的 IO 优化办法。

  1. 如果是读类型的申请造成了 IO 瓶颈,能够思考下层多开 cache。比方全局的 query cache,session 级别的 session cache,块设施的 block cache 等,从下层去缩小磁盘的 io 申请。
  2. 如果是是小数据大并发的写入类型的造成了 IO 瓶颈,咱们能够思考在内存做一次 cache,对这屡次写入先在内存解决,而后通过工夫或者大小阈值等策略管制,刷到磁盘上。
  3. 如果是大数据的写入,咱们能够思考做下平滑写入,每次限度写入的数量。
  4. 如果是因为流量的关系,某一时间点呈现峰值,之后回落,则能够思考通过第三方来写入。比方音讯队列,先写到音讯队列 i 进行削峰,再平滑写入零碎。
  5. 除此之外咱们还能够换更好的硬件,比方磁盘阵列等。

内存瓶颈型

内存瓶颈个别比拟难呈现,内存毕竟比拟便宜,基本上都会满足内存的需要。如果真的因为虚拟内存的问题造成了程序运行效率低下,咱们一方面是思考减少内存,敞开虚拟内存来解决,同时咱们也应该思考本人的程序模型,比方缩小两头数据的存在,多用写时复制技术,多用用零碎的 no copy 接口替换老的接口等。

5. 后续

如果切实没有办法优化了,咱们真的就须要看看以后的 query 是否真的适合咱们的零碎了。还是那句话,每套零碎都有适宜本人的业务,个别公司的零碎体系里都会有多种数据库引擎,针对咱们的 query,去寻找适合的。

正文完
 0