首批通过分布式安全可靠测评,为关键业务系统打造
SORT
更新时间:2026-07-19 16:40:56
SORT 算子用于对输入的数据进行排序。
SORT 算子类型
在 OceanBase 数据库中,SORT 算子根据不同的数据分布、查询语义和优化目标,具体表现为不同的形态:
| 算子类型 | 特性说明 | 核心原理 | 适用场景 |
|---|---|---|---|
| SORT | 用于通用的、完整的排序需求。 | 阻塞性排序:必须拿到下层算子的完整结果集后才能开始排序。 | 下层数据无序,或下层数据的有序性无法被当前排序利用时。例如,对没有合适索引的表执行 ORDER BY。 |
| TOP-N SORT | 针对 ORDER BY ... LIMIT N 语句的优化排序,效率更高。
注意
|
堆排序:只需维护一个大小为 N 的堆,无需对所有数据进行全排序,内存和计算开销更小。 | 查询中包含 ORDER BY 和 LIMIT 子句,且优化器判定使用该算子代价更低时。 |
| PARTITION SORT | 作为 MERGE GROUP BY 等算子的预处理阶段,为数据分组合并提供有序输入。 |
预排序:按照后续算子 MERGE GROUP BY 所需的分组键顺序对数据进行排序,以提升合并效率。 |
当优化器选择使用 MERGE GROUP BY 等基于排序的算法时,其下层通常会分配此算子进行预排序。 |
SORT
标准 SORT 算子是最常见的排序算子,当下层数据完全无序且需要完整排序时使用。例如,对没有合适索引的表执行 ORDER BY 时就会生成此算子。
SORT 示例
创建表
tbl1。obclient> CREATE TABLE tbl1(col1 INT, col2 INT);Q1:从表
tbl1中查询col1列的所有值,并按col1降序、col2升序的顺序进行排序,查看该查询的执行计划。obclient> EXPLAIN SELECT col1 FROM tbl1 ORDER BY col1 DESC, col2 ASC;返回结果如下:
+---------------------------------------------------------------------+ | Query Plan | +---------------------------------------------------------------------+ | ================================================= | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------- | | |0 |SORT | |1 |3 | | | |1 |└─TABLE FULL SCAN|TBL1|1 |3 | | | ================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output([TBL1.COL1]), filter(nil), rowset=16 | | sort_keys([TBL1.COL1, DESC], [TBL1.COL2, ASC]) | | 1 - output([TBL1.COL1], [TBL1.COL2]), filter(nil), rowset=16 | | access([TBL1.COL1], [TBL1.COL2]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([TBL1.__pk_increment]), range(MIN ; MAX)always true | +---------------------------------------------------------------------+ 14 rows in set
在 Q1 查询返回结果中,除了 SORT 算子(0 号算子),还展示了以下执行算子:
TABLE FULL SCAN:表示全表扫描。该算子属于TABLE SCAN算子,详细信息参见 TABLE SCAN。
上述 Q1 查询的执行计划展示中的 Outputs & filters 详细列出了 SORT 算子的输出信息如下:
| 信息名称 | 含义 | 示例说明 |
|---|---|---|
| output | 该算子最终输出的列或表达式列表。 | output([TBL1.COL1]) 表示该算子输出的是表 tbl1 中的 col1 列。 |
| filter | 该算子需要应用的过滤条件(谓词)。 | filter(nil) 表示没有需要再额外过滤的行。 |
| rowset | 表示当前算子的向量化大小。 | rowset=16 表示当前算子的向量化大小为 16。 |
| sort_keys | 表示该算子输出数据的排序键和排序方式。
|
sort_keys([TBL1.COL1, DESC], [TBL1.COL2, ASC]) 表示以排序键 TBL1.COL1 列降序和 TBL1.COL2 列升序。 |
TOP-N SORT
在 OceanBase 数据库的 MySQL 模式中,当查询包含 ORDER BY ... LIMIT N 时,优化器可能会将其优化为 TOP-N SORT 算子。该算子采用堆排序算法,只需在内存中维护一个大小为 N 的堆,而无需对所有输入数据进行全排序,因此在内存使用和执行效率上通常优于普通 SORT。
TOP-N SORT 示例
创建表
tbl2。obclient> CREATE TABLE tbl2(col1 INT, col2 INT);在表
tbl2上基于列col1创建索引idx_tbl2。obclient> CREATE INDEX idx_tbl2 ON tbl2(col1);Q2:从表
tbl2中查询所有col1大于 1 的记录,按col1和col2升序排序后,只返回前 10 条结果,查看该查询的执行计划。obclient> EXPLAIN SELECT * FROM tbl2 WHERE col1 > 1 ORDER BY col1, col2 LIMIT 10;返回结果如下:
+-------------------------------------------------------------------------------+ | Query Plan | +-------------------------------------------------------------------------------+ | ============================================================ | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------------ | | |0 |TOP-N SORT | |1 |5 | | | |1 |└─TABLE RANGE SCAN|tbl2(idx_tbl2)|1 |5 | | | ============================================================ | | Outputs & filters: | | ------------------------------------- | | 0 - output([tbl2.col1], [tbl2.col2]), filter(nil), rowset=16 | | sort_keys([tbl2.col1, ASC], [tbl2.col2, ASC]), topn(10), prefix_pos(1) | | 1 - output([tbl2.col1], [tbl2.col2]), filter(nil), rowset=16 | | access([tbl2.__pk_increment], [tbl2.col1], [tbl2.col2]), partitions(p0) | | is_index_back=true, is_global_index=false, | | range_key([tbl2.col1], [tbl2.__pk_increment]), range(1,MAX ; MAX,MAX), | | range_cond([tbl2.col1 > 1]) | +-------------------------------------------------------------------------------+ 15 rows in set
在 Q2 查询返回结果中,除了 TOP-N SORT 算子(0 号算子),还展示了以下执行算子:
TABLE RANGE SCAN:表示范围扫描,会根据给定的查询条件(范围谓词)扫描索引或主表的一段连续范围,返回 0 行或多行数据。该算子属于TABLE SCAN算子,详细信息参见 TABLE SCAN。
上述 Q2 查询的执行计划展示中的 Outputs & filters 详细列出了 TOP-N SORT 算子的输出信息如下:
| 信息名称 | 含义 | 示例说明 |
|---|---|---|
| output | 该算子最终输出的列或表达式列表。 | output([tbl2.col1], [tbl2.col2]) 表示该算子输出的是表 tbl2 中的 col1、col2 列。 |
| filter | 该算子需要应用的过滤条件(谓词)。 | filter(nil) 表示没有需要再额外过滤的行。 |
| rowset | 表示当前算子的向量化大小。 | rowset=16 表示当前算子的向量化大小为 16。 |
| sort_keys | 表示该算子输出数据的排序键和排序方式。
|
sort_keys([tbl2.col1, ASC], [tbl2.col2, ASC]) 表示以排序键 tbl2.col1 列升序和 tbl2.col2 列升序。 |
| topn | 表示需要获取的前 N 行数据量,对应查询中的 LIMIT N。 |
topn(10) 表示此算子只需获取并排序出前 10 条数据。 |
| prefix_pos | 排序列的有序位置。 | prefix_pos(1) 表示下层 TABLE RANGE SCAN 算子利用索引 idx_tbl2 扫描后,数据在 col1 列上已经有序,因此 TOP-N SORT 仅需在 col1 相同的数据组内对 col2 列进行堆排序即可。 |
PARTITION SORT
PARTITION SORT 表示分区排序,其主要目的并非为了最终输出结果的顺序,而是作为 MERGE GROUP BY 算子的预处理阶段。它通过特定的排序方式,将数据预先排列成便于合并分组的形式,从而提升分组聚合的效率。
当查询包含 GROUP BY 但未指定 ORDER BY,且优化器选择了 MERGE GROUP BY(也称为排序分组)作为执行方式时,下层通常会配套一个 PARTITION SORT 来提供有序输入。
PARTITION SORT 示例
创建表
tbl3。obclient> CREATE TABLE tbl3 (col1 INT, col2 INT);Q3:使用 Hint 强制优化器使用
MERGE GROUP BY,对表tbl3按col1分组并计算每组col2的和,同时筛选出总和大于 2 的分组,查看该查询的执行计划。obclient> EXPLAIN SELECT /*+NO_USE_HASH_AGGREGATION*/ col1, SUM(col2) FROM tbl3 GROUP BY col1 HAVING SUM(col2) > 2;返回结果如下:
+--------------------------------------------------------------------------------------------------+ | Query Plan | +--------------------------------------------------------------------------------------------------+ | =================================================== | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | --------------------------------------------------- | | |0 |MERGE GROUP BY | |1 |3 | | | |1 |└─PARTITION SORT | |1 |3 | | | |2 | └─TABLE FULL SCAN|TBL3|1 |3 | | | =================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([TBL3.COL1], [T_FUN_SUM(TBL3.COL2)]), filter([T_FUN_SUM(TBL3.COL2) > 2]), rowset=16 | | group([TBL3.COL1]), agg_func([T_FUN_SUM(TBL3.COL2)]) | | 1 - output([TBL3.COL1], [TBL3.COL2]), filter(nil), rowset=16 | | sort_keys([HASH(TBL3.COL1), ASC], [TBL3.COL1, ASC]) | | 2 - output([TBL3.COL1], [TBL3.COL2]), filter(nil), rowset=16 | | access([TBL3.COL1], [TBL3.COL2]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([TBL3.__pk_increment]), range(MIN ; MAX)always true | +--------------------------------------------------------------------------------------------------+ 17 rows in set
在 Q3 查询返回结果中,除了 PARTITION SORT 算子(1 号算子),还展示了以下执行算子:
MERGE GROUP BY:用于执行使用排序合并算法进行的分组聚合操作。该算子属于GROUP BY算子,详细信息参见 GROUP BY。TABLE FULL SCAN:表示全表扫描。该算子属于TABLE SCAN算子,详细信息参见 TABLE SCAN。
上述 Q3 查询的执行计划展示中的 Outputs & filters 详细列出了 PARTITION SORT 算子的输出信息如下:
| 信息名称 | 含义 | 示例说明 |
|---|---|---|
| output | 该算子最终输出的列或表达式列表。 | output([TBL3.COL1], [TBL3.COL2]) 表示该算子输出的是表 tbl3 中的 col1、col2 列。 |
| filter | 该算子需要应用的过滤条件(谓词)。 | filter(nil) 表示没有需要再额外过滤的行。 |
| rowset | 表示当前算子的向量化大小。 | rowset=16 表示当前算子的向量化大小为 16。 |
| sort_keys | 表示该算子输出数据的排序键和排序方式。
|
sort_keys([HASH(TBL3.COL1), ASC], [TBL3.COL1, ASC]) 表示:
|