数据库连接池调优之 Druid:可视化查询慢 SQL 的利器
文章目录
- [数据库连接池调优之 Druid:可视化查询慢 SQL 的利器](#数据库连接池调优之 Druid:可视化查询慢 SQL 的利器)
在当今的软件开发领域,数据库操作的性能优化至关重要,而数据库连接池扮演着关键角色。Druid 作为一款功能强大且备受青睐的数据库连接池组件,在处理诸如可视化查询慢 SQL 等方面展现出了卓越的特性和优势。以下将对 Druid 进行详细的介绍。
一、Druid 概述
Druid 是阿里巴巴开源平台上的一个数据库连接池实现,它为开发人员提供了高效、稳定且功能丰富的数据库连接管理方案。除了基础的连接池功能外,Druid 还具备强大的监控和扩展能力,能够帮助开发人员和运维人员深入了解数据库的使用情况,及时发现并解决潜在的性能问题,尤其是在定位和分析慢 SQL 语句方面表现突出。
二、Druid 的核心功能
(一)高效的连接池管理
- Druid 采用了先进的连接池算法,能够有效地管理数据库连接的创建、复用和销毁。它可以根据配置的参数,合理地控制连接池中连接的数量,避免过多的连接创建导致数据库资源耗尽,同时也能确保在高并发场景下有足够的可用连接,保障系统的响应速度。例如,在一个电商系统的促销活动期间,大量用户同时访问数据库进行下单、查询商品等操作,Druid 能动态分配和复用连接,使得数据库操作能够顺畅进行。
- 其内置的连接泄漏检测机制也是一大亮点。如果某个数据库连接长时间未被正确释放,Druid 能够及时检测出来,并通过日志等方式提醒开发人员,有助于快速定位代码中可能存在的资源管理漏洞,防止因连接泄漏而引发的数据库性能下降等问题。
(二)强大的监控功能
- 实时监控
- 慢 SQL 统计与分析
- SQL 执行历史查看
(三)灵活的配置与扩展
- Druid 的配置非常灵活,开发人员可以根据实际项目的需求,轻松调整连接池的各项参数,如初始连接数、最大连接数、最小空闲连接数、连接超时时间等等。这种灵活性使得它能够适配不同规模、不同业务场景的应用系统,无论是小型的企业内部管理系统还是大型的互联网分布式应用,都能通过合理配置 Druid 来优化数据库连接管理。
- 同时,Druid 支持丰富的扩展接口,开发人员可以基于这些接口进行自定义的功能扩展,比如添加自定义的监控指标、实现特定的连接过滤逻辑等,进一步增强其在特定业务场景下的适用性。
三、在可视化查询慢 SQL 方面的具体应用
(一)慢 SQL 自动捕获与展示
当应用系统运行过程中,Druid 会实时监控 SQL 的执行情况,一旦发现执行时间超过预设阈值(这个阈值可以根据业务实际情况进行配置)的 SQL 语句,就会将其捕获并记录下来。在监控界面中,这些慢 SQL 会以列表的形式呈现,按照执行时间等关键指标进行排序,方便开发人员优先关注那些对性能影响最大的语句。例如,在一个物流管理系统中,如果查询订单运输轨迹的 SQL 经常因为关联表过多、数据量较大而执行缓慢,Druid 就能准确地捕捉到它,并展示出详细的执行信息供开发人员分析优化。
(二)深度分析慢 SQL 详情
点击具体的慢 SQL 条目后,Druid 会展示出该 SQL 语句的全方位详情。包括其完整的 SQL 文本,开发人员可以直观地查看语句的写法是否合理,是否存在不必要的子查询、关联操作过于复杂等情况。同时,还能看到该 SQL 在不同执行时间点的耗时情况统计图表,通过图表分析其执行时间的波动规律,判断是在特定数据量下才出现慢的情况,还是每次执行都很慢等,进一步辅助确定优化方向。此外,展示涉及的数据库表以及索引使用情况,能帮助开发人员判断是否是因为缺少索引或者索引失效导致了 SQL 执行缓慢。
(三)基于慢 SQL 分析的优化建议与实践
根据 Druid 提供的慢 SQL 相关信息,开发人员可以有针对性地采取优化措施。比如,如果发现某条 SQL 语句因为全表扫描导致执行慢,而对应的查询字段适合添加索引,就可以在数据库中为相关字段创建索引后,再次通过 Druid 监控该 SQL 的执行情况,查看性能是否得到了提升。而且 Druid 持续的监控能力可以帮助验证优化后的效果,确保优化举措确实解决了慢 SQL 问题,提高了系统整体的数据库操作性能。
四、实战
Druid 连接池引入
可以参考 官方文档 引入(虽然也没什么好参考的)。
1)通过 Maven 引入 Druid,并且排除默认引入的 HikariCP:
xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.23</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
<exclusions>
<!-- 排除默认的 HikariCP -->
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
2)修改 application.yml 文件配置。
由于参数较多,建议直接拷贝以下配置即可,部分参数可以根据注释自行调整:
yaml
复制代码spring:
# 数据源配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mianshiya
username: root
password: 123456
# 指定数据源类型
type: com.alibaba.druid.pool.DruidDataSource
# Druid 配置
druid:
# 配置初始化大小、最小、最大
initial-size: 10
minIdle: 10
max-active: 10
# 配置获取连接等待超时的时间(单位:毫秒)
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 2000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 600000
max-evictable-idle-time-millis: 900000
# 用来测试连接是否可用的SQL语句,默认值每种数据库都不相同,这是mysql
validationQuery: select 1
# 应用向连接池申请连接,并且testOnBorrow为false时,连接池将会判断连接是否处于空闲状态,如果是,则验证这条连接是否可用
testWhileIdle: true
# 如果为true,默认是false,应用向连接池申请连接时,连接池会判断这条连接是否是可用的
testOnBorrow: false
# 如果为true(默认false),当应用使用完连接,连接池回收连接的时候会判断该连接是否还可用
testOnReturn: false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle
poolPreparedStatements: true
# 要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true,
# 在Druid中,不会存在Oracle下PSCache占用内存过多的问题,
# 可以把这个数值配置大一些,比如说100
maxOpenPreparedStatements: 20
# 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作
keepAlive: true
# Spring 监控,利用aop 对指定接口的执行时间,jdbc数进行记录
aop-patterns: "com.springboot.template.dao.*"
########### 启用内置过滤器(第一个 stat 必须,否则监控不到SQL)##########
filters: stat,wall,log4j2
# 自己配置监控统计拦截的filter
filter:
# 开启druiddatasource的状态监控
stat:
enabled: true
db-type: mysql
# 开启慢sql监控,超过2s 就认为是慢sql,记录到日志中
log-slow-sql: true
slow-sql-millis: 2000
# 日志监控,使用slf4j 进行日志输出
slf4j:
enabled: true
statement-log-error-enabled: true
statement-create-after-log-enabled: false
statement-close-after-log-enabled: false
result-set-open-after-log-enabled: false
result-set-close-after-log-enabled: false
########## 配置WebStatFilter,用于采集web关联监控的数据 ##########
web-stat-filter:
enabled: true # 启动 StatFilter
url-pattern: /* # 过滤所有url
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" # 排除一些不必要的url
session-stat-enable: true # 开启session统计功能
session-stat-max-count: 1000 # session的最大个数,默认100
########## 配置StatViewServlet(监控页面),用于展示Druid的统计信息 ##########
stat-view-servlet:
enabled: true # 启用StatViewServlet
url-pattern: /druid/* # 访问内置监控页面的路径,内置监控页面的首页是/druid/index.html
reset-enable: false # 不允许清空统计数据,重新计算
login-username: root # 配置监控页面访问密码
login-password: 123
allow: 127.0.0.1 # 允许访问的地址,如果allow没有配置或者为空,则允许所有访问
deny: # 拒绝访问的地址,deny优先于allow,如果在deny列表中,就算在allow列表中,也会被拒绝
3)启动后访问监控面板:http://localhost:8101/api/druid/index.html
输入上述配置中的用户名和密码登录:
测试
使用 Druid 监控
下面我们测试一下因为数据库连接池不足导致的性能问题,并借此带大家熟悉 Druid 监控的使用。
1)将配置中的连接池大小改为 1,且获取连接等待时间超时为 2s:
yaml
druid:
# 配置初始化大小、最小、最大
initial-size: 1
minIdle: 1
max-active: 1
# 配置获取连接等待超时的时间(单位:毫秒)
max-wait: 2000
然后任意执行一次对数据库的批量操作,比如插入 20 条数据,每批 2 条,一共 10 批,会随机报错:
查看 Druid 监控,可以看到最大并发为 1,因为连接池的连接数量只有 1:
除了 SQL 的监控,还有 URI 的监控,可以看到是哪个接口调用了数据库,执行了多少时间。以后出现线上数据库卡死的问题时,很快就能定位到是哪个接口、哪个 SQL 出现了问题(或者访问频率过高)。
💡 Druid 的 URI 监控是怎么实现的?
核心实现方法如下:
- 通过基于 Servlet 的过滤器 WebStatFilter 来拦截请求,该过滤器会收集关于请求的相关信息,比如请求的 URI、执行时长、请求期间执行的 SQL 语句数等。
- 统计 URI 和 SQL 执行情况是怎么关联起来的呢? 每次执行 SQL 时,Druid 会在内部统计该 SQL 的执行情况,而 WebStatFilter 会把 SQL 执行信息与当前的 HTTP 请求 URI 关联起来。
2)将配置中的连接池大小改为 10,且获取连接等待时间超时为 2s:
yaml
druid:
# 配置初始化大小、最小、最大
initial-size: 10
minIdle: 10
max-active: 10
# 配置获取连接等待超时的时间(单位:毫秒)
max-wait: 2000
可以看到,SQL 的并发直接变成了 10:
URI 接口调用的耗时,直接缩小的 10 倍,符合我们提升了 10 倍并发的优化情况:
有的时候,即使我们服务器 JVM 的内存和 CPU 占用都非常低,其他的中间件比如 MySQL 和 Redis 的占用也非常低,但系统依然会出现响应慢、卡死的情况。这可能就是因为一些配置错误,所以了解这些知识还是非常有必要的。
五、总结
Druid 作为一款优秀的数据库连接池,凭借其高效的连接池管理、强大的监控功能以及在可视化查询慢 SQL 等方面的出色表现,为开发和运维人员在数据库性能优化工作中提供了有力的工具支持。通过合理地应用 Druid,并充分利用其提供的各类功能,能够更加高效地定位和解决数据库操作中的慢 SQL 问题,提升整个应用系统的性能和稳定性,保障业务的顺畅运行。在越来越注重系统性能和用户体验的今天,Druid 的价值也愈发凸显,值得在各类涉及数据库操作的项目中广泛应用和深入探索。