我有一个百万数量级的表,row_id是主键
select * from history a order by a.row_id desc;
这样执行查询结果非常的慢,查看执行计划,用到了全表扫描。
但是执行以下查询 ,简称sql2
select * from (
select a.row_id,rownum rn from history a order by a.row_id desc )t
where rownum<20;
速度非常的快,查看执行计划,是直接用到了主键索引。
通过select max(row_id) from history;
对对上结果进行了验证,发现查询结果是没问题的。
我想问的是,rownum在执行过程中究竟是进行了怎样的优化?
按照我的理解,sql2中的查询应该是对子查询内部的所有数据查询出来,然后进行排序,然后将结果集再取前20行。不然查询结果怎么会是正确排序的结果呢。
请大佬们赐教。
------------------------------------------------------------补充
我再次进行了测试
select * from (
select a.row_id,rownum rn from history a
where a.create_date >sysdate -30
order by a.row_id desc )t
where rownum<20;
create_date是普通索引
select * from (
select a.row_id,rownum rn from history a
where a.row_id >10
order by a.create_date desc )t
where rownum<20;
这第二个sql也是光速返回结果。
我的猜测是由于主键row_id是顺序存储的,所以当没有查询条件的时候,cbo会直接从索引开头位置取20行。当查询条件为主键时,同理。查询条件为普通索引时,就需要先进行查询再排序了,这样效率就低了。
使用索引是查询优化的一种,一般为优化查询都会在必要列中添加索引
所以当索引为主键时会进行唯一性扫描,而当索引为普通索引会自动进行范围扫描,从而改变查询效率