mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-16 11:22:12 +00:00
456 lines
23 KiB
Markdown
456 lines
23 KiB
Markdown
---
|
||
sidebar_label: ORDER BY
|
||
---
|
||
|
||
# Секция ORDER BY {#select-order-by}
|
||
|
||
Секция `ORDER BY` содержит список выражений, к каждому из которых также может быть приписано `DESC` или `ASC` (направление сортировки). Если ничего не приписано - это аналогично приписыванию `ASC`. `ASC` - сортировка по возрастанию, `DESC` - сортировка по убыванию. Обозначение направления сортировки действует на одно выражение, а не на весь список. Пример: `ORDER BY Visits DESC, SearchPhrase`.
|
||
|
||
Если вы хотите для сортировки данных указывать номера столбцов, а не названия, включите настройку [enable_positional_arguments](../../../operations/settings/settings.md#enable-positional-arguments).
|
||
|
||
Строки, для которых список выражений, по которым производится сортировка, принимает одинаковые значения, выводятся в произвольном порядке, который может быть также недетерминированным (каждый раз разным).
|
||
Если секция ORDER BY отсутствует, то, аналогично, порядок, в котором идут строки, не определён, и может быть недетерминированным.
|
||
|
||
## Сортировка специальных значений {#sorting-of-special-values}
|
||
|
||
Существует два подхода к участию `NaN` и `NULL` в порядке сортировки:
|
||
|
||
- По умолчанию или с модификатором `NULLS LAST`: сначала остальные значения, затем `NaN`, затем `NULL`.
|
||
- С модификатором `NULLS FIRST`: сначала `NULL`, затем `NaN`, затем другие значения.
|
||
|
||
### Пример {#example}
|
||
|
||
Для таблицы
|
||
|
||
``` text
|
||
┌─x─┬────y─┐
|
||
│ 1 │ ᴺᵁᴸᴸ │
|
||
│ 2 │ 2 │
|
||
│ 1 │ nan │
|
||
│ 2 │ 2 │
|
||
│ 3 │ 4 │
|
||
│ 5 │ 6 │
|
||
│ 6 │ nan │
|
||
│ 7 │ ᴺᵁᴸᴸ │
|
||
│ 6 │ 7 │
|
||
│ 8 │ 9 │
|
||
└───┴──────┘
|
||
```
|
||
|
||
Выполните запрос `SELECT * FROM t_null_nan ORDER BY y NULLS FIRST` чтобы получить:
|
||
|
||
``` text
|
||
┌─x─┬────y─┐
|
||
│ 1 │ ᴺᵁᴸᴸ │
|
||
│ 7 │ ᴺᵁᴸᴸ │
|
||
│ 1 │ nan │
|
||
│ 6 │ nan │
|
||
│ 2 │ 2 │
|
||
│ 2 │ 2 │
|
||
│ 3 │ 4 │
|
||
│ 5 │ 6 │
|
||
│ 6 │ 7 │
|
||
│ 8 │ 9 │
|
||
└───┴──────┘
|
||
```
|
||
|
||
При сортировке чисел с плавающей запятой NaNs отделяются от других значений. Независимо от порядка сортировки, NaNs приходят в конце. Другими словами, при восходящей сортировке они помещаются так, как будто они больше всех остальных чисел, а при нисходящей сортировке они помещаются так, как будто они меньше остальных.
|
||
|
||
## Поддержка collation {#collation-support}
|
||
|
||
Для сортировки по значениям типа [String](../../../sql-reference/data-types/string.md) есть возможность указать collation (сравнение). Пример: `ORDER BY SearchPhrase COLLATE 'tr'` - для сортировки по поисковой фразе, по возрастанию, с учётом турецкого алфавита, регистронезависимо, при допущении, что строки в кодировке UTF-8. `COLLATE` может быть указан или не указан для каждого выражения в ORDER BY независимо. Если есть `ASC` или `DESC`, то `COLLATE` указывается после них. При использовании `COLLATE` сортировка всегда регистронезависима.
|
||
|
||
Сравнение поддерживается при использовании типов [LowCardinality](../../../sql-reference/data-types/lowcardinality.md), [Nullable](../../../sql-reference/data-types/nullable.md), [Array](../../../sql-reference/data-types/array.md) и [Tuple](../../../sql-reference/data-types/tuple.md).
|
||
|
||
Рекомендуется использовать `COLLATE` только для окончательной сортировки небольшого количества строк, так как производительность сортировки с указанием `COLLATE` меньше, чем обычной сортировки по байтам.
|
||
|
||
## Примеры с использованием сравнения {#collation-examples}
|
||
|
||
Пример с значениями типа [String](../../../sql-reference/data-types/string.md):
|
||
|
||
Входная таблица:
|
||
|
||
``` text
|
||
┌─x─┬─s────┐
|
||
│ 1 │ bca │
|
||
│ 2 │ ABC │
|
||
│ 3 │ 123a │
|
||
│ 4 │ abc │
|
||
│ 5 │ BCA │
|
||
└───┴──────┘
|
||
```
|
||
|
||
Запрос:
|
||
|
||
```sql
|
||
SELECT * FROM collate_test ORDER BY s ASC COLLATE 'en';
|
||
```
|
||
|
||
Результат:
|
||
|
||
``` text
|
||
┌─x─┬─s────┐
|
||
│ 3 │ 123a │
|
||
│ 4 │ abc │
|
||
│ 2 │ ABC │
|
||
│ 1 │ bca │
|
||
│ 5 │ BCA │
|
||
└───┴──────┘
|
||
```
|
||
|
||
Пример со строками типа [Nullable](../../../sql-reference/data-types/nullable.md):
|
||
|
||
Входная таблица:
|
||
|
||
``` text
|
||
┌─x─┬─s────┐
|
||
│ 1 │ bca │
|
||
│ 2 │ ᴺᵁᴸᴸ │
|
||
│ 3 │ ABC │
|
||
│ 4 │ 123a │
|
||
│ 5 │ abc │
|
||
│ 6 │ ᴺᵁᴸᴸ │
|
||
│ 7 │ BCA │
|
||
└───┴──────┘
|
||
```
|
||
|
||
Запрос:
|
||
|
||
```sql
|
||
SELECT * FROM collate_test ORDER BY s ASC COLLATE 'en';
|
||
```
|
||
|
||
Результат:
|
||
|
||
``` text
|
||
┌─x─┬─s────┐
|
||
│ 4 │ 123a │
|
||
│ 5 │ abc │
|
||
│ 3 │ ABC │
|
||
│ 1 │ bca │
|
||
│ 7 │ BCA │
|
||
│ 6 │ ᴺᵁᴸᴸ │
|
||
│ 2 │ ᴺᵁᴸᴸ │
|
||
└───┴──────┘
|
||
```
|
||
|
||
Пример со строками в [Array](../../../sql-reference/data-types/array.md):
|
||
|
||
Входная таблица:
|
||
|
||
``` text
|
||
┌─x─┬─s─────────────┐
|
||
│ 1 │ ['Z'] │
|
||
│ 2 │ ['z'] │
|
||
│ 3 │ ['a'] │
|
||
│ 4 │ ['A'] │
|
||
│ 5 │ ['z','a'] │
|
||
│ 6 │ ['z','a','a'] │
|
||
│ 7 │ [''] │
|
||
└───┴───────────────┘
|
||
```
|
||
|
||
Запрос:
|
||
|
||
```sql
|
||
SELECT * FROM collate_test ORDER BY s ASC COLLATE 'en';
|
||
```
|
||
|
||
Результат:
|
||
|
||
``` text
|
||
┌─x─┬─s─────────────┐
|
||
│ 7 │ [''] │
|
||
│ 3 │ ['a'] │
|
||
│ 4 │ ['A'] │
|
||
│ 2 │ ['z'] │
|
||
│ 5 │ ['z','a'] │
|
||
│ 6 │ ['z','a','a'] │
|
||
│ 1 │ ['Z'] │
|
||
└───┴───────────────┘
|
||
```
|
||
|
||
Пример со строками типа [LowCardinality](../../../sql-reference/data-types/lowcardinality.md):
|
||
|
||
Входная таблица:
|
||
|
||
```text
|
||
┌─x─┬─s───┐
|
||
│ 1 │ Z │
|
||
│ 2 │ z │
|
||
│ 3 │ a │
|
||
│ 4 │ A │
|
||
│ 5 │ za │
|
||
│ 6 │ zaa │
|
||
│ 7 │ │
|
||
└───┴─────┘
|
||
```
|
||
|
||
Запрос:
|
||
|
||
```sql
|
||
SELECT * FROM collate_test ORDER BY s ASC COLLATE 'en';
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
┌─x─┬─s───┐
|
||
│ 7 │ │
|
||
│ 3 │ a │
|
||
│ 4 │ A │
|
||
│ 2 │ z │
|
||
│ 1 │ Z │
|
||
│ 5 │ za │
|
||
│ 6 │ zaa │
|
||
└───┴─────┘
|
||
```
|
||
|
||
Пример со строками в [Tuple](../../../sql-reference/data-types/tuple.md):
|
||
|
||
```text
|
||
┌─x─┬─s───────┐
|
||
│ 1 │ (1,'Z') │
|
||
│ 2 │ (1,'z') │
|
||
│ 3 │ (1,'a') │
|
||
│ 4 │ (2,'z') │
|
||
│ 5 │ (1,'A') │
|
||
│ 6 │ (2,'Z') │
|
||
│ 7 │ (2,'A') │
|
||
└───┴─────────┘
|
||
```
|
||
|
||
Запрос:
|
||
|
||
```sql
|
||
SELECT * FROM collate_test ORDER BY s ASC COLLATE 'en';
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
┌─x─┬─s───────┐
|
||
│ 3 │ (1,'a') │
|
||
│ 5 │ (1,'A') │
|
||
│ 2 │ (1,'z') │
|
||
│ 1 │ (1,'Z') │
|
||
│ 7 │ (2,'A') │
|
||
│ 4 │ (2,'z') │
|
||
│ 6 │ (2,'Z') │
|
||
└───┴─────────┘
|
||
```
|
||
|
||
## Деталь реализации {#implementation-details}
|
||
|
||
Если кроме `ORDER BY` указан также не слишком большой [LIMIT](limit.md), то расходуется меньше оперативки. Иначе расходуется количество памяти, пропорциональное количеству данных для сортировки. При распределённой обработке запроса, если отсутствует [GROUP BY](group-by.md), сортировка частично делается на удалённых серверах, а на сервере-инициаторе запроса производится слияние результатов. Таким образом, при распределённой сортировке, может сортироваться объём данных, превышающий размер памяти на одном сервере.
|
||
|
||
Существует возможность выполнять сортировку во внешней памяти (с созданием временных файлов на диске), если оперативной памяти не хватает. Для этого предназначена настройка `max_bytes_before_external_sort`. Если она выставлена в 0 (по умолчанию), то внешняя сортировка выключена. Если она включена, то при достижении объёмом данных для сортировки указанного количества байт, накопленные данные будут отсортированы и сброшены во временный файл. После того, как все данные будут прочитаны, будет произведено слияние всех сортированных файлов и выдача результата. Файлы записываются в директорию `/var/lib/clickhouse/tmp/` (по умолчанию, может быть изменено с помощью параметра `tmp_path`) в конфиге.
|
||
|
||
На выполнение запроса может расходоваться больше памяти, чем `max_bytes_before_external_sort`. Поэтому, значение этой настройки должно быть существенно меньше, чем `max_memory_usage`. Для примера, если на вашем сервере 128 GB оперативки, и вам нужно выполнить один запрос, то выставите `max_memory_usage` в 100 GB, а `max_bytes_before_external_sort` в 80 GB.
|
||
|
||
Внешняя сортировка работает существенно менее эффективно, чем сортировка в оперативке.
|
||
|
||
## Оптимизация чтения данных {#optimize_read_in_order}
|
||
|
||
Если в списке выражений в секции `ORDER BY` первыми указаны те поля, по которым проиндексирована таблица, по которой строится выборка, такой запрос можно оптимизировать — для этого используйте настройку [optimize_read_in_order](../../../operations/settings/settings.md#optimize_read_in_order).
|
||
|
||
Когда настройка `optimize_read_in_order` включена, при выполнении запроса сервер использует табличные индексы и считывает данные в том порядке, который задан списком выражений `ORDER BY`. Поэтому если в запросе установлен [LIMIT](../../../sql-reference/statements/select/limit.md), сервер не станет считывать лишние данные. Таким образом, запросы к большим таблицам, но имеющие ограничения по числу записей, выполняются быстрее.
|
||
|
||
Оптимизация работает при любом порядке сортировки `ASC` или `DESC`, но не работает при использовании группировки [GROUP BY](../../../sql-reference/statements/select/group-by.md) и модификатора [FINAL](../../../sql-reference/statements/select/from.md#select-from-final).
|
||
|
||
Когда настройка `optimize_read_in_order` отключена, при выполнении запросов `SELECT` табличные индексы не используются.
|
||
|
||
Для запросов с сортировкой `ORDER BY`, большим значением `LIMIT` и условиями отбора [WHERE](../../../sql-reference/statements/select/where.md), требующими чтения больших объемов данных, рекомендуется отключать `optimize_read_in_order` вручную.
|
||
|
||
Оптимизация чтения данных поддерживается в следующих движках:
|
||
|
||
- [MergeTree](../../../engines/table-engines/mergetree-family/mergetree.md)
|
||
- [Merge](../../../engines/table-engines/special/merge.md), [Buffer](../../../engines/table-engines/special/buffer.md) и [MaterializedView](../../../engines/table-engines/special/materializedview.md), работающими с таблицами `MergeTree`
|
||
|
||
В движке `MaterializedView` оптимизация поддерживается при работе с сохраненными запросами (представлениями) вида `SELECT ... FROM merge_tree_table ORDER BY pk`. Но оптимизация не поддерживается для запросов вида `SELECT ... FROM view ORDER BY pk`, если в сохраненном запросе нет секции `ORDER BY`.
|
||
|
||
## Модификатор ORDER BY expr WITH FILL {#orderby-with-fill}
|
||
|
||
Этот модификатор также может быть скомбинирован с модификатором [LIMIT ... WITH TIES](../../../sql-reference/statements/select/limit.md#limit-with-ties)
|
||
|
||
Модификатор `WITH FILL` может быть установлен после `ORDER BY expr` с опциональными параметрами `FROM expr`, `TO expr` и `STEP expr`.
|
||
Все пропущенные значения для колонки `expr` будут заполнены значениями, соответствующими предполагаемой последовательности значений колонки, другие колонки будут заполнены значениями по умолчанию.
|
||
|
||
Используйте следующую конструкцию для заполнения нескольких колонок с модификатором `WITH FILL` с необязательными параметрами после каждого имени поля в секции `ORDER BY`.
|
||
|
||
```sql
|
||
ORDER BY expr [WITH FILL] [FROM const_expr] [TO const_expr] [STEP const_numeric_expr], ... exprN [WITH FILL] [FROM expr] [TO expr] [STEP numeric_expr]
|
||
[INTERPOLATE [(col [AS expr], ... colN [AS exprN])]]
|
||
```
|
||
|
||
`WITH FILL` может быть применен к полям с числовыми (все разновидности float, int, decimal) или временными (все разновидности Date, DateTime) типами. В случае применения к полям типа `String` недостающие значения заполняются пустой строкой.
|
||
Когда не определен `FROM const_expr`, последовательность заполнения использует минимальное значение поля `expr` из `ORDER BY`.
|
||
Когда не определен `TO const_expr`, последовательность заполнения использует максимальное значение поля `expr` из `ORDER BY`.
|
||
Когда `STEP const_numeric_expr` определен, `const_numeric_expr` интерпретируется "как есть" для числовых типов, как "дни" для типа `Date` и как "секунды" для типа `DateTime`.
|
||
|
||
Когда `STEP const_numeric_expr` не указан, тогда используется `1.0` для числовых типов, `1 день` для типа Date и `1 секунда` для типа DateTime.
|
||
|
||
`INTERPOLATE` может быть применен к колонкам, не участвующим в `ORDER BY WITH FILL`. Такие колонки заполняются значениями, вычисляемыми применением `expr` к предыдущему значению. Если `expr` опущен, то колонка заполняется предыдущим значением. Если список колонок не указан, то включаются все разрешенные колонки.
|
||
|
||
Пример запроса без использования `WITH FILL`:
|
||
```sql
|
||
SELECT n, source FROM (
|
||
SELECT toFloat32(number % 10) AS n, 'original' AS source
|
||
FROM numbers(10) WHERE number % 3 = 1
|
||
) ORDER BY n;
|
||
```
|
||
|
||
Результат:
|
||
```text
|
||
┌─n─┬─source───┐
|
||
│ 1 │ original │
|
||
│ 4 │ original │
|
||
│ 7 │ original │
|
||
└───┴──────────┘
|
||
```
|
||
|
||
Тот же запрос после применения модификатора `WITH FILL`:
|
||
```sql
|
||
SELECT n, source FROM (
|
||
SELECT toFloat32(number % 10) AS n, 'original' AS source
|
||
FROM numbers(10) WHERE number % 3 = 1
|
||
) ORDER BY n WITH FILL FROM 0 TO 5.51 STEP 0.5
|
||
```
|
||
|
||
Результат:
|
||
|
||
```text
|
||
┌───n─┬─source───┐
|
||
│ 0 │ │
|
||
│ 0.5 │ │
|
||
│ 1 │ original │
|
||
│ 1.5 │ │
|
||
│ 2 │ │
|
||
│ 2.5 │ │
|
||
│ 3 │ │
|
||
│ 3.5 │ │
|
||
│ 4 │ original │
|
||
│ 4.5 │ │
|
||
│ 5 │ │
|
||
│ 5.5 │ │
|
||
│ 7 │ original │
|
||
└─────┴──────────┘
|
||
```
|
||
|
||
Для случая с несколькими полями `ORDER BY field2 WITH FILL, field1 WITH FILL` порядок заполнения будет соответствовать порядку полей в секции `ORDER BY`.
|
||
|
||
Пример:
|
||
```sql
|
||
SELECT
|
||
toDate((number * 10) * 86400) AS d1,
|
||
toDate(number * 86400) AS d2,
|
||
'original' AS source
|
||
FROM numbers(10)
|
||
WHERE (number % 3) = 1
|
||
ORDER BY
|
||
d2 WITH FILL,
|
||
d1 WITH FILL STEP 5;
|
||
```
|
||
|
||
Результат:
|
||
```text
|
||
┌───d1───────┬───d2───────┬─source───┐
|
||
│ 1970-01-11 │ 1970-01-02 │ original │
|
||
│ 1970-01-01 │ 1970-01-03 │ │
|
||
│ 1970-01-01 │ 1970-01-04 │ │
|
||
│ 1970-02-10 │ 1970-01-05 │ original │
|
||
│ 1970-01-01 │ 1970-01-06 │ │
|
||
│ 1970-01-01 │ 1970-01-07 │ │
|
||
│ 1970-03-12 │ 1970-01-08 │ original │
|
||
└────────────┴────────────┴──────────┘
|
||
```
|
||
|
||
Поле `d1` не заполняется и использует значение по умолчанию. Поскольку у нас нет повторяющихся значений для `d2`, мы не можем правильно рассчитать последователность заполнения для `d1`.
|
||
|
||
Cледующий запрос (с измененым порядком в ORDER BY):
|
||
```sql
|
||
SELECT
|
||
toDate((number * 10) * 86400) AS d1,
|
||
toDate(number * 86400) AS d2,
|
||
'original' AS source
|
||
FROM numbers(10)
|
||
WHERE (number % 3) = 1
|
||
ORDER BY
|
||
d1 WITH FILL STEP 5,
|
||
d2 WITH FILL;
|
||
```
|
||
|
||
Результат:
|
||
```text
|
||
┌───d1───────┬───d2───────┬─source───┐
|
||
│ 1970-01-11 │ 1970-01-02 │ original │
|
||
│ 1970-01-16 │ 1970-01-01 │ │
|
||
│ 1970-01-21 │ 1970-01-01 │ │
|
||
│ 1970-01-26 │ 1970-01-01 │ │
|
||
│ 1970-01-31 │ 1970-01-01 │ │
|
||
│ 1970-02-05 │ 1970-01-01 │ │
|
||
│ 1970-02-10 │ 1970-01-05 │ original │
|
||
│ 1970-02-15 │ 1970-01-01 │ │
|
||
│ 1970-02-20 │ 1970-01-01 │ │
|
||
│ 1970-02-25 │ 1970-01-01 │ │
|
||
│ 1970-03-02 │ 1970-01-01 │ │
|
||
│ 1970-03-07 │ 1970-01-01 │ │
|
||
│ 1970-03-12 │ 1970-01-08 │ original │
|
||
└────────────┴────────────┴──────────┘
|
||
```
|
||
|
||
Пример запроса без `INTERPOLATE`:
|
||
|
||
``` sql
|
||
SELECT n, source, inter FROM (
|
||
SELECT toFloat32(number % 10) AS n, 'original' AS source, number as inter
|
||
FROM numbers(10) WHERE number % 3 = 1
|
||
) ORDER BY n WITH FILL FROM 0 TO 5.51 STEP 0.5;
|
||
```
|
||
|
||
Результат:
|
||
``` text
|
||
┌───n─┬─source───┬─inter─┐
|
||
│ 0 │ │ 0 │
|
||
│ 0.5 │ │ 0 │
|
||
│ 1 │ original │ 1 │
|
||
│ 1.5 │ │ 0 │
|
||
│ 2 │ │ 0 │
|
||
│ 2.5 │ │ 0 │
|
||
│ 3 │ │ 0 │
|
||
│ 3.5 │ │ 0 │
|
||
│ 4 │ original │ 4 │
|
||
│ 4.5 │ │ 0 │
|
||
│ 5 │ │ 0 │
|
||
│ 5.5 │ │ 0 │
|
||
│ 7 │ original │ 7 │
|
||
└─────┴──────────┴───────┘
|
||
```
|
||
|
||
Тот же запрос с `INTERPOLATE`:
|
||
|
||
``` sql
|
||
SELECT n, source, inter FROM (
|
||
SELECT toFloat32(number % 10) AS n, 'original' AS source, number as inter
|
||
FROM numbers(10) WHERE number % 3 = 1
|
||
) ORDER BY n WITH FILL FROM 0 TO 5.51 STEP 0.5 INTERPOLATE (inter AS inter + 1);
|
||
```
|
||
|
||
Результат:
|
||
``` text
|
||
┌───n─┬─source───┬─inter─┐
|
||
│ 0 │ │ 0 │
|
||
│ 0.5 │ │ 0 │
|
||
│ 1 │ original │ 1 │
|
||
│ 1.5 │ │ 2 │
|
||
│ 2 │ │ 3 │
|
||
│ 2.5 │ │ 4 │
|
||
│ 3 │ │ 5 │
|
||
│ 3.5 │ │ 6 │
|
||
│ 4 │ original │ 4 │
|
||
│ 4.5 │ │ 5 │
|
||
│ 5 │ │ 6 │
|
||
│ 5.5 │ │ 7 │
|
||
│ 7 │ original │ 7 │
|
||
└─────┴──────────┴───────┘
|