ORDER BY 子句包含:
- 表达式列表,例如
ORDER BY visits, search_phrase; - 引用
SELECT子句中列的数字列表,例如ORDER BY 2, 1;或者 ALL,表示SELECT子句中的所有列,例如ORDER BY ALL。
ALL 排序,请将设置 enable_order_by_all 设为 0。
ORDER BY 子句可以带有 DESC (降序) 或 ASC (升序) 修饰符,用于指定排序方向。
除非显式指定排序顺序,否则默认使用 ASC。
排序方向仅适用于单个表达式,而不是整个列表,例如 ORDER BY Visits DESC, SearchPhrase。
此外,排序区分大小写。
如果排序表达式的值相同,这些行将以任意且非确定性的顺序返回。
如果在 SELECT 语句中省略 ORDER BY 子句,行的顺序同样是任意且非确定性的。
特殊值的排序
NaN 和 NULL 的排序顺序,有两种方式:
- 默认情况下,或使用
NULLS LAST修饰符时:先是普通值,然后是NaN,最后是NULL。 - 使用
NULLS FIRST修饰符时:先是NULL,然后是NaN,最后是其他值。
示例
SELECT * FROM t_null_nan ORDER BY y NULLS FIRST,即可得到:
排序规则支持
ORDER BY SearchPhrase COLLATE 'tr' —— 使用土耳其字母表按关键字升序排序,不区分大小写,并假定字符串采用 UTF-8 编码。ORDER BY 中的每个 表达式 都可以单独指定或不指定 COLLATE。如果指定了 ASC 或 DESC,则 COLLATE 应写在其后。使用 COLLATE 时,排序始终不区分大小写。
LowCardinality、Nullable、Array 和 Tuple 支持 COLLATE。
我们仅建议将 COLLATE 用于少量行的最终排序,因为使用 COLLATE 排序的效率低于普通的按字节排序。
排序规则示例
Query
Response
Query
Response
Query
Response
Query
Response
Response
Query
Response
实现细节
ORDER BY 之外还指定了足够小的 LIMIT,内存占用就会更少。否则,排序消耗的内存量与待排序数据量成正比。对于分布式查询处理,如果省略了 GROUP BY,排序会在远程服务器上部分完成,并在发起请求的服务器上合并结果。这意味着在分布式排序中,待排序的数据量可能会超过单台服务器的内存容量。
如果 RAM 不足,可以在外部内存中执行排序 (即在磁盘上创建临时 File) 。为此,请使用设置 max_bytes_before_external_sort。如果将其设为 0 (默认值) ,则外部排序会被禁用。如果启用该功能,当待排序数据量达到指定字节数时,已收集的数据会先排序并转储到临时文件中。读取完所有数据后,再将所有已排序的文件合并并输出结果。文件会写入配置中的 /var/lib/clickhouse/tmp/ 目录 (默认如此,但你也可以使用 tmp_path 参数更改此设置) 。你还可以仅在查询超出内存限制时启用落盘,也就是说,max_bytes_ratio_before_external_sort=0.6 会仅在查询达到内存限制 (用户/服务器) 的 60% 后启用落盘。
运行查询时,实际使用的内存可能会超过 max_bytes_before_external_sort。因此,这个设置值必须显著小于 max_memory_usage。例如,如果你的服务器有 128 GB RAM,并且只需运行单个查询,可以将 max_memory_usage 设为 100 GB,并将 max_bytes_before_external_sort 设为 80 GB。
外部排序的效率远低于在 RAM 中排序。
数据读取优化
ORDER BY 表达式的前缀与表的 sorting key 一致,可以通过使用 optimize_read_in_order 设置来优化查询。
启用 optimize_read_in_order 设置后,ClickHouse server 会使用表索引,并按 ORDER BY 键的顺序读取数据。这样,在指定了 LIMIT 的情况下,就可以避免读取全部数据。因此,对于 LIMIT 较小的大数据查询,处理速度会更快。
该优化同时适用于 ASC 和 DESC,但不能与 GROUP BY 子句和 FINAL 修饰符 一起使用。
禁用 optimize_read_in_order 设置后,ClickHouse server 在处理 SELECT 查询时不会使用表索引。
当运行包含 ORDER BY 子句、较大的 LIMIT,以及需要在找到目标数据前读取大量记录的 WHERE 条件的查询时,请考虑手动禁用 optimize_read_in_order。
以下表引擎支持此优化:
- MergeTree (包括 materialized views) ,
- Merge,
- Buffer
MaterializedView 引擎的表,此优化适用于类似 SELECT ... FROM merge_tree_table ORDER BY pk 的视图。但如果视图查询本身不包含 ORDER BY 子句,则不支持类似 SELECT ... FROM view ORDER BY pk 的查询。
ORDER BY Expr WITH FILL 修饰符
WITH FILL 修饰符可以放在 ORDER BY expr 之后,并可选择指定 FROM expr、TO expr 和 STEP expr 参数。
expr 列中所有缺失的值都会按顺序补齐,其他列则会填充为默认值。
要填充多个列,请在 ORDER BY 部分中每个字段名后添加带可选参数的 WITH FILL 修饰符。
Query
WITH FILL 可用于 Numeric (所有类型的 float、decimal、int) 或 Date/DateTime 类型的字段。用于 String 字段时,缺失值会用空字符串填充。
如果未定义 FROM const_expr,则填充序列将使用 ORDER BY 中 expr 字段的最小值。
如果未定义 TO const_expr,则填充序列将使用 ORDER BY 中 expr 字段的最大值。
如果定义了 STEP const_numeric_expr,则对于数值类型,const_numeric_expr 按原样解释;对于 Date 类型,按 days 解释;对于 DateTime 类型,按 seconds 解释。它还支持表示时间和日期时间间隔的 INTERVAL 数据类型。
如果省略 STEP const_numeric_expr,则填充序列对数值类型使用 1.0,对 Date 类型使用 1 day,对 DateTime 类型使用 1 second。
如果定义了 STALENESS const_numeric_expr,查询将持续生成行,直到原始数据中当前行与前一行的差值超过 const_numeric_expr。
INTERPOLATE 可用于未参与 ORDER BY WITH FILL 的列。这些列会通过应用 expr,根据前一个字段的值进行填充。如果未指定 expr,则会重复前一个值。省略列列表则表示包含所有允许的列。
不使用 WITH FILL 的查询示例:
Query
Response
WITH FILL 修饰符后的同一查询:
Query
Response
ORDER BY field2 WITH FILL, field1 WITH FILL,填充会按照 ORDER BY 子句中字段的顺序进行。
示例:
Query
Response
d1 不会被填充,也不会使用默认值,因为 d2 没有重复值,因此无法正确计算 d1 的序列。
下面是更改了 ORDER BY 中字段后的查询:
Query
Response
d1 中填充的每条数据使用了 1 天的 INTERVAL 数据类型:
Query
Response
STALENESS 的查询示例:
Query
Response
STALENESS 3 后的同一查询:
Query
Response
INTERPOLATE 的查询示例:
Query
Response
INTERPOLATE 后的同一查询:
Query
Response
按排序前缀分组填充
sensor_id 列用作填充列 timestamp 的排序前缀:
value 列插值为 9999,只是为了让填充出的行更醒目。
此行为由设置项 use_with_fill_by_sorting_prefix 控制 (默认启用)