
本文探讨了oracle jdbc template在处理带有参数的大数据集查询时,可能出现的显著性能下降问题。针对控制台查询快速而程序执行缓慢的现象,文章提出并详细阐述了利用oracle物化视图作为高效解决方案,通过预计算和定时刷新机制,显著提升查询响应速度,并提供了相关实现细节和注意事项。
在使用Spring Boot的JDBC Template与Oracle 19c进行数据交互时,开发者可能会遇到一个令人困惑的性能问题:一个在数据库控制台中执行仅需数百毫秒的复杂查询,当通过JDBC Template并使用参数化查询(如绑定变量)时,响应时间却急剧增加到数分钟,尤其是在处理千万级别的大型数据集时。这种性能差异通常指向了数据库优化器在处理绑定变量时的行为变化,或者是数据倾斜导致的问题。
当SQL查询通过JDBC Template并使用绑定变量执行时,Oracle数据库优化器在生成执行计划时可能会面临挑战。以下是几个常见原因:
针对上述问题,特别是当查询涉及复杂连接且对数据实时性要求不是极高时,物化视图(Materialized View, MV)是一个非常有效的解决方案。物化视图本质上是预先计算并存储查询结果的数据库对象。它将复杂的查询结果固化下来,当应用程序查询物化视图时,实际上是在查询一个已经计算好的表,从而大大减少了实时计算的开销。
物化视图通过以下方式提升性能:
假设我们有如下一个慢查询,它通过CLIENT_EXTRA_INFO和CONTRACT表连接,并基于电话号码、合同状态和标志进行过滤:
SELECT
CLIENT_EXTRA_INFO.CLIENT_NUMBER,
CLIENT_EXTRA_INFO.FULL_NAME
FROM
CONTRACT
JOIN CLIENT_EXTRA_INFO on (CONTRACT.CLIENTID = CLIENT_EXTRA_INFO.ID)
WHERE
CLIENT_EXTRA_INFO.MBPHONE = :phone
and CONTRACT.STATUS = 'ACTIVE'
and CONTRACT.FLAG IN ('2', '5')
FETCH FIRST :row ROWS ONLY;为了优化这个查询,我们可以创建一个物化视图,将核心的连接和过滤操作预先执行。
1. 创建物化视图
首先,我们需要定义一个物化视图,它包含我们查询所需的所有列,并预先执行大部分的过滤条件。由于电话号码:phone是一个动态参数,我们不能直接将其包含在物化视图的WHERE子句中。但我们可以预先处理其他静态过滤条件和连接。
CREATE MATERIALIZED VIEW MV_RETAIL_CUSTOMER_INFO
BUILD IMMEDIATE -- 立即构建,即在创建时填充数据
REFRESH COMPLETE ON DEMAND -- 按需完全刷新
ENABLE QUERY REWRITE -- 允许优化器在查询基表时重写为查询物化视图
AS
SELECT
CEI.CLIENT_NUMBER,
CEI.FULL_NAME,
CEI.MBPHONE -- 将电话号码也包含进来,以便后续过滤
FROM
CONTRACT C
JOIN CLIENT_EXTRA_INFO CEI on (C.CLIENTID = CEI.ID)
WHERE
C.STATUS = 'ACTIVE'
and C.FLAG IN ('2', '5');请注意,MBPHONE字段被包含在物化视图中,以便应用程序可以在查询物化视图时,继续对MBPHONE进行过滤。
2. 设置定时刷新
由于原始问题中提到数据量大且需要每日更新,我们可以设置一个每日刷新的调度任务,确保物化视图的数据保持相对新鲜。
-- 创建一个调度程序来定时刷新物化视图
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'REFRESH_MV_RETAIL_CUSTOMER_JOB',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN DBMS_MVIEW.REFRESH(''MV_RETAIL_CUSTOMER_INFO'', ''C''); END;', -- 'C' 代表 COMPLETE 刷新
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=3', -- 每天凌晨3点刷新
enabled => TRUE,
comments => 'Daily refresh for MV_RETAIL_CUSTOMER_INFO'
);
END;
/3. 修改JDBC Template查询
应用程序中的JDBC Template查询将不再直接操作原始的CONTRACT和CLIENT_EXTRA_INFO表,而是查询新创建的物化视图。
@Override
public ResponsePagingDTO<RetailCustomerDTO> getDuplicateRetailCustomerWithPhoneNumber(DuplicatePhoneNumberRequest request) {
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();
mapSqlParameterSource.addValue("phone", request.getPhoneNumber());
mapSqlParameterSource.addValue("row", request.getSize());
// 查询物化视图
String sql ="SELECT\n" +
" CLIENT_NUMBER,\n" +
" FULL_NAME\n" +
"FROM\n" +
" MV_RETAIL_CUSTOMER_INFO\n" + // 修改为查询物化视图
"WHERE\n" +
" MBPHONE = :phone\n" +
"FETCH FIRST :row ROWS ONLY";
ResponsePagingDTO<RetailCustomerDTO> responsePagingDTO = new ResponsePagingDTO<>();
List<RetailCustomerDTO> retailCustomerDTOS = new ArrayList<>();
// 执行查询
pulseOpsTemplateJdbc.query(sql, mapSqlParameterSource, (result -> {
RetailCustomerDTO retailCustomer = new RetailCustomerDTO();
retailCustomer.setClientNumber(result.getString(ClientConstant.CLIENT_NUM));
retailCustomer.setFullName(result.getString(ClientConstant.FULL_NAME));
retailCustomer.setPhoneNumber(request.getPhoneNumber()); // 电话号码从请求中获取,因为MV中MBPHONE可能不唯一
retailCustomerDTOS.add(retailCustomer);
}));
responsePagingDTO.setData(retailCustomerDTOS);
return responsePagingDTO;
}通过这种方式,查询MV_RETAIL_CUSTOMER_INFO时,Oracle只需要在预计算好的结果集上进行简单的MBPHONE过滤和分页,大大提升了性能。
当Oracle JDBC Template查询在处理大规模数据时出现显著性能瓶颈,尤其是在控制台执行与程序执行之间存在巨大差异时,物化视图提供了一个强大的解决方案。通过将复杂的连接和过滤操作预计算并存储,物化视图能够将查询响应时间从数分钟缩短到数百毫秒。然而,引入物化视图也意味着需要考虑数据新鲜度、存储开销和维护成本。在决定使用物化视图之前,务必仔细评估业务需求和系统资源,并结合执行计划分析来确保其是最佳的优化策略。
以上就是优化Oracle JDBC Template慢查询:利用物化视图提升性能的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号