如题重复一下:使用c++,调用mysql api函数,读取mysql大表数据,碰到内存暴涨的问题。
现在了解到的处理方法有:
# 一个是mysqldump,把结果集分批导入到文件中,还没有测试
# 另一个是mysql_use_result(),这是mysql提供的api函数,可能会导致mysql数据库端内存暴涨。测试过程中,读取数据不完全,会漏数据。应该需要调整mysql数据库参数。第二种方法,请示大牛,已经pass。
有可能会使用第一种方法,请教各位网络神人,看看有没有好的建议,望不吝赐教!!!多谢!

解决方案 »

  1.   

    是mysql进程内存暴涨  还是系统内存暴涨
      

  2.   

    to rucypli :
    是c++程序进程占用的内存暴涨,导致系统内存吃紧。
      

  3.   

    看看这个mysql_store_result()
      

  4.   

    mysql_store_result() Retrieves a complete result set to the client
    -----------这个函数,会把mysql表的所有数据一次性读取到程序内存中。而且,数据读取不完,这个函数会一直处于执行中。我测试的时候,看着进程占用内存飙到5g,怕把虚拟内存也占完,只好kill掉进程。mysql程序员手册讲,也只能考虑mysql_use_result。但是,使用过mysql_use_result的朋友应该知道,这个函数不稳定。
    There are two ways for a client to process result sets. One way is to retrieve the entire result set all at once by calling
    mysql_store_result(). This function acquires from the server all the rows returned by the query and stores them in the client.
    The second way is for the client to initiate a row-by-row result set retrieval by calling mysql_use_result(). This function initializes the retrieval, but does not actually get any rows from the server.
      

  5.   

    楼主需要这些大批量数据进行干嘛!说出来方便分析,
    第一种方法是肯定可行的啊!用命令行函数导出来!
    第二种方法,你如果执行读取所有的数据,不如给个limit限制,
    意思就是 你可以先 执行 select count(*)
    得到一个数据
    按需求把它分成N次
    然后一次查询就  limit  1/N 
    然后释放内存,然后再进行查询 当然这是个笨方法,还需要楼主谈谈 自己的需求  然后 供大家分析
      

  6.   

    谢谢小柯。我说下的应用场景:我做的是一个数据交换软件,完成异构数据库之间的数据转储,例如从mysql转储数据到oracle。软件基本完成,测试过程中,发现读取mysql大表时,内存占用很高。
    第一种方法采用mysqldump,应该可以避免程序占用内存飙高的问题,还需要测试。
    第二种方法,你说的意思我理解了,笨但是比较实用。可能需要考虑如何应对动态变化的数据表,比如点击日志表、账号信息表。
    另外,主要想问一下,有没有别的办法或工具,是不是只有沦落到改mysql源码了?
      

  7.   

    # 另一个是mysql_use_result(),这是mysql提供的api函数,可能会导致mysql数据库端内存暴涨。测试过程中,读取数据不完全,会漏数据。应该需要调整mysql数据库参数。
    >>:
    为什么读取数据不完全?既然是转出数据,之前lock table了吗?这个API逐行提取,应该对内存需求会少一些。如果不用此API, 那就只能通过where查询条件限制返回的记录条数来控制内存分配的大小了。
      

  8.   


    mysql_use_result这个函数,我测试过5、6次,每次获取数据都不完全,会漏数据。这个可能和mysql数据库服务端的参数设置有关系,还没有进一步测试。
    测试的数据表,只有一个链接在读取,不会锁表。通过where条件可以限制最大转储行数,这个可能是最终的方法
      

  9.   


    作为标准的API, mysql_use_result不会漏数据的。除非程序写的有问题。
    你说的漏数据,是指记录条数不够? 如何验证?
      

  10.   


    作为标准的API, mysql_use_result不会漏数据的。除非程序写的有问题。
    你说的漏数据,是指记录条数不够? 如何验证?
    测试的数据表:单行最大字节数2k,数据行数:2000多万行
    测试了5、6次,每次获取6000行左右,程序就退出,报错:
    Retrive error: Lost connection to MySQL server during query
    猜测可能是mysql服务端的参数设置问题程序的代码如下,斑竹帮忙瞧瞧吧://执行select查询语句
    res = mysql_query(pOrgMysql, strOrgSql.c_str());
    if (res)
    {
          //记录日志
          return 1;
    }
    //获取结果集
    //result = mysql_store_result(pOrgMysql);
    result = mysql_use_result(pOrgMysql);
    int nResultRemainRows = mysql_num_rows(result); //未转储的剩余行数
    while( row = mysql_fetch_row(result) )
    {//循环遍历结果集
    //获取各个字段长度
    unsigned long *lengths(NULL);
    lengths = mysql_fetch_lengths(result);
    if (NULL == lengths)
    {
                    //记录日志
    return 6;
    }
            //解析结果集中的行数据:row
    }
      

  11.   

    嗯,修改几个参数吧:
    show variables like “%timeout%”;
    重点修改两个timeout参数,在my.cnf/ini文件中:
    wait_timeout=28800
    interactive_timeout=28800
    (28800是默认值,似乎,8小时,可以改成比较大的值)
    另一个更值得怀疑的地方是:
    max_allowed_packet可以参考下边的说明:
    You normally can get the following error codes in this case (which one you get is OS-dependent):
    CR_SERVER_GONE_ERRORThe client couldn't send a question to the server.CR_SERVER_LOSTThe client didn't get an error when writing to the server, but it didn't get a full answer (or any answer) to the question.You can also get these errors if you send a query to the server that is incorrect or too large. If mysqld gets a packet that is too large or out of order, it assumes that something has gone wrong with the client and closes the connection. If you need big queries (for example, if you are working with big BLOB columns), you can increase the query limit by starting mysqld with the -O max_allowed_packet=# option (default 1M). The extra memory is allocated on demand, so mysqld will use more memory only when you issue a big query or when mysqld must return a big result row!可以在配置文件中修改参数值:max_allowed_packet, 设定为一个比较大的值,比如100M左右,然后再看看能传输多少条记录。我怀疑mysql是不是把所有的结果集都在server端缓存起来?如果是那样,可能真的不行。
    不过,实验还是要做的。
    先看看上述三个参数修改以后是否起作用,能起多大作用,尤其是最后一个参数。