跳到主要内容
跳到主要内容

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 子句,则行的顺序也是任意且非确定性。

特殊值的排序

NaNNULL 排序顺序有两种处理方式:

  • 默认情况下或使用 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 中的每个表达式指定或不指定。如果指定了 ASCDESC,则 COLLATE 在其后指定。在使用 COLLATE 时,排序始终为不区分大小写。

排序规则在 LowCardinalityNullableArrayTuple 中受到支持。

我们只建议在最终排序少量行时使用 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 的情况下读取所有数据。因此,对于大数据的小限制的查询处理更快。

优化适用于 ASCDESC,并且与 GROUP BY 子句以及 FINAL 修饰符不兼容。

当禁用 optimize_read_in_order 设置时,ClickHouse 服务器在处理 SELECT 查询时不使用表索引。

在运行具有 ORDER BY 子句、大 LIMITWHERE 条件的查询时,可以考虑手动禁用 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 exprTO exprSTEP expr。 所有缺失的 expr 列的值将按顺序填充,其他列将填充默认值。

要填充多个列,在 ORDER BY 部分的每个字段名称后添加 WITH FILL 修饰符及可选参数。

WITH FILL 可应用于具有数值(所有类型的浮点、十进制、整型)或日期/日期时间类型的字段。应用于 String 字段时,缺失的值填充为空字符串。 当未定义 FROM const_expr 时,填充顺序使用 ORDER BYexpr 字段的最小值。 当未定义 TO const_expr 时,填充顺序使用 ORDER BYexpr 字段的最大值。 当定义了 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_exprINTERPOLATE 可以应用于不参与 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 控制(默认启用)。