Mysql数据库10万条数据多表联合查询速度过慢解决方案

点我,查看原文

问题描述

今天在写项目时发现之前好好的查询接口突然挂了🤔,检查后发现原来是有人往数据里新增了10万条数据,以至于Mysql语句执行的特别慢就不行了。

原因

原因也简单这个接口原本是一张组织机构表关联区域表、组织标准类型表、币种表、行业分类标准表等多张表的联合查询。按照下图的写法已经写了limit分页只取10条,可Mysql确实会很认真的先帮你把10万条数据的外键关系先建立起来,然后在拿最上面的10条给你。emmmmm……🐴🥚
在这里插入图片描述
所以数据量一旦多起来后,Mysql的遍历查询结果就不尽人意,10万条语句这一次查询差不多就要3分多钟。

解决思路

解决思路也很简单,我目前想到的做法就是在Mysql与关联表进行关联操作之前,先通过分页、查询条件、约束等减小它的范围。简单点说就是,先查再建视图

实际步骤

直接放优化后的语句叭
在这里插入图片描述

效果展示

最后再看看优化后的速度
在这里插入图片描述
0.083秒。恩……真香!🎉

<think>好的,用户问的是如何处理批量保存数据过大的问题,特别是数据库性能优化和批量插入限制。首先,我需要回忆之前学过的相关知识,以及参考提供的引用内容。 根据引用[2],批量插入性能优化很重要,尤其是在数据量大的情况下。引用[3]提到了批量插入的具体方法,比如JDBC的批量处理配置,还有分页处理数据。用户可能遇到的问题可能包括插入时间过长、数据库负载高,甚至事务超时等。 首先,我需要考虑分批次插入。用户提到“批量保存数据过大”,所以一次性插入大量数据肯定不行,分批次处理是关键。比如,每1000条提交一次,这样可以减少事务的大小,避免锁和内存溢出。引用[3]里也提到了批量插入的参数配置,比如rewriteBatchedStatements参数,这个对MySQL特别有效。 然后是使用批量处理API,比如JDBC的addBatch和executeBatch,这样能减少网络开销,提升效率。同时,ORM框架如MyBatis的foreach标签需要注意参数数量,过的参数会导致SQL语句过长,可能需要调整数据库的max_allowed_packet设置,这点在引用[3]的JDBC配置里提到过。 接下来是禁用索引和约束。在插入前暂时关闭索引和外键检查,插入后再重建,这对大量数据插入很有效。但要注意,这可能会影响其他操作,需要评估业务场景是否允许。 事务管理方面,自动提交会频繁刷盘,改为手动提交,分批提交事务,可以降低I/O压力。引用[1]提到硬件和数据库配置优化,比如SSD和内存,虽然用户可能无法直接改变硬件,但可以建议调整innodb_buffer_pool_size等参数。 另外,使用LOAD DATA INFILE或者批量插入工具,比如MySQL的这个命令,比普通INSERT快很,适合极端情况。但可能需要文件导出,用户的应用是否支持需要确认。 还有,调整数据库参数,比如增大max_allowed_packet,调整JDBC的批量大小,这些在引用[3]都有例子。比如,设置useServerPrepStmts和cachePrepStmts可以提升预处理语句的效率。 监控和分析性能也很重要,引用[1]提到持续监控,用户可能需要使用慢查询日志或监控工具找出瓶颈。 潜在的问题需要考虑,比如分批次的大小选择,太大可能还是慢,太小则增加次数。还有ORM框架的批量操作支持情况,可能需要原生JDBC。另外,高并发下的锁竞争,可能需要选择低峰期执行批量插入。 总结起来,步骤应该是分批次处理、使用批量API、优化数据库配置、禁用索引/约束、合理事务管理,以及可能的工具使用。需要把这些点组织清晰,给出具体例子和参数设置,让用户能一步步操作。同时,结合引用中的内容,比如引用[3]中的JDBC配置和分页方法,来支持建议的可行性。</think>### 如何优化批量保存数据过大的问题? 处理批量保存数据过大时的性能问题,需从**数据库配置**、**插入策略**、**代码优化**和**硬件资源**四方面综合优化。以下是具体解决方案: --- ### 一、分批次插入(核心优化) 1. **限制单次插入量** - 将数据拆分为个小批次(如每批1000条),避免单次事务过大导致内存溢出或锁。 - 示例代码(Java): ```java int batchSize = 1000; for (int i = 0; i < dataList.size(); i += batchSize) { List<Data> subList = dataList.subList(i, Math.min(i + batchSize, dataList.size())); jdbcTemplate.batchUpdate("INSERT INTO table (col1, col2) VALUES (?, ?)", subList); } ``` - 分批次可减少事务日志刷盘频率,降低I/O压力[^2][^3]。 2. **动态调整批次大小** - 根据数据库响应时间和硬件性能动态调整批次大小(如500~5000条),避免固定值导致性能波动。 --- ### 二、使用批量处理API 1. **JDBC批量操作** - 启用JDBC批量处理参数(如MySQL的`rewriteBatchedStatements=true`),合并次插入为单次网络请求。 - 配置示例(JDBC URL): ``` jdbc:mysql://host:3306/db?rewriteBatchedStatements=true&useServerPrepStmts=true&cachePrepStmts=true ``` - 此配置可提升批量插入速度2~10倍。 2. **ORM框架优化** - MyBatis中避免使用`<foreach>`拼接过长SQL,改用`BATCH`执行模式: ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO table (col1, col2) VALUES <foreach collection="list" item="item" separator=","> (#{item.col1}, #{item.col2}) </foreach> </insert> ``` - 注意:单条SQL长度需小于`max_allowed_packet`(默认4MB)。 --- ### 三、数据库配置优化 1. **临时禁用索引和约束** - 插入前关闭索引更新和外键检查: ```sql ALTER TABLE table_name DISABLE KEYS; SET FOREIGN_KEY_CHECKS=0; ``` - 插入完成后重建索引: ```sql ALTER TABLE table_name ENABLE KEYS; SET FOREIGN_KEY_CHECKS=1; ``` - 此方法可减少插入时的索引维护开销。 2. **调整事务提交策略** - 关闭自动提交(`autocommit=0`),每批次提交一次事务,减少日志刷盘次数。 3. **关键参数调优** - 增大`innodb_buffer_pool_size`(占用内存70%~80%) - 调整`max_allowed_packet`(匹配批次数据大小) - 设置`innodb_flush_log_at_trx_commit=2`(批量插入期间降低日志持久化强度) --- ### 四、替代方案 1. **文件导入工具** - 使用`LOAD DATA INFILE`(MySQL)或`COPY`(PostgreSQL)直接导入CSV文件,速度比INSERT快10~100倍。 ```sql LOAD DATA INFILE '/path/data.csv' INTO TABLE table FIELDS TERMINATED BY ','; ``` 2. **异步写入** - 将数据写入消息队列(如Kafka),由消费者异步批量插入,避免阻塞主业务。 --- ### 五、监控与验证 1. **性能分析工具** - 使用`SHOW PROCESSLIST`监控数据库线程状态 - 通过慢查询日志(`slow_query_log`)定位瓶颈语句 2. **压力测试** - 逐步增加批次大小,观察吞吐量和资源占用曲线,找到最优值。 --- ### 注意事项 - **避免长事务**:单批次操作时间不宜超过30秒,防止锁竞争。 - **错误回滚**:需实现失败批次的重试机制。 - **资源隔离**:生产环境中建议使用读写分离或专用从库执行批量任务。 通过上述优化,可显著降低批量插入时间。例如某案例中,10万条数据插入时间从120秒优化至3秒[^3]。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值