ORDER BY 子句
ORDER BY
子句包含
- 表达式列表,例如
ORDER BY visits, search_phrase
, - 引用
SELECT
子句中列的数字列表,例如ORDER BY 2, 1
,或 ALL
,表示SELECT
子句的所有列,例如ORDER BY ALL
。
要禁用按列编号排序,请将设置 enable_positional_arguments 设置为 0。
要禁用按 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
以获取:
当浮点数被排序时,NaNs 会与其他值分开。无论排序顺序如何,NaNs 都在最后。换句话说,对于升序排序,NaNs 被放置在所有其他数字之上,而对于降序排序,它们被放置在剩余数字之下。
排序支持
对于按 String 值排序,可以指定排序规则(比较)。示例:ORDER BY SearchPhrase COLLATE 'tr'
- 用土耳其字母表按关键字升序排序,区分大小写,假设字符串为 UTF-8 编码。COLLATE
可以单独为 ORDER BY
中的每个表达式指定或不指定。如果指定了 ASC
或 DESC
,则 COLLATE
在其后指定。在使用 COLLATE
时,排序始终为不区分大小写。
排序规则在 LowCardinality、Nullable、Array 和 Tuple 中受到支持。
我们只建议在最终排序少量行时使用 COLLATE
,因为使用 COLLATE
的排序效率低于按字节正常排序。
排序示例
仅包含 String 值的示例:
输入表:
查询:
结果:
使用 Nullable 的示例:
输入表:
查询:
结果:
使用 Array 的示例:
输入表:
查询:
结果:
使用 LowCardinality 字符串的示例:
输入表:
查询:
结果:
使用 Tuple 的示例:
查询:
结果:
实施细节
如果除了 ORDER BY
外,还指定了足够小的 LIMIT,则使用的内存较少。否则,花费的内存量与用于排序的数据量成正比。对于分布式查询处理,如果省略 GROUP BY,则排序部分在远程服务器上进行,结果在请求服务器上合并。这意味着对于分布式排序,待排序的数据量可能大于单个服务器上的内存。
如果内存不足,可以在外部内存中进行排序(在磁盘上创建临时文件)。为此,使用设置 max_bytes_before_external_sort
。如果设置为 0(默认),则禁用外部排序。如果启用,当待排序的数据量达到指定字节数时,收集到的数据将被排序并转储到临时文件中。读取所有数据后,所有已排序的文件将合并并输出结果。文件写入配置中的 /var/lib/clickhouse/tmp/
目录(默认情况下,但可以使用 tmp_path
参数更改此设置)。
运行查询可能会使用比 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
表达式有一个与表排序键相同的前缀,可以使用设置 optimize_read_in_order 优化查询。
当启用 optimize_read_in_order
设置时,ClickHouse 服务器使用表索引并按 ORDER BY
键的顺序读取数据。这可以避免在指定了 LIMIT 的情况下读取所有数据。因此,对于大数据的小限制的查询处理更快。
优化适用于 ASC
和 DESC
,并且与 GROUP BY 子句以及 FINAL 修饰符不兼容。
当禁用 optimize_read_in_order
设置时,ClickHouse 服务器在处理 SELECT
查询时不使用表索引。
在运行具有 ORDER BY
子句、大 LIMIT
和 WHERE 条件的查询时,可以考虑手动禁用 optimize_read_in_order
,因为这需要在找到查询数据之前读取大量记录。
优化支持以下表引擎:
在 MaterializedView
引擎的表中,优化支持视图,例如 SELECT ... FROM merge_tree_table ORDER BY pk
。但是在查询像 SELECT ... FROM view ORDER BY pk
如果视图查询没有 ORDER BY
子句时则不支持。
带填充修饰符的 ORDER BY Expr
此修饰符也可以与 LIMIT ... WITH TIES 修饰符 结合使用。
WITH FILL
修饰符可以在 ORDER BY expr
后面设置,后面可选参数为 FROM expr
、TO expr
和 STEP expr
。
所有缺失的 expr
列的值将按顺序填充,其他列将填充默认值。
要填充多个列,在 ORDER BY
部分的每个字段名称后添加 WITH FILL
修饰符及可选参数。
WITH FILL
可应用于具有数值(所有类型的浮点、十进制、整型)或日期/日期时间类型的字段。应用于 String
字段时,缺失的值填充为空字符串。
当未定义 FROM const_expr
时,填充顺序使用 ORDER BY
中 expr
字段的最小值。
当未定义 TO const_expr
时,填充顺序使用 ORDER BY
中 expr
字段的最大值。
当定义了 STEP const_numeric_expr
时,const_numeric_expr
解释为数值类型的原样,作为日期类型的 days
,作为日期时间类型的 seconds
。它还支持表示时间和日期间隔的 INTERVAL 数据类型。
当省略 STEP const_numeric_expr
时,填充序列使用数值类型的 1.0
、日期类型的 1 day
和日期时间类型的 1 second
。
当定义了 STALENESS const_numeric_expr
时,查询将生成行,直到原始数据中与前一行的差异超过 const_numeric_expr
。
INTERPOLATE
可以应用于不参与 ORDER BY WITH FILL
的列。这些列根据先前字段的值来填充,应用 expr
。如果未提供 expr
,则会重复先前的值。省略列表将导致包括所有允许的列。
没有 WITH FILL
的查询示例:
结果:
应用 WITH FILL
修饰符后的相同查询:
结果:
对于多个字段的情况 ORDER BY field2 WITH FILL, field1 WITH FILL
,填充顺序将遵循 ORDER BY
子句中字段的顺序。
示例:
结果:
字段 d1
没有填充并使用默认值,因为我们对 d2
值没有重复值,无法正确计算 d1
的序列。
以下查询在 ORDER BY
中更改字段后的结果:
结果:
以下查询使用 INTERVAL
数据类型的每个填充在列 d1
上的示例:
结果:
没有 STALENESS
的查询示例:
结果:
在应用 STALENESS 3
后相同的查询:
结果:
没有 INTERPOLATE
的查询示例:
结果:
应用 INTERPOLATE
后的相同查询:
结果:
按排序前缀填充
填充具有特定列相同值的行独立地可能很有用,一个很好的例子是填充时间序列中的缺失值。 假设有以下时间序列表:
我们希望以 1 秒间隔填充每个传感器的缺失值。
实现此目的的方法是将 sensor_id
列用作填充 timestamp
列的排序前缀:
结果:
┌─sensor_id─┬───────────────timestamp─┬─value─┐ │ 234 │ 2021-12-01 00:00:03.000 │ 3 │ │ 234 │ 2021-12-01 00:00:04.000 │ 9999 │ │ 234 │ 2021-12-01 00:00:05.000 │ 9999 │ │ 234 │ 2021-12-01 00:00:06.000 │ 9999 │ │ 234 │ 2021-12-01 00:00:07.000 │ 7 │ │ 432 │ 2021-12-01 00:00:01.000 │ 1 │ │ 432 │ 2021-12-01 00:00:02.000 │ 9999 │ │ 432 │ 2021-12-01 00:00:03.000 │ 9999 │ │ 432 │ 2021-12-01 00:00:04.000 │ 9999 │ │ 432 │ 2021-12-01 00:00:05.000 │ 5 │ └───────────┴─────────────────────────┴───────┘
在这里,value
列用 9999
插值,以便填充的行更为显眼。
这种行为由设置 use_with_fill_by_sorting_prefix
控制(默认启用)。