MySQL 流式查询

大数据量查询容易OOM?试试MySQL流式查询

一、前言

  程序访问MySQL数据库时,当查询出来的数据量特别大时,数据库驱动把加载到的数据全部加载到内存里,就有可能会导致内存溢出(OOM)。其实在MySQL数据库中提供了流式查询,允许把符合条件的数据分批一部分一部分地加载到内存中,可以有效避免OOM;本文主要介绍如何使用流式查询并对比普通查询进行性能测试。

二、JDBC实现流式查询

使用JDBC的PreparedStatement/Statement的setFetchSize方法设置为 Integer.MIN_VALUE或使用方法Statement.enableStreamingResults()可以实现流式查询,在执行ResultSet.next()方法时,会通过数据库连接一条一条的返回,这样也不会大量占用客户端的内存。

public int execute(String sql, boolean isStreamQuery) throws SQLException {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    int count = 0;
    try {
        //获取数据库连接
        conn = getConnection();
        if (isStreamQuery) {
            //设置流式查询参数
            stmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            stmt.setFetchSize(Integer.MIN_VALUE);
        } else {
            //普通查询
            stmt = conn.prepareStatement(sql);
        }

        //执行查询获取结果
        rs = stmt.executeQuery();
        //遍历结果
        while(rs.next()){
            System.out.println(rs.getString(1));
            count++;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(stmt, rs, conn);
    }
    return count;
}

PS:上面的例子中通过参数 isStreamQuery 来切换流式查询与普通查询,用于下面做测试对比。

三、性能测试

创建一张测试表 my_test 进行测试,总数据量为 27w 条,分别使用以下4个测试用例进行测试:

  1. 大数据量普通查询(27w条)
  2. 大数据量流式查询(27w条)
  3. 小数据量普通查询(10条)
  4. 小数据量流式查询(10条)

3.1. 测试大数据量普通查询

@Test
public void testCommonBigData() throws SQLException {
    String sql = "select * from my_test";
    testExecute(sql, false);
}
3.1.1. 查询耗时

27w 数据量用时 38 秒

file

3.1.2. 内存占用情况

使用将近 1G 内存 img

3.2. 测试大数据量流式查询

@Test
public void testStreamBigData() throws SQLException {
    String sql = "select * from my_test";
    testExecute(sql, true);
}
3.2.1. 查询耗时

27w 数据量用时 37 秒
img

3.2.2. 内存占用情况

由于是分批获取,所以内存在30-270m波动 img

3.3. 测试小数据量普通查询

@Test
public void testCommonSmallData() throws SQLException {
    String sql = "select * from my_test limit 100000, 10";
    testExecute(sql, false);
}
3.3.1. 查询耗时

10 条数据量用时 1 秒
img

3.4. 测试小数据量流式查询

@Test
public void testStreamSmallData() throws SQLException {
    String sql = "select * from my_test limit 100000, 10";
    testExecute(sql, true);
}
3.4.1. 查询耗时

10 条数据量用时 1 秒
img

四、总结

MySQL流式查询对于内存占用方面的优化还是比较明显的,但是对于查询速度的影响较小,主要用于解决大数据量查询时的内存占用多的场景。

DEMO地址

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于MySQL查询经常断开的问题,有几个可能的原因和解决方法。首先,查询是指在查询结果集太大无法一次性获取完整结果时,可以使用逐行获取结果,这对于大型数据集或者网络延迟较高的情况非常有用。 1. 网络连接问题:断开可能是由于网络连接不稳定导致的。你可以检查网络连接是否正常,尝试使用其他工具或方连接MySQL,看是否存在相同的问题。如果是网络问题,可以尝试增加连接超时时间或者优化网络环境。 2. 查询时间过长:如果查询执行时间较长,可能会导致连接断开。可以尝试优化查询语句、添加索引、分批次获取结果等方来缩短查询时间。另外,可以适当调整MySQL的配置参数,例如增加max_allowed_packet参数的值,以允许更大的数据包传输。 3. 服务器配置限制:有些服务器可能对查询结果集的大小有限制,超过限制会导致连接断开。你可以查看服务器配置文件中相关参数的设置,例如max_allowed_packet、max_connections等,适当调整这些参数的值。 4. MySQL版本问题:某些MySQL版本可能存在与查询相关的bug或者限制。你可以尝试升级MySQL到最新的稳定版本,或者查阅官方文档、社区论坛等了解是否有相关的已知问题和解决方法。 希望以上解决方法对你有所帮助!如果问题仍然存在,请提供更多细节和错误信息,我将尽力协助你解决。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值