关于数据库的坑1

本文介绍了一种因大量参数传递导致的慢SQL问题及其优化方案。通过将IN子查询转换为INNER JOIN并结合UNION ALL操作,显著提升了查询效率。同时探讨了进一步优化的可能性。
部署运行你感兴趣的模型镜像

各位好:

 

  在今天排查磁盘使用率异常时,我们发现一条慢SQL造成大量的物理IO读操作,严重消耗服务器IO资源。

该慢SQL类似于:

SELECTUID,

COUNT(1)AS UID_COUNT

FROMTB_XXXXX

WHEREUID IN(

’XXX’,

’XXX’,

’XXX’,

)

GROUPBY UID

 

应用程序在IN子查询中传入超过22000UID值,整个SQL语句超过45000行,执行时间超过130

 

  从程序角度来优化,应该严格控制IN子查询传入的参数数量,超量的参数会导致MySQL消耗大量CPU资源去进行语法检查和语法分析,且SQL响应时间较长,导致应用长期占有数据库链接无法释放。

 

  从数据库角度来优化,首先可以考虑将IN子查询改换成INNER JOIN操作,IN中的参数可以使用UNION ALL来合并,改换后SQL为:

  SELECT UID,

COUNT(1) AS UID_COUNT

FROM TB_XXXXX AS T2

INNER JOIN(

SELECT ’XXX’AS RID

UNION ALL SELECT ’XXX’

UNION ALL SELECT ’XXX’

)AS T1

ON T1.RID=T2.UID

GROUP BY UID

  改换后的SQL执行时间为1.2秒,执行效率提升约100倍。通过SQL PROFILE发现,该SQL主要99%消耗在UNION ALL SELECT 操作上,因为需要超过22000次的UNION ALL操作,哪是否可以通过字符串拆分来优化UNION ALL操作呢?

 

  首先创建一张辅助表tb001,创建语句为CREATE TABLE `tb001`(`id` int(11) NOT NULL PRIMEY KEY),然后测试插入0到99999的数据。

然后测试字符串拆分效率,SQL为:

SELECT substring_index(substring_index(T2.RIDS,',', T1.ID + 1), ',', -1)AS RID

FROM (

SELECT ',xxx,xxx,xxx,xxx,xxx' AS RIDS

) AS T2

INNER JOIN TB001 T1

ON T1.ID <  (LENGTH(T2.RIDS) - LENGTH(REPLACE(T2.RIDS, ',', ''))+ 1)

当传入的字符串较少(低于20个)时能快速返回,当传入值到650个时需要50毫秒才能返回,当传入值到22000个时需要40+秒才能返回。显然这种字符串拆分方式不够高效,不能解决问题。

总结:当业务使用上面类似场景时,我们建议将IN改为INNER JOIN查询,并尽量控制传入参数的数量,分批次小数据量地查询,以保证不会因为单条SQL影响数据库整体性能。 

 

 


您可能感兴趣的与本文相关的镜像

Qwen3-8B

Qwen3-8B

文本生成
Qwen3

Qwen3 是 Qwen 系列中的最新一代大型语言模型,提供了一整套密集型和专家混合(MoE)模型。基于广泛的训练,Qwen3 在推理、指令执行、代理能力和多语言支持方面取得了突破性进展

在使用 Spring Boot 集成 Elasticsearch 的过程中,开发者常常会遇到一些典型问题,这些问题可能会影响系统的稳定性、性能和功能实现。以下是一些常见的问题及其解决方案: ### 3. 连接失败或超时 在配置 Spring Boot 应用连接 Elasticsearch 时,常见的问题是连接失败或超时。这通常由网络配置错误、Elasticsearch 服务未启动、端口未开放或防火墙限制引起。建议检查 Elasticsearch 服务是否正常运行,并确认配置文件中的主机地址和端口是否正确。此外,应确保网络策略允许应用与 Elasticsearch 之间的通信[^1]。 ### 4. 数据序列化与反序列化异常 Elasticsearch 操作通常涉及将 Java 对象转换为 JSON 格式并存储,或者从 JSON 格式转换回 Java 对象。如果实体类字段与 Elasticsearch 映射不匹配,可能会导致序列化或反序列化失败。为避免此类问题,应确保实体类字段使用正确的注解(如 `@Field`)进行定义,并与 Elasticsearch 索引映射保持一致[^2]。 ### 5. 版本兼容性问题 Spring Boot 提供的 `spring-data-elasticsearch` 模块可能与所使用的 Elasticsearch 版本存在兼容性问题。例如,某些 API 在新版本中已被弃用或移除,导致代码无法正常运行。为避免此类问题,建议在选择 Spring Boot 和 Elasticsearch 版本时,查阅官方文档以确保兼容性[^3]。 ### 6. 性能瓶颈与资源消耗 当数据量较大或查询复杂度较高时,Elasticsearch 可能会出现性能瓶颈。例如,未优化的聚合查询或全索引扫描可能导致响应延迟。为提升性能,可以优化索引结构、合理使用分页、缓存常用查询结果,并避免在高并发场景下执行昂贵的搜索操作[^4]。 ### 7. 依赖配置错误 Spring Boot 项目中需要正确引入 `spring-boot-starter-data-elasticsearch` 或其他相关依赖。如果依赖版本冲突或未正确配置,可能导致应用启动失败。建议使用 Spring Boot 的依赖管理工具(如 Maven 或 Gradle)并参考官方推荐的依赖版本[^1]。 ### 8. 自定义查询实现困难 虽然 Spring Boot 提供了基于方法名的自动查询生成机制,但面对复杂查询时,往往需要自定义查询逻辑。此时,可以使用 `ElasticsearchRestTemplate` 编写原生查询语句,灵活构建查询条件并处理返回结果。 ### 9. 索引管理不当 索引的创建、更新和删除操作如果没有妥善处理,可能导致数据不一致或查询失败。建议在应用启动时使用 `ElasticsearchRestTemplate` 自动创建索引,或在首次运行时手动定义索引结构以确保字段映射正确。 ### 示例代码:使用 ElasticsearchRestTemplate 构建自定义查询 ```java import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.BoolQueryBuilder; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import java.util.List; public class CustomElasticsearchQuery { private final ElasticsearchRestTemplate elasticsearchRestTemplate; public CustomElasticsearchQuery(ElasticsearchRestTemplate elasticsearchRestTemplate) { this.elasticsearchRestTemplate = elasticsearchRestTemplate; } public List<SearchHit<YourEntity>> searchByCustomCriteria(String keyword) { BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery() .should(QueryBuilders.matchQuery("fieldName", keyword)); NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(queryBuilder) .build(); return elasticsearchRestTemplate.search(searchQuery, YourEntity.class); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值