mysql分页查询报错,及解决

mysql分页查询报错:
前提:
1.每页1000条数据
2.查到57页的时候,就报错了
以下是错误信息:

org.springframework.jdbc.UncategorizedSQLException:
### Error querying database. Cause: java.sql.SQLException:
...省略中间...
received message larger than max (18441058 vs. 16777216)
### The error may exist in sqlmap/RxOrder.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT ...省略中间查询... LIMIT ?,?
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:71)
...省略后面

关于这个错误,网上几乎没有太多可用记录,最初就猜想是分页太深,导致内存满了,毕竟是内存排序,最后找公司同事确认了,就是这个原因

解决方式就是优化sql,避开深度分页

原sql:
select * from table01 where id > 1000000000000 and id < 9000000000000
limit 57000,1000
sql的目的是分页查出所有的数据,但因为分页太深,导致数据库内存爆满,查询就停止了

优化方案1(单步改分步查询):
select id from table01 where id > 1000000000000 and id < 9000000000000
limit 56999,1
第一步,先查出第56999条的id
select * from table01 where id > #{id} and id < 9000000000000
limit 57000,1000
第二步,直接从这个id开始向后拿1000条


优化方案2(子查询):
select id from table01 where 
id > (select id from table01 where id > 1000000000000 and id < 9000000000000
limit 56999,1)
and id < 9000000000000
limit 1000
原理和优化方案1一样,只不过放在一个sql中了,但是数据量大的数据库一般都分库分表,至少也是分片,所以对子查询的支持不是很好,因业务系统而异

优化方案3(分步查询唯一字段,再组装):
select id from table01 where id > 1000000000000 and id < 9000000000000
limit 57000,1000
先查出id的集合list,再遍历这个集合,分别查出每个id对应的数据,再组装起来
这样的好处是将数据库的内存压力变相的转移到服务器,一般服务器还是可以抗住的
但这样的缺点也明显,就是多了层查询,会慢些

优化方案4(缩小粒度):
业务原因,原来分页是以天为最小粒度,每天是个线程,每个线程再查所有
优化的话可以考虑以小时为一个最小粒度,每个小时是一个线程,那么每个小时的数据量就没那么大了,分页也就不会太深了

总结:一切优化的根本目的都是为了避开一次性的大数据量的分页

猜你喜欢

转载自blog.csdn.net/java_zhangshuai/article/details/80807827