这个坑很深沉,官方文档太简短了。
这个坑是由:select语句引起的。
也就是声明游标时的查询语句,如下:
拉开序幕:
这是一张很简单的表test,id是row key,一共15条数据。
接着,我们使用游标遍历这个表数据。
public static void main(String[] args) throws SQLException {
long start = System.currentTimeMillis();
// 获得连接资源
Connection con = PhoenixUtils.getConnection();
ResultSet rset = null;
// 游标语句
PreparedStatement statement = con.prepareStatement("DECLARE empCursor CURSOR FOR select * from test");
statement.execute();
// 开启游标
statement = con.prepareStatement("OPEN empCursor");
statement.execute();
int countTotal=0;
// 一次拿2条
statement = con.prepareStatement("FETCH NEXT 2 ROWS FROM empCursor");
rset = statement.executeQuery();
while (rset.next()){
countTotal++;
System.out.println(rset.getString("id"));
}
System.out.println("countTotal="+countTotal);
// 关闭游标
statement = con.prepareStatement("CLOSE empCursor");
statement.execute();
// 释放资源
PhoenixUtils.colseResource(con,statement,rset);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) +" ms");
}
执行结果:
拿2条数据,没错只拿到了两条数据!这个逻辑很正常。
重点来了,我改了一下声明游标的sql。
DECLARE empCursor CURSOR FOR select * from test
改为:
DECLARE empCursor CURSOR FOR select id from test
只是把查询内容由*号,改为了id,我们继续执行一次,来看看结果。
执行结果:
What???
说好了只拿2条,怎么拿到了16条?
什么什么test表一共就15条数据,怎么会有16条??这是假的吧。冷静、冷静。
查下test表的索引有哪些
!indexes test
果然有个二级索引表,接着查下二级索引表内容。
果然有16条数据,执行以下计划看看。
select id from test; 直接走的二级索引表。
这下大概明白问题所在了,原来test是不可变表。出现索引表与原始表,数据不一致,也就正常了。
为了证实我的想法,再修改sql测试下改为:
select age from test; -- age字段不会走二级索引表
执行结果:
结论:
申明游标的语句
1、数据如果来自索引表。那么会一次性都给到结果集。即使你指定了取的行数。
2、SQL不走索引表,数据来自原表。则会按照你指定的行数,返回结果集。如果你需要遍历全部数据,去统计结果。那么需要在外部增加循环。类似递归。
https://mp.csdn.net/postedit/84875099 不走二级索引表可以参考这个循环。
注意:声明游标的SQL走,二级索引 和 不走二级索引的差别!!!!
(如果是不可变表,那么遍历数据一定不能取索引表,否则统计结果是不正确的。)
当然,走表自身的row key是没有问题的。我们还可以使用hint /*+NO_INDEX*/ 来处理,数据遍历二级索引表的情况。
注意:一定要用explain查看sql
END,闭幕--