You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle 12c结合R2DBC查询耗时过长问题排查求助

Spring WebFlux + Oracle 12c R2DBC 查询性能问题排查

我正在使用Spring WebFlux开发API,数据库采用Oracle 12c。当通过R2DBC执行查询时,即便表中仅1条记录,单次查询耗时仍达300-1200ms。请问我哪里操作有误?为何查询耗时如此久?

【跟踪截图】


1. Repository代码

使用协程响应式等待结果。

@Repository
class ClientRepository(
    private val r2dbcEntityTemplate: R2dbcEntityTemplate
) : BaseRepository<ClientEntity>(r2dbcEntityTemplate) {

    suspend fun getSEQ() = getSEQ("CLIENT_SEQ")

    suspend fun findByClientId(
        clientId: String
    ) = run {
        logger.debug("+findByClientId : {}", clientId)
        val now = LocalDate.now()
        var aa = r2dbcEntityTemplate.select(
            Query.query(
                Criteria.where(ClientEntity::clientId.name).`is`(clientId)
                    .and(Criteria.where(ClientEntity::isDeleted.name).`is`(Flag.N))
                    .and(Criteria.where(ClientEntity::startDate.name).lessThanOrEquals(now))
                    .and(
                        Criteria.where(ClientEntity::endDate.name).isNull
                            .or(ClientEntity::endDate.name).greaterThanOrEquals(now)
                    )
            ),
            ClientEntity::class.java
        )
        logger.debug("done query")
        var bb = aa.awaitFirstOrNull()
        logger.debug("done awaitFirstOrNull")
        logger.debug("-findByClientId : {}", clientId)
        bb
    }
}

2. R2DBC配置

使用io.r2dbc:r2dbc-pool:0.9.2.RELEASE作为连接池。

@Configuration
@EnableR2dbcRepositories
@EnableTransactionManagement
class R2DBCConfig(
    val myConfigProperty: MyConfigProperty
) : AbstractR2dbcConfiguration() {

    @Bean
    override fun connectionFactory(): ConnectionFactory {
        val descriptor = "(DESCRIPTION =\n" +
                "    (ADDRESS = (PROTOCOL = TCP)(HOST = ${myConfigProperty.database.host})(PORT = ${myConfigProperty.database.port}))\n" +
                "    (CONNECT_DATA =\n" +
                "      (SERVER = DEDICATED)\n" +
                "      (SERVICE_NAME = ${myConfigProperty.database.serviceName})\n" +
                "    )\n" +
                "  )"

        val connectionOption = ConnectionFactoryOptions.builder()
            .option(ConnectionFactoryOptions.DRIVER, "oracle")
            .option(OracleR2dbcOptions.DESCRIPTOR, descriptor)
            .option(ConnectionFactoryOptions.USER, myConfigProperty.database.username)
            .option(ConnectionFactoryOptions.PASSWORD, myConfigProperty.database.password)
            .build()

        val connectionPoolConfig = ConnectionPoolConfiguration
            .builder(ConnectionFactories.get(connectionOption))
            .initialSize(myConfigProperty.database.poolInitialSize)
            .maxSize(myConfigProperty.database.pooMaxSize)
            .maxIdleTime(Duration.ofSeconds(5))
            .validationQuery(myConfigProperty.database.validationQuery)
            .build()

        return ConnectionPool(connectionPoolConfig)
    }

    @Bean
    fun r2dbcEntityTemplate(
        connectionFactory: ConnectionFactory
    ) = R2dbcEntityTemplate(connectionFactory)

    @Bean
    fun transactionManager(connectionFactory: ConnectionFactory): TransactionalOperator {
        return TransactionalOperator.create(R2dbcTransactionManager(connectionFactory))
    }

}

3. build.gradle.kts

项目所有依赖配置

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    application
    id("org.springframework.boot") version "2.7.3"
    id("io.spring.dependency-management") version "1.0.13.RELEASE"
    id("nebula.release") version "16.1.0"
    kotlin("jvm") version "1.6.21"
    kotlin("plugin.spring") version "1.6.21"
}

application {
    applicationDefaultJvmArgs = listOf("-Duser.timezone=UTC+7", "-Dfile.encoding=UTF-8")
}


group = "com.demo"
//version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11

repositories {
    maven(
        uri("https://repo1.maven.org/maven2/")
    )
    maven(
        uri("https://repo.spring.io/plugins-release/")
    )
    maven(
        uri("https://artifactory.wetransform.to/artifactory/libs-release/")
    )
    maven(
        uri("https://repo.spring.io/libs-milestone"),
    )
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-security")
    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
//    implementation("org.springframework.boot:spring-boot-starter-cache")

    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4")
    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-slf4j")

    implementation("org.springframework.boot:spring-boot-starter-data-r2dbc:2.7.3")
//    implementation("com.oracle.database.jdbc:ojdbc11:21.7.0.0")
    implementation("io.r2dbc:r2dbc-pool:0.9.2.RELEASE")
    implementation("com.oracle.database.r2dbc:oracle-r2dbc:0.4.0")

    implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
    implementation("io.jsonwebtoken:jjwt-api:0.11.5")
    runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5")
    runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5")


    implementation("org.ehcache:ehcache:3.10.1")

    implementation("javax.xml:jaxrpc-api:1.1")
    implementation("javax.xml.soap:javax.xml.soap-api:1.4.0")
    implementation("org.apache.axis:axis:1.4")
    implementation("commons-discovery:commons-discovery:0.5")
    implementation("javax.wsdl:com.springsource.javax.wsdl:1.6.1")
    implementation(files("libs/webseal.client-1.0.jar"))

    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("io.projectreactor:reactor-test")
    testImplementation("junit:junit:4.13.2")

    implementation("com.google.zxing:core:3.5.0")
    implementation("org.json:json:20220320")
    implementation("joda-time:joda-time:2.11.1")

}

dependencyManagement {
    imports {
        mavenBom("io.r2dbc:r2dbc-bom:Borca-SR2")
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:2021.0.4")
    }
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "11"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

4. application.yaml

数据库配置

spring:
  webflux:
    base-path: /my-context

server:
  port: 8080

my-config:
  api-profile : DEMO
  database:
    host: 192.168.46.131
    port: 1751
    username: usr_sit
    password: Qwertysd
    service-name: DCNET1DB
    pool-initial-size: 10
    poo-max-size: 20
    pool-max-idle-time: 1m
    validation-query: "SELECT 1 from dual"

可能的原因及优化方案

1. 数据库索引缺失

查询条件包含clientId、isDeleted、startDate、endDate,若表中无对应复合索引,Oracle会走全表扫描,即便只有1条记录也可能因统计信息或表结构问题导致慢查询。

  • 创建复合索引:CREATE INDEX idx_client_id_status_date ON CLIENT (CLIENT_ID, IS_DELETED, START_DATE, END_DATE);
  • 执行EXPLAIN PLAN查看查询执行计划,确认是否命中索引。

2. R2DBC连接池配置不一致

代码中maxIdleTime设为5秒,与yaml配置的pool-max-idle-time: 1m不匹配,导致连接频繁被回收重建,每次查询都需重新建立连接,增加耗时。修正代码:maxIdleTime(Duration.ofMinutes(1))。

  • 开启R2DBC连接池DEBUG日志,观察连接获取、释放频率,确认池化是否正常工作。

3. Oracle R2DBC驱动版本兼容性

当前使用的oracle-r2dbc:0.4.0虽兼容Spring Boot 2.7.3对应的R2DBC Borca-SR2,但建议升级到最新稳定版(如0.4.1),修复已知性能问题。

4. 日期类型转换开销

LocalDate.now()生成的日期绑定到Oracle时可能存在类型转换开销,或Oracle对日期范围查询的处理未优化。

  • 确保实体类日期字段与数据库类型完全匹配;
  • 业务允许的话,直接使用Oracle的SYSDATE函数替代客户端生成的日期,减少绑定转换步骤。

5. 网络延迟问题

检查应用服务器到Oracle数据库的网络连通性,用ping、traceroute测试延迟和丢包情况,远程数据库的网络问题可能是主要耗时原因。


内容的提问来源于stack exchange,提问作者poknovem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:25:30