创建通用的分组索引查询

来源:互联网 发布:ubuntu 命令行 编辑:程序博客网 时间:2024/06/18 11:31

        谷歌地图原理给人印象深刻,JadePool针对百万条、甚至千万条的大数据创建的分组索引查询,就是借鉴了这一做法。

        谷歌地图原理是把巨大的全球地图分割成一张张100px*100px的小图,查找地图时,给用户加载了(N+2)*(N+2)张小图,每次在屏幕上只显示中间N*N张相连的小图,当鼠标拖动时,如向左侧拖动时,屏幕外最左侧一列图片被挤出队列,屏幕外右侧一列图片进入屏幕右侧,新的相邻的一列小图被预加载到右侧屏幕外,如此生生不息,给用户带来了平滑地浏览全球的感觉。

        如果一个表,其中的记录只有几百条、几千条,我们没有必要去费什么心思;如果记录有上万条、甚至千万条,我们必须认真对待。对记录创建分组索引相当于把全球地图分割成一张张小图,在建立了分组索引后,可以按照指定位置准确查询某一组记录

        具体的做法是这样的
                首先,按照顺序或者倒序查询表的第一个主键,通过ResultSet结果,获取主键在查询结果中的位置信息,记录的位置是从1开始计算
                二是对主键索引的位置信息进行分组,默认的步长是1000,如果有1000万条记录将被划分成1万组,会生成1万个索引节点;
                三是通过指定节点查询一组记录,默认情况下通常是1000条记录,不足1000条的则是余下的全部记录。
        此外,JadePool根据分组索引的结果,实现了另外两个方法
                一是通过指定位置开始,查询一组指定长度的记录;
                二是通过指定位置查询一条记录。

        ProcessVO调用底层的核心方法private IndexNode[] _indexNodes(String tableName, boolean rebuildIndexNodes) throws SQLException创建表的分组索引,针对主键创建的分组索引信息保存在DbCenter有限多列模式的一个实例中。DbCenter的实例管理了一组Table对象。
        在Table类中,有一个IndexNode[] indexNodes数组,它保存着每一个表的主键分组索引信息。使用默认步长1000,每增加1000条记录创建一个节点,最后一个节点保存最后一条记录信息,每个节点记录表的第一个主键值以及按该键顺序查询结果的行数。默认的步长可以通过ProcessVO的public void setIndexNodesStepLength(int indexStepLength)方法修改。
        IndexNode类有两个属性,第一个主键值firstKeyValue和行数row。

        private IndexNode[] _indexNodes(String tableName, boolean rebuildIndexNodes) throws SQLException源代码

    /**     * 创建表的索引节点数组<br/>     * 使用默认步长1000,每增加1000条记录创建一个节点,最后一个节点保存最后一条记录信息,每个节点记录表的第一个主键值以及按该键顺序查询结果的行数<br/>     *     * @param tableName 表名     * @param rebuildIndexNodes 是否无条件重建     * @return 返回IndexNode数组     * @throws SQLException     */    private IndexNode[] _indexNodes(String tableName, boolean rebuildIndexNodes) throws SQLException {        Table table = db.getTable(tableName);        String key = db.getFields(tableName)[0];        if (db.getKeys(tableName).length > 0) {            key = db.getKeys(tableName)[0];        }        int length = (int) this.queryCount(tableName);        int nodeNums = (int) Math.ceil((double) length / (double) indexStepLength);        IndexNode[] nodes = db.getTable(tableName).getIndexNodes();        if (nodes == null) {            nodes = new IndexNode[nodeNums];        } else if (nodes.length == 0) {            nodes = new IndexNode[nodeNums];        }        int countInNodes = 0;        if (nodes[nodes.length - 1] != null) {//======= ====            countInNodes = nodes[nodes.length - 1].getRow();//最后一个节点保存了记录总长度(总行数)信息        }        boolean b = false;        if (table.getIndexStepLength() != indexStepLength) {            b = true;            table.setIndexStepLength(indexStepLength);        } else if (rebuildIndexNodes) {            b = true;        } else if (countInNodes == 0) {//无条件重新建立索引            b = true;        } else if (length > countInNodes) {            b = true;        }        if (b) {            String querySql = "select " + key + " from " + tableName + " order by " + key;            stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);//创建不敏感的可滚动结果集            rs = stmt.executeQuery(querySql);            nodes = new IndexNode[nodeNums];            int row = indexStepLength;            for (int i = 0; i < nodes.length - 1; i++) {                rs.absolute(row);                nodes[i] = new IndexNode();                nodes[i].setFirstKeyValue(rs.getObject(key));                nodes[i].setRow(rs.getRow());//"第一个关键字段的值对应的行号"                row += indexStepLength;            }            rs.last();            nodes[nodes.length - 1] = new IndexNode();            nodes[nodes.length - 1].setFirstKeyValue(rs.getObject(key));            nodes[nodes.length - 1].setRow(rs.getRow());//"第一个关键字段的值对应的行号"            db.getTable(tableName).setIndexNodes(nodes);        }        rs.close();        stmt.close();        return nodes;    }

        public List indexByIndexNodes(String tableName, String[] fields, int position_of_indexNodes, boolean asc, boolean rebuildIndexNodes) throws SQLException源代码

    /**     * 索引查询多条记录<br/> 根据已经建立的索引节点数组查询     * 返回的记录是当前节点的行数减前一节点的行数,即:默认的步长内的记录数,通常是1000。<br/>     * 默认步长可以调用pvo.setIndexNodesStepLength(indexStepLength)方法重新设置<br/>     * 可用于大数据分组分页查询     *     * @param tableName 表名     * @param fields 待查询的字段     * @param position_of_indexNodes     * 取第position_of_indexNodes位已建立的节点,取值[0,nodes.length - 1]     * @param asc 排列顺序,true顺序,false逆序     * @param rebuildIndexNodes 在查询前是否重新创建索引数组     * @return 返回List<Map>类型的结果     * @throws SQLException     */    public List indexByIndexNodes(String tableName, String[] fields, int position_of_indexNodes, boolean asc, boolean rebuildIndexNodes) throws SQLException {        String key = db.getFields(tableName)[0];        if (db.getKeys(tableName).length > 0) {            key = db.getKeys(tableName)[0];        }        int step_old = db.getTable(tableName).getIndexStepLength();        if (this.indexStepLength != step_old) {            rebuildIndexNodes = true;        }//步长发生变化时,必须重建        IndexNode[] nodes = _indexNodes(tableName, rebuildIndexNodes);        List<Map> list = new ArrayList();        if (position_of_indexNodes < 0 || position_of_indexNodes >= (nodes.length - 1)) {            return list;//超出范围        }        Field f = db.getField(tableName, key);        String sort = "asc";        if (!asc) {            sort = "desc";        }        String sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + "<=" + nodes[position_of_indexNodes].getFirstKeyValue() + " order by " + key + " " + sort;        if (f.getTypeClassName().equals("java.lang.String")) {            sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + "<='" + nodes[position_of_indexNodes].getFirstKeyValue() + "' order by " + key + " " + sort;        }        if (position_of_indexNodes > 0 && position_of_indexNodes <= (nodes.length - 1)) {            sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + ">" + nodes[position_of_indexNodes - 1].getFirstKeyValue() + " and " + key + "<=" + nodes[position_of_indexNodes].getFirstKeyValue() + " order by " + key + " " + sort;            if (f.getTypeClassName().equals("java.lang.String")) {                sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + ">'" + nodes[position_of_indexNodes - 1].getFirstKeyValue() + "'and " + key + "<='" + nodes[position_of_indexNodes].getFirstKeyValue() + "' order by " + key + " " + sort;            }        }        db.getTable(tableName).setPosition_of_indexNodes(position_of_indexNodes);//保存本次查询的位置信息        list = this.query(sql);        return list;    }

分组索引查询范例:
/** 假设表tableName中含有100万条记录,按每组1000条记录分组,查找第99组记录[索引号98]*/                     Jade j = new Jade();List<Map> v = j.indexByIndexNodes(tableName, new String[]{fieldName1, fieldName2, fieldName3}, 98, false降序, false不重新创建索引数组);j.commit();

        JadePool创建的分组索引不同于在数据库中创建的索引,按照我手头一部《SQL Server 2008实战》(人民邮电出版社)一书的说法,在数据库中创建索引可以有效地提高查询的效率,但是会带来一些副作用,它会扰动数据存储的物理结构,会影响插入、更新操作JadePool针对主键创建的分组索引信息是保存在DbCenter有限多列模式的一个实例中,它不会扰动数据存储。用户可以使用分组索引信息实现精准的数据查询,从而提高了数据库的查询效率。JadePool这种做法至少在理论上是对的,在大数据查询上能否有效有待实践的检验。

        另外两个方法与indexByIndexNodes大致相同。

        public List indexByRow(String tableName, String[] fields, int row_in_table, int length, boolean asc) throws SQLException 源代码

    /**     * 索引查询多条记录     *     * @param tableName 表名     * @param fields 待查询的字段     * @param row_in_table 从该行开始,取值[1,记录总长度],出界位置返回0长度List<Map>结果     * @param length 查询长度,row_in_table后记录数少于length,则返回其后的全部记录     * @param asc 排列顺序,true顺序,false逆序     * @return 返回List<Map>类型的结果     * @throws SQLException     */    public List indexByRow(String tableName, String[] fields, int row_in_table, int length, boolean asc) throws SQLException {        String key = db.getFields(tableName)[0];        if (db.getKeys(tableName).length > 0) {            key = db.getKeys(tableName)[0];        }        List<Map> list = new ArrayList();        IndexNode[] nodes = _indexNodeTwo(tableName, row_in_table, length);        Field f = db.getField(tableName, key);        String sort = "asc";        if (!asc) {            sort = "desc";        }        String sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + ">=" + nodes[0].getFirstKeyValue() + " and  " + key + "<=" + nodes[1].getFirstKeyValue() + " order by " + key + " " + sort;        if (f.getTypeClassName().equals("java.lang.String")) {            sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + ">='" + nodes[0].getFirstKeyValue() + "' and  " + key + "<='" + nodes[1].getFirstKeyValue() + "' order by " + key + " " + sort;        }        list = this.query(sql);        return list;    }

        public Map indexByRow(String tableName, String[] fields, int row_in_table) throws SQLException源代码

    /**     * 索引查询一条记录     *     * @param tableName 表名     * @param fields 待查询的字段     * @param row_in_table 从该行开始,取值[1,记录总长度],出界位置返回0长度List<Map>结果     * @return 返回List<Map>类型的结果     * @throws SQLException     */    public Map indexByRow(String tableName, String[] fields, int row_in_table) throws SQLException {        String key = db.getFields(tableName)[0];        if (db.getKeys(tableName).length > 0) {            key = db.getKeys(tableName)[0];        }        IndexNode nodes = _indexNodeOne(tableName, row_in_table);        Field f = db.getField(tableName, key);        String sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + "=" + nodes.getFirstKeyValue();        if (f.getTypeClassName().equals("java.lang.String")) {            sql = "select " + tool.arryToString(fields, ",") + " from  " + tableName + " where " + key + " like '" + nodes.getFirstKeyValue() + "'";        }        Map m = this.queryOne(sql);        return m;    }

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 高帮足球鞋松了怎么办 橡筋裤头太紧了怎么办 内增高鞋跟太高怎么办 电脑增高架高了怎么办 银行取钱走后回来说少了怎么办 运动t桖太大了怎么办 袖口松紧太紧了怎么办 衣服穿着就皱了怎么办 麻料的衣服很皱怎么办 麻料衣服皱了怎么办 棉麻裤子皱了怎么办 裙子屁股坐皱了怎么办 真丝衣服洗皱了怎么办 粘纤的衣服皱了怎么办 硅胶手机壳粘灰怎么办 橡筋裤子买大了怎么办 橡筋裤子腰小了怎么办 地垫粘瓷砖上怎么办 汽车围裙锈透了怎么办 万能胶水沾到手上怎么办 圆领体恤领口容易皱怎么办 上衣剪了个洞怎么办 上衣破了个洞怎么办 鸟屎腐蚀车漆怎么办 毛风衣叠久了怎么办 黑色的衣服沾毛怎么办 雪纺裙子弄上油怎么办 内衣买小了怎么办妙招 长裤衬衫裙邹了怎么办 100棉衬衣皱了怎么办? 短袖t恤袖口大了怎么办 短袖底下卷边了怎么办 棉质短袖衫缩水怎么办 纯棉t恤缩水了怎么办 t恤缩水变小了怎么办 衣服掉在雨棚上怎么办 车衣密码锁忘记密码怎么办 衣服的铁拉链弯怎么办 去旅行衣服皱了怎么办 衣服抽绳出来了怎么办 裤子的绑带掉了怎么办