Oracle 18c查询为何不按数据插入顺序返回结果行
Oracle 18c:
我有1000行测试数据,建表及测试数据插入语句如下:
create table lines (id number, shape sdo_geometry); begin insert into lines (id, shape) values (1, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(574360, 4767080, 574200, 4766980))); insert into lines (id, shape) values (2, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(573650, 4769050, 573580, 4768870))); insert into lines (id, shape) values (3, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(574290, 4767090, 574200, 4767070))); insert into lines (id, shape) values (4, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(571430, 4768160, 571260, 4768040))); insert into lines (id, shape) values (5, sdo_geometry(2002, 26917, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(571500, 4769030, 571350, 4768930))); -- 剩余995行测试数据省略 end; /
执行如下查询语句时,返回的数据没有按照插入顺序排列:
select id, sdo_util.to_wktgeometry(shape) from lines
我原本预期ID为1的行会作为第一行返回,后续行按ID递增顺序排列。在本地部署的SQL Developer环境、在线测试环境分别执行该查询,得到的排序结果也不一致。
我知晓实际生产场景中不应依赖表的默认行返回顺序,若对结果排序有要求需要使用order by子句指定排序规则,但仍想了解:为何数据不会按照插入顺序返回?该现象的底层机制是什么?
问题解答
Oracle(以及绝大多数主流关系型数据库)不保证无ORDER BY子句的查询按插入顺序返回结果,这是设计层面的机制决定的,不是异常,核心原因有三点:
- 堆表的无序存储特性
你创建的普通表默认是堆组织表,“堆”的核心逻辑就是数据无序存放:插入数据时,数据库只会优先寻找当前可用的空闲空间写入,不会为新插入的数据专门维护连续的、和插入顺序一致的存储位置。如果之前的删改操作留下了空闲块,新数据甚至可能写到物理位置比旧数据更靠前的块中。你批量插入1000行数据时,数据库会调度多个进程并行写入,不同行可能被分配到不同数据块、不同磁盘分区,从物理存储层面就不存在和插入顺序一致的排列。 - 全表扫描的读取逻辑不绑定插入顺序
不带ORDER BY的查询走全表扫描时,返回顺序由两个因素决定:一是数据块在磁盘上的物理存储顺序,二是数据库缓存(Buffer Cache)中已缓存块的读取优先级。已经缓存在内存中的数据块会被优先返回,不需要等待磁盘块按固定顺序读取;并行查询、行迁移、行链接、分区裁剪等机制,都会进一步打乱结果返回顺序。不同环境的缓存状态、存储配置、参数设置存在差异,自然会出现你观察到的“两个环境返回顺序完全不同”的现象。 - “按插入顺序返回”只是偶然巧合
你可能在某些场景下观察到无ORDER BY的查询刚好按插入顺序返回,这只是特殊条件下的巧合:比如刚创建的空表首次批量插入数据时,刚好所有数据被写入连续的空闲块,且查询时没有命中缓存、未开启并行,才会刚好匹配插入顺序。这个顺序没有任何稳定性保障,只要数据库做过空间回收、执行过增删改操作、重启过实例、调整过执行参数,返回顺序随时会变化。
补充说明:就算查询加了
ORDER BY,如果指定的排序字段存在重复值,重复值之间的返回顺序Oracle同样不做保障;只有排序字段可以唯一标识每一行时,查询结果的顺序才是稳定可预期的。
内容的提问来源于stack exchange,提问作者User1974
相关产品推荐
相关产品推荐

