mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-07 16:14:52 +00:00
477 lines
23 KiB
Markdown
477 lines
23 KiB
Markdown
---
|
||
toc_title: ORDER BY
|
||
---
|
||
|
||
# Секция ORDER BY {#select-order-by}
|
||
|
||
Секция `ORDER BY` содержит список выражений, к каждому из которых также может быть приписано `DESC` или `ASC` (направление сортировки). Если ничего не приписано - это аналогично приписыванию `ASC`. `ASC` - сортировка по возрастанию, `DESC` - сортировка по убыванию. Обозначение направления сортировки действует на одно выражение, а не на весь список. Пример: `ORDER BY Visits DESC, SearchPhrase`
|
||
|
||
Строки, для которых список выражений, по которым производится сортировка, принимает одинаковые значения, выводятся в произвольном порядке, который может быть также недетерминированным (каждый раз разным).
|
||
Если секция 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]
|
||
```
|
||
|
||
`WITH FILL` может быть применене только к полям с числовыми (все разновидности float, int, decimal) или временными (все разновидности Date, DateTime) типами.
|
||
Когда не определен `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.
|
||
|
||
|
||
Для примера, следующий запрос
|
||
```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 │
|
||
└────────────┴────────────┴──────────┘
|
||
```
|
||
|
||
## Секция OFFSET FETCH {#offset-fetch}
|
||
|
||
`OFFSET` и `FETCH` позволяют извлекать данные по частям. Они указывают строки, которые вы хотите получить в результате запроса.
|
||
|
||
``` sql
|
||
OFFSET offset_row_count {ROW | ROWS}] [FETCH {FIRST | NEXT} fetch_row_count {ROW | ROWS} {ONLY | WITH TIES}]
|
||
```
|
||
|
||
`offset_row_count` или `fetch_row_count` может быть числом или литеральной константой. Если вы не используете `fetch_row_count`, то его значение равно 1.
|
||
|
||
`OFFSET` указывает количество строк, которые необходимо пропустить перед началом возврата строк из запроса.
|
||
|
||
`FETCH` указывает максимальное количество строк, которые могут быть получены в результате запроса.
|
||
|
||
Опция `ONLY` используется для возврата строк, которые следуют сразу же за строками, пропущенными секцией `OFFSET`. В этом случае `FETCH` — это альтернатива [LIMIT](../../../sql-reference/statements/select/limit.md). Например, следующий запрос
|
||
|
||
``` sql
|
||
SELECT * FROM test_fetch ORDER BY a OFFSET 1 ROW FETCH FIRST 3 ROWS ONLY;
|
||
```
|
||
|
||
идентичен запросу
|
||
|
||
``` sql
|
||
SELECT * FROM test_fetch ORDER BY a LIMIT 3 OFFSET 1;
|
||
```
|
||
|
||
Опция `WITH TIES` используется для возврата дополнительных строк, которые привязываются к последней в результате запроса. Например, если `fetch_row_count` имеет значение 5 и существуют еще 2 строки с такими же значениями столбцов, указанных в `ORDER BY`, что и у пятой строки результата, то финальный набор будет содержать 7 строк.
|
||
|
||
!!! note "Примечание"
|
||
Секция `OFFSET` должна находиться перед секцией `FETCH`, если обе присутствуют.
|
||
|
||
### Примеры {#examples}
|
||
|
||
Входная таблица:
|
||
|
||
``` text
|
||
┌─a─┬─b─┐
|
||
│ 1 │ 1 │
|
||
│ 2 │ 1 │
|
||
│ 3 │ 4 │
|
||
│ 1 │ 3 │
|
||
│ 5 │ 4 │
|
||
│ 0 │ 6 │
|
||
│ 5 │ 7 │
|
||
└───┴───┘
|
||
```
|
||
|
||
Использование опции `ONLY`:
|
||
|
||
``` sql
|
||
SELECT * FROM test_fetch ORDER BY a OFFSET 3 ROW FETCH FIRST 3 ROWS ONLY;
|
||
```
|
||
|
||
Результат:
|
||
|
||
``` text
|
||
┌─a─┬─b─┐
|
||
│ 2 │ 1 │
|
||
│ 3 │ 4 │
|
||
│ 5 │ 4 │
|
||
└───┴───┘
|
||
```
|
||
|
||
Использование опции `WITH TIES`:
|
||
|
||
``` sql
|
||
SELECT * FROM test_fetch ORDER BY a OFFSET 3 ROW FETCH FIRST 3 ROWS WITH TIES;
|
||
```
|
||
|
||
Результат:
|
||
|
||
``` text
|
||
┌─a─┬─b─┐
|
||
│ 2 │ 1 │
|
||
│ 3 │ 4 │
|
||
│ 5 │ 4 │
|
||
│ 5 │ 7 │
|
||
└───┴───┘
|
||
```
|
||
|
||
[Оригинальная статья](https://clickhouse.tech/docs/ru/sql-reference/statements/select/order-by/) <!--hide-->
|