alibaba / druid

阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池
https://github.com/alibaba/druid/wiki
Apache License 2.0
27.97k stars 8.58k forks source link

首次请求创建 statement 很慢 #4376

Open bigzuo opened 3 years ago

bigzuo commented 3 years ago

使用 druid 连接池,前几次请求总是特别慢,经过 debug 分析:druid 在应用启动时建立的连接,在首次执行请求时,都会进行创建 statement 操作,而这一步耗时特别长。后面再执行请求时,就没有创建 statement 的操作,请求处理的也特别快。

请大佬帮忙分析一下,这个第一次请求耗时是否可以优化?现在应用启动后,前几次请求都特别长,体验非常不好。

应用启动时,druid 创建了连接,这一步符合预期:

2021-07-23 15:32:11.599  WARN 26288 --- [      main] com.alibaba.druid.pool.DruidDataSource  [1243] : removeAbandoned is true, not use in production.
2021-07-23 15:32:11.856 DEBUG 26288 --- [      main] druid.sql.Connection                    [129] : {conn-10001,procId-55682} connected
2021-07-23 15:32:11.957 DEBUG 26288 --- [      main] druid.sql.Connection                    [129] : {conn-10002,procId-55684} connected
2021-07-23 15:32:12.062 DEBUG 26288 --- [      main] druid.sql.Connection                    [129] : {conn-10003,procId-55685} connected

首次请求时,创建 statment 用了将近 200ms,见下面 {conn-10030, pstmt-20000} created 日志,导致首次请求特别慢。

2021-07-23 15:32:28.498 DEBUG 26288 --- [l-thread-1] druid.sql.Connection                    [129] : {conn-10030} pool-connect
2021-07-23 15:32:28.501 DEBUG 26288 --- [l-thread-1] druid.sql.Connection                    [129] : {conn-10030} setAutoCommit false
2021-07-23 15:32:28.670 DEBUG 26288 --- [l-thread-1] druid.sql.Statement                     [134] : {conn-10030, pstmt-20000} created. insert into table_name

2021-07-23 15:32:28.687 DEBUG 26288 --- [l-thread-1] druid.sql.Statement                     [134] : {conn-10030, pstmt-20000} Parameters : [..]
2021-07-23 15:32:28.687 DEBUG 26288 --- [l-thread-1] druid.sql.Statement                     [134] : {conn-10030, pstmt-20000} Types : [VARCHAR, INTEGER]
2021-07-23 15:32:28.700 DEBUG 26288 --- [l-thread-1] druid.sql.Statement                     [134] : {conn-10030, pstmt-20000} executed. 14.004616 millis. insert into table_name

druid 版本:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>

druid 配置:

spring:
  datasource:
    dynamic:
      primary: master                                                                               
      strict: false                                                                                 
      datasource:
        master:                                                                                                                                                             
          url: jdbc:mysql://ip:port/database?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useAffectedRows=true&nullCatalogMeansCurrent=true
          username: xxx
          password: xxx                                                                              
          driver-class-name: com.mysql.jdbc.Driver                                                                               
          druid:                                                                                
            default-auto-commit: true                                                                               
            initial-size: 30                                                                                
            min-idle: 30                                                                                
            max-active: 30                                                                              
            test-while-idle: true   
            keep-alive: true                                                                        
            time-between-eviction-runs-millis: 60000
            min-evictable-idle-time-millis: 300000
            max-evictable-idle-time-millis: 900000                                                                         
            connection-init-sqls: SELECT now()                                                                           
            validation-query: SELECT now()                                                                               
            connection-error-retry-attempts: 3                                                                              
            remove-abandoned: true                                                                              
            transaction-query-timeout: 200                                                                 
            max-wait: 100                                                                                                                                                       
            filters: slf4j,wall,stat
            filter:
              slf4j:
                enabled: true
                statement-log-enabled: true
              stat:
                enabled: true
            web-stat-filter:
              enabled: true
              url-pattern: "/*"
              exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
            stat-view-servlet:
              url-pattern: "/druid/*"
              reset-enable: false
              login-username: admin
              login-password: admin
              enabled: true
        slave:
          (配置略)

mysql 版本:MySQL 5.7.15

testzlx commented 1 year ago

我也遇到类似问题, 在springboot项目中使用mybatis+druid, 项目启动后第一次访问慢, 体现在18,19行耗时有450ms左右, 已打开debug日志,第一次之后请求访问就比较快了,只有30ms左右。 截屏2023-07-02 14 53 48

版本:springboot 2.4.1,mybatis-spring-boot-starter 2.1.4, druid 1.2.6,druid-spring-boot-starter 1.2.6

配置如下: spring: datasource: url: jdbc:mysql://127.0.0.1:3306/abc?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&autoReconnect=true&useSSL=false&verifyServerCertificate=false username: root password: 123

使用druid数据源

    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    druid:
      # 配置初始化大小、最小、最大
      initial-size: 10
      minIdle: 10
      max-active: 20
      # 配置获取连接等待超时的时间(单位:毫秒)
      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.123.boot.mapper.*"
      ########### 启用内置过滤器(第一个 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: