解决运行溢出问题

##
- 在查询数据库的时候,由于要查询很大的数据,上百万的级别,往往让出现内存溢出的问题,所以这时候需要分批去取数据库表中的全部数据来进行处理,最简单的方法就是使用分页查询语句:MySQL的LIMIT语句是满足这个要求的。
- 先来了解这个用法和原理:mysql LIMIT 子句用法及原理。
- 使用查询语句的时候,经常要返回前几条或者中间某几行数据, LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。

SELECT * FROM table   LIMIT [offset,] rows | rows OFFSET offset
  • 1

这是两个参数,第一个是偏移量,第二个是数目

select * from table limit 2, 7; // 返回3-9行,偏移7个
select * from table limit 3,1; // 返回第4行
  • 1
  • 2

一个参数

select * from table limit 3; // 返回前3行,默认是0开始。
  • 1
  • 效率:
    mysql中分页都是用的 limit 10000,20这样的方式,这样的下驴是很低的。因为要先扫描1W多行才剔除前面的1W行,返回后面的结果。

第一部分:看一下分页的基本原理:
mysql explain   SELECT *  FROM  message  ORDER BY id DESC LIMIT 10000, 20
 
id: 1
select_type: SIMPLE
table: message
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 10020
Extra:
1 row in set (0.00 sec)
 
  对上面的mysql语句说明:limit 10000,20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行,每次查询需要扫描超过1W行,性能肯定大打折扣。
  增加where语句,缩小范围:
  
  如果LIMIT m,n不可避免的话,要优化效率,只有尽可能的让偏移量m小一下
  

SELECT * FROM table WHERE id >=2500 ORDER BY auto_id asc LIMIT 0,20
  • 1

这句表示从id2500 开始,从0行开始以偏移量20 查询下去。

SELECT * FROM table WHERE auto_id <2500 ORDER BY auto_id desc LIMIT 40,20
  • 1
  • 原理还是一样,记录住当前页id的最大值和最小值,计算跳转页面和当前页相对偏移,由于页面相近,这个偏移量不会很大,这样的话m值相对较小,大大减少扫描的行数。
      
  • 其实传统的limit m,n,相对的偏移一直是第一页,这样的话越翻到后面,效率越差,而上面给出的方法就没有这样的问题。
  • 注意SQL语句里面的ASC和DESC,如果是ASC取出来的结果,显示的时候记得倒置一下。

代码,java

public void getNewsByMysql() {
        Connection conn = null;
        Statement stmt = null;
        try {
            conn = DBHelper.getConn();//获取数据库的连接
            System.out.println(" 实例化Statement对...");
            stmt = conn.createStatement();
            String commentSql;//执行语句
            newsSql = "SELECT news_id, news_website_type, news_title, news_content FROM news WHERE news_id >= 200000";
            int start = 0;//开始位置,从0行开始查询
            int pageSize = 1000;//偏移量
            int numrows =  13224221;//SELECT COUNT( * )  FROM news_comment,这里是总的行数
            int pages = (int)(numrows / pageSize);//根据偏移量计算需要翻多少页
            if (numrows % pageSize > 0){
                pages++;
            }

//循环获取查询语句,这里的处理越到后面就越慢,因为没有处理到where的变化量,我主要是为了解决运行时溢出的问题。
//这个循环表示的是:从id大于105000开始,第0行以1000的偏移量查询下去,直到结束。
            while(pages>0){
                System.out.println(start);
                commentSql = "SELECT news_id, news_comment_content FROM news_comment  WHERE news_id > 105000 ORDER BY news_id DESC limit "+start+","+ pageSize;
                getComments(stmt, commentSql);//这是我的方法,存储相关查询出来的信息
                start+=pageSize;
                pages--; 
            }

//          getNews(stmt, newsSql);

        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//关闭
            try {
                if (stmt != null)
                    stmt.close();
            } catch (SQLException se2) {
                se2.printStackTrace();
            }
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }

        }
        System.out.println("Goodbye!");

    }

猜你喜欢

转载自blog.csdn.net/huangzuhua_8888/article/details/80030869