From ae17feed4c60cd01aecdea6412a925ee00d0f284 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Wed, 30 May 2018 09:06:44 +0300 Subject: [PATCH 001/425] Bugs and broken links fixes. --- docs/ru/formats/csv.md | 4 +--- docs/ru/query_language/queries.md | 12 +++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/ru/formats/csv.md b/docs/ru/formats/csv.md index a1d0dee45c9..226745dddd9 100644 --- a/docs/ru/formats/csv.md +++ b/docs/ru/formats/csv.md @@ -4,9 +4,7 @@ Формат comma separated values ([RFC](https://tools.ietf.org/html/rfc4180)). -При форматировании, строки выводятся в двойных кавычках. Двойная кавычка внутри строки выводится как две двойные кавычки подряд. Других правил экранирования нет. Даты и даты-с-временем выводятся в двойных кавычках. Числа выводятся без кавычек. Значения разделяются символом-разделителем*. Строки разделяются unix переводом строки (LF). Массивы сериализуются в CSV следующим образом: сначала массив сериализуется в строку, как в формате TabSeparated, а затем полученная строка выводится в CSV в двойных кавычках. Кортежи в формате CSV сериализуются, как отдельные столбцы (то есть, теряется их вложенность в кортеж). - -*По умолчанию — `,`. См. настройку [format_csv_delimiter](/docs/ru/operations/settings/settings/#format_csv_delimiter) для дополнительной информации. +При форматировании, строки выводятся в двойных кавычках. Двойная кавычка внутри строки выводится как две двойные кавычки подряд. Других правил экранирования нет. Даты и даты-с-временем выводятся в двойных кавычках. Числа выводятся без кавычек. Значения разделяются символом-разделителем, по умолчанию — `,`. Символ-разделитель определяется настройкой [format_csv_delimiter](../operations/settings/settings.md#format_csv_delimiter). Строки разделяются unix переводом строки (LF). Массивы сериализуются в CSV следующим образом: сначала массив сериализуется в строку, как в формате TabSeparated, а затем полученная строка выводится в CSV в двойных кавычках. Кортежи в формате CSV сериализуются, как отдельные столбцы (то есть, теряется их вложенность в кортеж). При парсинге, все значения могут парситься как в кавычках, так и без кавычек. Поддерживаются как двойные, так и одинарные кавычки. В том числе, строки могут быть расположены без кавычек - тогда они парсятся до символа-разделителя или перевода строки (CR или LF). В нарушение RFC, в случае парсинга строк не в кавычках, начальные и конечные пробелы и табы игнорируются. В качестве перевода строки, поддерживаются как Unix (LF), так и Windows (CR LF) и Mac OS Classic (LF CR) варианты. diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index 58bc73bc44a..12094fcae9e 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -115,13 +115,13 @@ CREATE TABLE IF NOT EXISTS all_hits ON CLUSTER cluster (p Date, i Int32) ENGINE CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT ... ``` -Создаёт представление. Представления бывают двух видов - обычные и материализованные (MATERIALIZED). +Создаёт представление. Представления бывают двух видов: обычные и материализованные (`MATERIALIZED`). -При создании материализованного представления, нужно обязательно указать ENGINE - движок таблицы для хранения данных. +При создании материализованного представления, нужно обязательно указать `ENGINE` — [движок таблицы](../table_engines/index.md#table_engines) для хранения данных. Материализованное представление работает следующим образом: при вставлении данных в таблицу, указанную в SELECT, часть вставленных данных конвертируется запросом, а результат вставляется в представление. -Обычные представления не хранят никаких данных, а всего лишь производят чтение из другой таблицы. То есть, обычное представление - не более чем сохранённый запрос. При чтении из представления, этот сохранённый запрос, используется в качестве подзапроса в секции FROM. +Обычные представления не хранят никаких данных, а всего лишь производят чтение из другой таблицы. То есть, обычное представление — не более чем сохранённый запрос. При чтении из представления, этот сохранённый запрос, используется в качестве подзапроса в секции [FROM](#query_language-section-from). Для примера, пусть вы создали представление: @@ -143,10 +143,6 @@ SELECT a, b, c FROM (SELECT ...) Материализованные (MATERIALIZED) представления хранят данные, преобразованные соответствующим запросом SELECT. -При создании материализованного представления, нужно обязательно указать ENGINE - движок таблицы для хранения данных. - -Материализованное представление устроено следующим образом: при вставке данных в таблицу, указанную в SELECT-е, кусок вставляемых данных преобразуется этим запросом SELECT, и полученный результат вставляется в представление. - Если указано POPULATE, то при создании представления, в него будут вставлены имеющиеся данные таблицы, как если бы был сделан запрос `CREATE TABLE ... AS SELECT ...` . Иначе, представление будет содержать только данные, вставляемые в таблицу после создания представления. Не рекомендуется использовать POPULATE, так как вставляемые в таблицу данные во время создания представления, не попадут в него. Запрос `SELECT` может содержать `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`... Следует иметь ввиду, что соответствующие преобразования будут выполняться независимо, на каждый блок вставляемых данных. Например, при наличии `GROUP BY`, данные будут агрегироваться при вставке, но только в рамках одной пачки вставляемых данных. Далее, данные не будут доагрегированы. Исключение - использование ENGINE, производящего агрегацию данных самостоятельно, например, `SummingMergeTree`. @@ -650,6 +646,8 @@ SELECT [DISTINCT] expr_list Если в запросе отсутствуют секции `DISTINCT`, `GROUP BY`, `ORDER BY`, подзапросы в `IN` и `JOIN`, то запрос будет обработан полностью потоково, с использованием O(1) количества оперативки. Иначе запрос может съесть много оперативки, если не указаны подходящие ограничения `max_memory_usage`, `max_rows_to_group_by`, `max_rows_to_sort`, `max_rows_in_distinct`, `max_bytes_in_distinct`, `max_rows_in_set`, `max_bytes_in_set`, `max_rows_in_join`, `max_bytes_in_join`, `max_bytes_before_external_sort`, `max_bytes_before_external_group_by`. Подробнее смотрите в разделе "Настройки". Присутствует возможность использовать внешнюю сортировку (с сохранением временных данных на диск) и внешнюю агрегацию. `Merge join` в системе нет. + + ### Секция FROM Если секция FROM отсутствует, то данные будут читаться из таблицы `system.one`. From c91a2c0de0e02bed58efbf863b758787cf0eb186 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Sat, 30 Jun 2018 20:04:07 +0300 Subject: [PATCH 002/425] NULL-literal. Support for NULLs in data formats. --- docs/ru/data_types/array.md | 2 ++ docs/ru/data_types/string.md | 2 ++ docs/ru/formats/csv.md | 2 ++ docs/ru/formats/json.md | 2 +- docs/ru/formats/pretty.md | 12 +++++++ docs/ru/formats/rowbinary.md | 2 ++ docs/ru/formats/tabseparated.md | 56 +++++++++++++++++-------------- docs/ru/formats/tskv.md | 9 +++++ docs/ru/formats/values.md | 2 +- docs/ru/formats/vertical.md | 15 +++++++++ docs/ru/query_language/queries.md | 2 +- docs/ru/query_language/syntax.md | 28 ++++++++++------ 12 files changed, 96 insertions(+), 38 deletions(-) diff --git a/docs/ru/data_types/array.md b/docs/ru/data_types/array.md index 894b6c7647c..00e708c9181 100644 --- a/docs/ru/data_types/array.md +++ b/docs/ru/data_types/array.md @@ -1,3 +1,5 @@ + + # Array(T) Массив из элементов типа T. Типом T может быть любой тип, в том числе, массив. diff --git a/docs/ru/data_types/string.md b/docs/ru/data_types/string.md index e35fa6a892d..f4a100470c7 100644 --- a/docs/ru/data_types/string.md +++ b/docs/ru/data_types/string.md @@ -1,3 +1,5 @@ + + # String Строки произвольной длины. Длина не ограничена. Значение может содержать произвольный набор байт, включая нулевые байты. diff --git a/docs/ru/formats/csv.md b/docs/ru/formats/csv.md index 226745dddd9..7ab679688be 100644 --- a/docs/ru/formats/csv.md +++ b/docs/ru/formats/csv.md @@ -8,4 +8,6 @@ При парсинге, все значения могут парситься как в кавычках, так и без кавычек. Поддерживаются как двойные, так и одинарные кавычки. В том числе, строки могут быть расположены без кавычек - тогда они парсятся до символа-разделителя или перевода строки (CR или LF). В нарушение RFC, в случае парсинга строк не в кавычках, начальные и конечные пробелы и табы игнорируются. В качестве перевода строки, поддерживаются как Unix (LF), так и Windows (CR LF) и Mac OS Classic (LF CR) варианты. +`NULL` форматируется в виде `\N`. + Формат CSV поддерживает вывод totals и extremes аналогично `TabSeparated`. diff --git a/docs/ru/formats/json.md b/docs/ru/formats/json.md index 5664e54297f..8706143a469 100644 --- a/docs/ru/formats/json.md +++ b/docs/ru/formats/json.md @@ -1,4 +1,4 @@ - + # JSON diff --git a/docs/ru/formats/pretty.md b/docs/ru/formats/pretty.md index 0f2434230f2..7baa55da18d 100644 --- a/docs/ru/formats/pretty.md +++ b/docs/ru/formats/pretty.md @@ -5,6 +5,18 @@ Выводит данные в виде Unicode-art табличек, также используя ANSI-escape последовательности для установки цветов в терминале. Рисуется полная сетка таблицы и, таким образом, каждая строчка занимает две строки в терминале. Каждый блок результата выводится в виде отдельной таблицы. Это нужно, чтобы можно было выводить блоки без буферизации результата (буферизация потребовалась бы, чтобы заранее вычислить видимую ширину всех значений.) + +[NULL](../query_language/syntax.md#null-literal) выводится как `ᴺᵁᴸᴸ`. + +```sql +SELECT * FROM t_null +``` +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +└───┴──────┘ +``` + Для защиты от вываливания слишком большого количества данных в терминал, выводится только первые 10 000 строк. Если строк больше или равно 10 000, то будет написано "Showed first 10 000." Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). diff --git a/docs/ru/formats/rowbinary.md b/docs/ru/formats/rowbinary.md index d0d33c696c7..7982ca0df54 100644 --- a/docs/ru/formats/rowbinary.md +++ b/docs/ru/formats/rowbinary.md @@ -12,3 +12,5 @@ String представлены как длина в формате varint (unsi FixedString представлены просто как последовательность байт. Array представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем элементы массива, подряд. + +Для поддержки [NULL](../query_language/syntax.md#null-literal) перед каждым значением в строке добавлен дополнительный байт, который содержит 0 или 1. Если 0, то значение не `NULL` и далее идёт значение. Если 1, то значение — `NULL` и этот байт трактуется как отдельное значение. diff --git a/docs/ru/formats/tabseparated.md b/docs/ru/formats/tabseparated.md index a38c418d10d..0513f617bc4 100644 --- a/docs/ru/formats/tabseparated.md +++ b/docs/ru/formats/tabseparated.md @@ -1,9 +1,38 @@ - + # TabSeparated В TabSeparated формате данные пишутся по строкам. Каждая строчка содержит значения, разделённые табами. После каждого значения идёт таб, кроме последнего значения в строке, после которого идёт перевод строки. Везде подразумеваются исключительно unix-переводы строк. Последняя строка также обязана содержать перевод строки на конце. Значения пишутся в текстовом виде, без обрамляющих кавычек, с экранированием служебных символов. +Этот формат также доступен под именем `TSV`. + +Формат `TabSeparated` удобен для обработки данных произвольными программами и скриптами. Он используется по умолчанию в HTTP-интерфейсе, а также в batch-режиме клиента командной строки. Также формат позволяет переносить данные между разными СУБД. Например, вы можете получить дамп из MySQL и загрузить его в ClickHouse, или наоборот. + +Формат `TabSeparated` поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения. Основной результат, тотальные значения и экстремальные значения, отделяются друг от друга пустой строкой. Пример: + +```sql +SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT TabSeparated`` +``` + +```text +2014-03-17 1406958 +2014-03-18 1383658 +2014-03-19 1405797 +2014-03-20 1353623 +2014-03-21 1245779 +2014-03-22 1031592 +2014-03-23 1046491 + +0000-00-00 8873898 + +2014-03-17 1031592 +2014-03-23 1406958 +``` + + + +## Форматирование данных + Целые числа пишутся в десятичной форме. Числа могут содержать лишний символ "+" в начале (игнорируется при парсинге, а при форматировании не пишется). Неотрицательные числа не могут содержать знак отрицания. При чтении допустим парсинг пустой строки, как числа ноль, или (для знаковых типов) строки, состоящей из одного минуса, как числа ноль. Числа, не помещающиеся в соответствующий тип данных, могут парсится, как некоторое другое число, без сообщения об ошибке. Числа с плавающей запятой пишутся в десятичной форме. При этом, десятичный разделитель - точка. Поддерживается экспоненциальная запись, а также inf, +inf, -inf, nan. Запись числа с плавающей запятой может начинаться или заканчиваться на десятичную точку. @@ -34,27 +63,4 @@ world Массивы форматируются в виде списка значений через запятую в квадратных скобках. Элементы массива - числа форматируются как обычно, а даты, даты-с-временем и строки - в одинарных кавычках с такими же правилами экранирования, как указано выше. -Формат TabSeparated удобен для обработки данных произвольными программами и скриптами. Он используется по умолчанию в HTTP-интерфейсе, а также в batch-режиме клиента командной строки. Также формат позволяет переносить данные между разными СУБД. Например, вы можете получить дамп из MySQL и загрузить его в ClickHouse, или наоборот. - -Формат TabSeparated поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения. Основной результат, тотальные значения и экстремальные значения, отделяются друг от друга пустой строкой. Пример: - -```sql -SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT TabSeparated`` -``` - -```text -2014-03-17 1406958 -2014-03-18 1383658 -2014-03-19 1405797 -2014-03-20 1353623 -2014-03-21 1245779 -2014-03-22 1031592 -2014-03-23 1046491 - -0000-00-00 8873898 - -2014-03-17 1031592 -2014-03-23 1406958 -``` - -Этот формат также доступен под именем `TSV`. +[NULL](../query_language/syntax.md#null-literal) форматируется в виде `\N`. diff --git a/docs/ru/formats/tskv.md b/docs/ru/formats/tskv.md index 50d95b928bc..f388259f60b 100644 --- a/docs/ru/formats/tskv.md +++ b/docs/ru/formats/tskv.md @@ -17,6 +17,15 @@ SearchPhrase=дизайн штор count()=1064 SearchPhrase=баку count()=1000 ``` +[NULL](../query_language/syntax.md#null-literal) форматируется в виде `\N`. + +```sql +SELECT * FROM t_null FORMAT TSKV +``` +``` +x=1 y=\N +``` + При большом количестве маленьких столбцов, этот формат существенно неэффективен, и обычно нет причин его использовать. Он реализован, так как используется в некоторых отделах Яндекса. Поддерживается как вывод, так и парсинг данных в этом формате. При парсинге, поддерживается расположение значений разных столбцов в произвольном порядке. Допустимо отсутствие некоторых значений - тогда они воспринимаются как равные значениям по умолчанию. При этом, в качестве значений по умолчанию используются нули, пустые строки и не поддерживаются сложные значения по умолчанию, которые могут быть заданы в таблице. diff --git a/docs/ru/formats/values.md b/docs/ru/formats/values.md index a8037898a31..4c3fb5c9d94 100644 --- a/docs/ru/formats/values.md +++ b/docs/ru/formats/values.md @@ -2,7 +2,7 @@ # Values -Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату TabSeparated. При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). +Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату [TabSeparated](tabseparated.md#formats-tabseparated). При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). [NULL](../query_language/syntax.md#null-literal) представляется как `NULL`. Минимальный набор символов, которых вам необходимо экранировать при передаче в Values формате: одинарная кавычка и обратный слеш. diff --git a/docs/ru/formats/vertical.md b/docs/ru/formats/vertical.md index 98da1a6686e..3db44cfe747 100644 --- a/docs/ru/formats/vertical.md +++ b/docs/ru/formats/vertical.md @@ -3,4 +3,19 @@ # Vertical Выводит каждое значение на отдельной строке, с указанием имени столбца. Формат удобно использовать для вывода одной-нескольких строк, если каждая строка состоит из большого количества столбцов. + +[NULL](../query_language/syntax.md#null-literal) выводится как `ᴺᵁᴸᴸ`. + +Пример: + +```sql +SELECT * FROM t_null FORMAT Vertical +``` +``` +Row 1: +────── +x: 1 +y: ᴺᵁᴸᴸ +``` + Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index 12094fcae9e..f7c113402c6 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -54,7 +54,7 @@ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... `DEFAULT expr`, `MATERIALIZED expr`, `ALIAS expr`. Пример: `URLDomain String DEFAULT domain(URL)`. -Если выражение для значения по умолчанию не указано, то в качестве значений по умолчанию будут использоваться нули для чисел, пустые строки для строк, пустые массивы для массивов, а также `0000-00-00` для дат и `0000-00-00 00:00:00` для дат с временем. NULL-ы не поддерживаются. +Если выражение для значения по умолчанию не указано, то в качестве значений по умолчанию будут использоваться нули для чисел, пустые строки для строк, пустые массивы для массивов, а также `0000-00-00` для дат и `0000-00-00 00:00:00` для дат с временем. В случае, если указано выражение по умолчанию, то указание типа столбца не обязательно. При отсутствии явно указанного типа, будет использован тип выражения по умолчанию. Пример: `EventDate DEFAULT toDate(EventTime)` - для столбца EventDate будет использован тип Date. diff --git a/docs/ru/query_language/syntax.md b/docs/ru/query_language/syntax.md index 5b5e0fb5a7f..4820a7c6ff1 100644 --- a/docs/ru/query_language/syntax.md +++ b/docs/ru/query_language/syntax.md @@ -40,28 +40,26 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') ## Литералы -Бывают числовые, строковые и составные литералы. - -### Числовые литералы +### Числовые Числовой литерал пытается распарситься: -- сначала как 64-битное число без знака, с помощью функции strtoull; -- если не получилось - то как 64-битное число со знаком, с помощью функции strtoll; -- если не получилось - то как число с плавающей запятой, с помощью функции strtod; +- сначала как 64-битное число без знака, с помощью функции `strtoull`; +- если не получилось - то как 64-битное число со знаком, с помощью функции `strtoll`; +- если не получилось - то как число с плавающей запятой, с помощью функции `strtod`; - иначе - ошибка. Соответствующее значение будет иметь тип минимального размера, который вмещает значение. -Например, 1 парсится как UInt8, а 256 - как UInt16. Подробнее смотрите "Типы данных". +Например, 1 парсится как `UInt8`, а 256 - как `UInt16`. Подробнее смотрите "Типы данных". Примеры: `1`, `18446744073709551615`, `0xDEADBEEF`, `01`, `0.1`, `1e100`, `-1e-100`, `inf`, `nan`. -### Строковые литералы +### Строковые -Поддерживаются только строковые литералы в одинарных кавычках. Символы внутри могут быть экранированы с помощью обратного слеша. Следующие escape-последовательности имеют соответствующее специальное значение: `\b`, `\f`, `\r`, `\n`, `\t`, `\0`, `\a`, `\v`, `\xHH`. Во всех остальных случаях, последовательности вида `\c`, где c - любой символ, преобразуется в c. Таким образом, могут быть использованы последовательности `\'` и `\\`. Значение будет иметь тип String. +Поддерживаются только строковые литералы в одинарных кавычках. Символы внутри могут быть экранированы с помощью обратного слеша. Следующие escape-последовательности имеют соответствующее специальное значение: `\b`, `\f`, `\r`, `\n`, `\t`, `\0`, `\a`, `\v`, `\xHH`. Во всех остальных случаях, последовательности вида `\c`, где c - любой символ, преобразуется в c. Таким образом, могут быть использованы последовательности `\'` и `\\`. Значение будет иметь тип [String](../data_types/string.md#data_types-string). Минимальный набор символов, которых вам необходимо экранировать в строковых литералах: `'` and `\`. -### Составные литералы +### Составные Поддерживаются конструкции для массивов: `[1, 2, 3]` и кортежей: `(1, 'Hello, world!', 2)`. На самом деле, это вовсе не литералы, а выражение с оператором создания массива и оператором создания кортежа, соответственно. @@ -69,6 +67,16 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') Массив должен состоять хотя бы из одного элемента, а кортеж - хотя бы из двух. Кортежи носят служебное значение для использования в секции IN запроса SELECT. Кортежи могут быть получены в качестве результата запроса, но не могут быть сохранены в базу (за исключением таблиц типа Memory). + + +### NULL + +Обозначает, что значение отсутствует. + +Чтобы в поле таблицы можно было хранить `NULL`, оно должно быть типа [Nullable](../data_types/nullable.md#data_type-nullable). + +В зависимости от формата данных (входных или выходных) `NULL` может иметь различное представление. Подробнее смотрите в документации для [форматов данных](../formats/index.md#formats). + ## Функции Функции записываются как идентификатор со списком аргументов (возможно, пустым) в скобках. В отличие от стандартного SQL, даже в случае пустого списка аргументов, скобки обязательны. Пример: `now()`. From f7ba157b10b8d9bd4f15ac5305d2d936505d6870 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Tue, 3 Jul 2018 15:51:46 +0300 Subject: [PATCH 003/425] New data types: Nullable and Nothing. Processing of Nullable in inserts from selects. Some links and typographic fixes. --- docs/mkdocs_ru.yml | 5 +- docs/ru/data_types/nullable.md | 46 +++++++++++++++++++ .../data_types/special_data_types/nothing.md | 19 ++++++++ docs/ru/data_types/tuple.md | 2 + docs/ru/formats/json.md | 3 ++ docs/ru/formats/rowbinary.md | 2 +- docs/ru/formats/values.md | 2 +- docs/ru/query_language/queries.md | 11 ++++- 8 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 docs/ru/data_types/nullable.md create mode 100644 docs/ru/data_types/special_data_types/nothing.md diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 7bc70245bad..978f5912034 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -122,10 +122,9 @@ pages: - 'Табличные функции': - 'Введение': 'table_functions/index.md' - - 'file': 'table_functions/file.md' + - 'remote': 'table_functions/remote.md' - 'merge': 'table_functions/merge.md' - 'numbers': 'table_functions/numbers.md' - - 'remote': 'table_functions/remote.md' - 'Форматы': - 'Введение': 'formats/index.md' @@ -166,6 +165,7 @@ pages: - 'Array(T)': 'data_types/array.md' - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' + - 'Nullable': 'data_types/nullable.md' - 'Вложенные структуры данных': # - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' @@ -173,6 +173,7 @@ pages: # - 'Служебные типы данных': 'data_types/special_data_types/index.md' - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' + - 'Nothing': 'data_types/special_data_types/nothing.md' - 'Операторы': 'operators/index.md' diff --git a/docs/ru/data_types/nullable.md b/docs/ru/data_types/nullable.md new file mode 100644 index 00000000000..83d1cb583f6 --- /dev/null +++ b/docs/ru/data_types/nullable.md @@ -0,0 +1,46 @@ + + +# Nullable(TypeName) + +Позволяет хранить в таблице [NULL](../query_language/syntax.md#null-literal) вместо значения типа `TypeName`. + +В качестве `TypeName` нельзя использовать составные типы данных [Array](array.md#data_type-array) и [Tuple](typle.md#data_type-tuple). Составные типы данных могут содержать значения типа `Nullable`, например `Array(Nullable(Int8))`. + +Поле типа `Nullable` нельзя включать в индексы. + +## Пример использования + +``` +:) CREATE TABLE t_null(x Int8, y Nullable(Int8)) engine TinyLog + +CREATE TABLE t_null +( + x Int8, + y Nullable(Int8) +) +ENGINE = TinyLog + +Ok. + +0 rows in set. Elapsed: 0.012 sec. + +:) INSERT INTO t_null VALUES (1, NULL) + +INSERT INTO t_null VALUES + +Ok. + +1 rows in set. Elapsed: 0.007 sec. + +:) SELECT x+y from t_null + +SELECT x + y +FROM t_null + +┌─plus(x, y)─┐ +│ \N │ +└────────────┘ + +1 rows in set. Elapsed: 0.009 sec. + +``` diff --git a/docs/ru/data_types/special_data_types/nothing.md b/docs/ru/data_types/special_data_types/nothing.md new file mode 100644 index 00000000000..43c3ff05840 --- /dev/null +++ b/docs/ru/data_types/special_data_types/nothing.md @@ -0,0 +1,19 @@ + + +# Nothing + +Этот тип данных предназначен только для того, чтобы представлять [NULL](../../query_language/syntax.md#null-literal). + +Невозможно создать значение типа `Nothing`, поэтому он используется там, где значение не подразумевается. Например, `NULL` записывается как `Nullable(Nothing)` ([Nullable](../../data_types/nullable.md#data_type-nullable) — это тип данных, позволяющий хранить `NULL` в таблицах). Также тип Nothing используется для обозначения пустых массивов: + +```bash +:) SELECT toTypeName(Array()) + +SELECT toTypeName([]) + +┌─toTypeName(array())─┐ +│ Array(Nothing) │ +└─────────────────────┘ + +1 rows in set. Elapsed: 0.062 sec. +``` diff --git a/docs/ru/data_types/tuple.md b/docs/ru/data_types/tuple.md index abac42bc4b7..dd68cd6608c 100644 --- a/docs/ru/data_types/tuple.md +++ b/docs/ru/data_types/tuple.md @@ -1,3 +1,5 @@ + + # Tuple(T1, T2, ...) Кортежи не могут быть записаны в таблицы (кроме таблиц типа Memory). Они используется для временной группировки столбцов. Столбцы могут группироваться при использовании выражения IN в запросе, а также для указания нескольких формальных параметров лямбда-функций. Подробнее смотрите раздел "Операторы IN", "Функции высшего порядка". diff --git a/docs/ru/formats/json.md b/docs/ru/formats/json.md index 8706143a469..55dd1e0f94e 100644 --- a/docs/ru/formats/json.md +++ b/docs/ru/formats/json.md @@ -84,4 +84,7 @@ JSON совместим с JavaScript. Для этого, дополнитель `extremes` - экстремальные значения (при настройке extremes, выставленной в 1). Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). + +ClickHouse поддерживает [NULL](../query_language/syntax.md#null-literal), который при выводе JSON будет отображен как `null`. + Смотрите также формат JSONEachRow. diff --git a/docs/ru/formats/rowbinary.md b/docs/ru/formats/rowbinary.md index 7982ca0df54..224f6ea78ef 100644 --- a/docs/ru/formats/rowbinary.md +++ b/docs/ru/formats/rowbinary.md @@ -13,4 +13,4 @@ FixedString представлены просто как последовате Array представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем элементы массива, подряд. -Для поддержки [NULL](../query_language/syntax.md#null-literal) перед каждым значением в строке добавлен дополнительный байт, который содержит 0 или 1. Если 0, то значение не `NULL` и далее идёт значение. Если 1, то значение — `NULL` и этот байт трактуется как отдельное значение. +Для поддержки [NULL](../query_language/syntax.md#null-literal) перед каждым значением типа [Nullable](../data_types/nullable.md#data_type-nullable) в строке добавлен дополнительный байт, который содержит 1 или 0. Если 1, то значение — `NULL` и этот байт трактуется как отдельное значение. Если 0, то после байта идёт не `NULL`-значение. diff --git a/docs/ru/formats/values.md b/docs/ru/formats/values.md index 4c3fb5c9d94..9252f19098b 100644 --- a/docs/ru/formats/values.md +++ b/docs/ru/formats/values.md @@ -1,4 +1,4 @@ - + # Values diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index c584840334d..23fc6f275e2 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -641,13 +641,20 @@ INSERT INTO t FORMAT TabSeparated INSERT INTO [db.]table [(c1, c2, c3)] SELECT ... ``` -Соответствие столбцов определяется их позицией в секции SELECT. При этом, их имена в выражении SELECT и в таблице для INSERT, могут отличаться. При необходимости выполняется приведение типов данных, эквивалентное соответствующему оператору CAST. +Соответствие столбцов определяется их позицией в секции `SELECT`. При этом, их имена в выражении `SELECT` и в таблице для `INSERT`, могут отличаться. При необходимости выполняется приведение типов данных, эквивалентное соответствующему оператору `CAST`. -Все форматы данных кроме Values не позволяют использовать в качестве значений выражения, такие как `now()`, `1 + 2` и подобные. Формат Values позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода. +Все форматы данных кроме [Values](..formats/values.md#formats-values) не позволяют использовать в качестве значений выражения, такие как `now()`, `1 + 2` и подобные. Формат `Values` позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода. Не поддерживаются другие запросы на модификацию части данных: `UPDATE`, `DELETE`, `REPLACE`, `MERGE`, `UPSERT`, `INSERT UPDATE`. Вы можете удалять старые данные с помощью запроса `ALTER TABLE ... DROP PARTITION`. +Особенности вставки значений типа [Nullable](../data_types/nullable.md#data_types-nullable): + +- Если не `Nullable` значение вставляется в `Nullable` поле, то операция происходит без особенностей. +- Если значение типа `Nullable` вставляется в не `Nullable` поле, то ClickHouse проверяет присутствие `NULL` в результатах `SELECT` и если: + - Есть хотя бы один `NULL`, то ClickHouse не выполняет `INSERT` и генерирует исключение. + - Нет ни одного `NULL`, то ClickHouse выполняет `INSERT`, но тип значения преобразуется к типу поля в конечной таблице. + ### Замечания о производительности `INSERT` сортирует входящие данные по первичному ключу и разбивает их на партиции по месяцам. Если вы вставляете данные за разные месяцы вперемешку, то это может значительно снизить производительность запроса `INSERT`. Чтобы избежать этого: From 0cf2d401de5ab9477a62ab52e2aedb5506cf5fc6 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Tue, 3 Jul 2018 16:07:16 +0300 Subject: [PATCH 004/425] Liks fixes. --- docs/mkdocs_ru.yml | 1 + docs/ru/data_types/nullable.md | 2 +- docs/ru/query_language/queries.md | 2 +- docs/ru/table_functions/file.md | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 978f5912034..76e7c9dbc48 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -125,6 +125,7 @@ pages: - 'remote': 'table_functions/remote.md' - 'merge': 'table_functions/merge.md' - 'numbers': 'table_functions/numbers.md' + - 'file': 'table_functions/file.md' - 'Форматы': - 'Введение': 'formats/index.md' diff --git a/docs/ru/data_types/nullable.md b/docs/ru/data_types/nullable.md index 83d1cb583f6..987570cbac2 100644 --- a/docs/ru/data_types/nullable.md +++ b/docs/ru/data_types/nullable.md @@ -4,7 +4,7 @@ Позволяет хранить в таблице [NULL](../query_language/syntax.md#null-literal) вместо значения типа `TypeName`. -В качестве `TypeName` нельзя использовать составные типы данных [Array](array.md#data_type-array) и [Tuple](typle.md#data_type-tuple). Составные типы данных могут содержать значения типа `Nullable`, например `Array(Nullable(Int8))`. +В качестве `TypeName` нельзя использовать составные типы данных [Array](array.md#data_type-array) и [Tuple](tuple.md#data_type-tuple). Составные типы данных могут содержать значения типа `Nullable`, например `Array(Nullable(Int8))`. Поле типа `Nullable` нельзя включать в индексы. diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index 23fc6f275e2..a910636bb42 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -643,7 +643,7 @@ INSERT INTO [db.]table [(c1, c2, c3)] SELECT ... Соответствие столбцов определяется их позицией в секции `SELECT`. При этом, их имена в выражении `SELECT` и в таблице для `INSERT`, могут отличаться. При необходимости выполняется приведение типов данных, эквивалентное соответствующему оператору `CAST`. -Все форматы данных кроме [Values](..formats/values.md#formats-values) не позволяют использовать в качестве значений выражения, такие как `now()`, `1 + 2` и подобные. Формат `Values` позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода. +Все форматы данных кроме [Values](../formats/values.md#formats-values) не позволяют использовать в качестве значений выражения, такие как `now()`, `1 + 2` и подобные. Формат `Values` позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода. Не поддерживаются другие запросы на модификацию части данных: `UPDATE`, `DELETE`, `REPLACE`, `MERGE`, `UPSERT`, `INSERT UPDATE`. Вы можете удалять старые данные с помощью запроса `ALTER TABLE ... DROP PARTITION`. diff --git a/docs/ru/table_functions/file.md b/docs/ru/table_functions/file.md index 88bb201eb9b..0c009133dc0 100644 --- a/docs/ru/table_functions/file.md +++ b/docs/ru/table_functions/file.md @@ -6,7 +6,7 @@ path - относительный путь до файла от [user_files_path](../operations/server_settings/settings.md#user_files_path). -format - [формат](../formats/index.md) файла. +format - [формат](../formats/index.md#formats) файла. structure - структура таблицы в форме 'UserID UInt64, URL String'. Определяет имена и типы столбцов. From 29afde3ac93a295d22a6033f7196a3692bdad0d4 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Wed, 4 Jul 2018 09:21:21 +0300 Subject: [PATCH 005/425] Described operators IS NULL and IS NOT NULL --- docs/ru/operators/index.md | 50 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/docs/ru/operators/index.md b/docs/ru/operators/index.md index 7f8a4d8c692..45fcb97f84d 100644 --- a/docs/ru/operators/index.md +++ b/docs/ru/operators/index.md @@ -79,9 +79,9 @@ `a ? b : c` - функция `if(a, b, c)` -Примечание: +Примечание: -Условный оператор сначала вычисляет значения b и c, затем проверяет выполнение условия a, и только после этого возвращает соответствующее значение. Если в качестве b или с выступает функция arrayJoin(), то размножение каждой строки произойдет вне зависимости от условия а. +Условный оператор сначала вычисляет значения b и c, затем проверяет выполнение условия a, и только после этого возвращает соответствующее значение. Если в качестве b или с выступает функция arrayJoin(), то размножение каждой строки произойдет вне зависимости от условия а. ## Условное выражение @@ -119,3 +119,49 @@ END Иногда это работает не так, как ожидается. Например, `SELECT 4 > 3 > 2` выдаст 0. Для эффективности, реализованы функции `and` и `or`, принимающие произвольное количество аргументов. Соответствующие цепочки операторов `AND` и `OR`, преобразуются в один вызов этих функций. + +## Проверка `NULL` + +ClickHouse поддерживает операторы `IS NULL` и `IS NOT NULL`. + +### IS NULL + +- Для значений типа [Nullable](../data_types/nullable.md#data_type-nullable) оператор `IS NULL` возвращает: + - `1`, если значение — `NULL`. + - `0` в обратном случае. +- Для прочих значений оператор `IS NULL` всегда возвращает `0`. + +```bash +:) SELECT x+100 FROM t_null WHERE y IS NULL + +SELECT x + 100 +FROM t_null +WHERE isNull(y) + +┌─plus(x, 100)─┐ +│ 101 │ +└──────────────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + +### IS NOT NULL + +- Для значений типа [Nullable](../data_types/nullable.md#data_type-nullable) оператор `IS NOT NULL` возвращает: + - `0`, если значение — `NULL`. + - `1`, в обратном случае. +- Для прочих значений оператор `IS NOT NULL` всегда возвращает `1`. + +```bash +:) SELECT * FROM t_null WHERE y IS NOT NULL + +SELECT * +FROM t_null +WHERE isNotNull(y) + +┌─x─┬─y─┐ +│ 2 │ 3 │ +└───┴───┘ + +1 rows in set. Elapsed: 0.002 sec. +``` From ae8c739c69b6b00ca9c1637cb69e1e2040c0631c Mon Sep 17 00:00:00 2001 From: BayoNet Date: Sun, 8 Jul 2018 11:58:43 +0300 Subject: [PATCH 006/425] Some clarifications about `Nullable` type and `NULL`s. --- docs/ru/data_types/nullable.md | 15 ++++++++++++++- docs/ru/query_language/syntax.md | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/ru/data_types/nullable.md b/docs/ru/data_types/nullable.md index 987570cbac2..14c00257740 100644 --- a/docs/ru/data_types/nullable.md +++ b/docs/ru/data_types/nullable.md @@ -2,12 +2,25 @@ # Nullable(TypeName) -Позволяет хранить в таблице [NULL](../query_language/syntax.md#null-literal) вместо значения типа `TypeName`. +Позволяет хранить в таблице [NULL](../query_language/syntax.md#null-literal) вместо значения типа `TypeName`. Например, `Nullable(Int8)` позволяет хранить `NULL` вместо значений `Int8`. В качестве `TypeName` нельзя использовать составные типы данных [Array](array.md#data_type-array) и [Tuple](tuple.md#data_type-tuple). Составные типы данных могут содержать значения типа `Nullable`, например `Array(Nullable(Int8))`. Поле типа `Nullable` нельзя включать в индексы. +`NULL` — значение по умолчанию для типа `Nullable`, если в конфигурации сервера ClickHouse не указано иное. + +##Особенности хранения + +Для хранения значения типа `Nullable` ClickHouse использует: + +- Отдельный файл с масками `NULL` (далее маска). +- Непосредственно файл со значениями. + +Маска определяет, что лежит в ячейке данных: `NULL` или значение. + +В случае, когда маска указывает, что в ячейке хранится `NULL`, в файле значений хранится значение по умолчанию для типа данных. Т.е. если, например, поле имеет тип `Nullable(Int8)`, то ячейка будет хранить значение по умолчанию для `Int8`. Эта особенность увеличивает размер хранилища. Также для некоторых операций возможно снижение производительности. Будьте внимательны при проектировании системы хранения. + ## Пример использования ``` diff --git a/docs/ru/query_language/syntax.md b/docs/ru/query_language/syntax.md index 4820a7c6ff1..9c67dc7fd46 100644 --- a/docs/ru/query_language/syntax.md +++ b/docs/ru/query_language/syntax.md @@ -77,6 +77,8 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') В зависимости от формата данных (входных или выходных) `NULL` может иметь различное представление. Подробнее смотрите в документации для [форматов данных](../formats/index.md#formats). +При обработке `NULL` есть множество особенностей. Например, если хотя бы один из аргументов операции сравнения — `NULL`, то результатом такой операции тоже будет `NULL`. Этим же свойством обладают операции умножения, сложения и пр. Подробнее читайте в документации на каждую операцию. + ## Функции Функции записываются как идентификатор со списком аргументов (возможно, пустым) в скобках. В отличие от стандартного SQL, даже в случае пустого списка аргументов, скобки обязательны. Пример: `now()`. From 6c7ba03d0f6b34520f274922709febe309ccbe54 Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Tue, 10 Jul 2018 00:25:56 +0300 Subject: [PATCH 007/425] Add missing UInt128 (UUID) field visitors --- dbms/src/Common/FieldVisitors.cpp | 7 ++ dbms/src/Common/FieldVisitors.h | 102 +++++++++++++++++-------- dbms/src/DataTypes/FieldToDataType.cpp | 5 ++ dbms/src/DataTypes/FieldToDataType.h | 1 + 4 files changed, 85 insertions(+), 30 deletions(-) diff --git a/dbms/src/Common/FieldVisitors.cpp b/dbms/src/Common/FieldVisitors.cpp index 3132a7412ca..a2d7d016002 100644 --- a/dbms/src/Common/FieldVisitors.cpp +++ b/dbms/src/Common/FieldVisitors.cpp @@ -155,6 +155,13 @@ void FieldVisitorHash::operator() (const UInt64 & x) const hash.update(x); } +void FieldVisitorHash::operator() (const UInt128 & x) const +{ + UInt8 type = Field::Types::UInt128; + hash.update(type); + hash.update(x); +} + void FieldVisitorHash::operator() (const Int64 & x) const { UInt8 type = Field::Types::Int64; diff --git a/dbms/src/Common/FieldVisitors.h b/dbms/src/Common/FieldVisitors.h index b59c6a47aa7..99f776ad0cf 100644 --- a/dbms/src/Common/FieldVisitors.h +++ b/dbms/src/Common/FieldVisitors.h @@ -38,6 +38,7 @@ typename std::decay_t::ResultType applyVisitor(Visitor && visitor, F && { case Field::Types::Null: return visitor(field.template get()); case Field::Types::UInt64: return visitor(field.template get()); + case Field::Types::UInt128: return visitor(field.template get()); case Field::Types::Int64: return visitor(field.template get()); case Field::Types::Float64: return visitor(field.template get()); case Field::Types::String: return visitor(field.template get()); @@ -57,6 +58,7 @@ static typename std::decay_t::ResultType applyBinaryVisitorImpl(Visitor { case Field::Types::Null: return visitor(field1, field2.template get()); case Field::Types::UInt64: return visitor(field1, field2.template get()); + case Field::Types::UInt128: return visitor(field1, field2.template get()); case Field::Types::Int64: return visitor(field1, field2.template get()); case Field::Types::Float64: return visitor(field1, field2.template get()); case Field::Types::String: return visitor(field1, field2.template get()); @@ -79,6 +81,9 @@ typename std::decay_t::ResultType applyVisitor(Visitor && visitor, F1 & case Field::Types::UInt64: return applyBinaryVisitorImpl( std::forward(visitor), field1.template get(), std::forward(field2)); + case Field::Types::UInt128: + return applyBinaryVisitorImpl( + std::forward(visitor), field1.template get(), std::forward(field2)); case Field::Types::Int64: return applyBinaryVisitorImpl( std::forward(visitor), field1.template get(), std::forward(field2)); @@ -107,6 +112,7 @@ class FieldVisitorToString : public StaticVisitor public: String operator() (const Null & x) const; String operator() (const UInt64 & x) const; + String operator() (const UInt128 & x) const; String operator() (const Int64 & x) const; String operator() (const Float64 & x) const; String operator() (const String & x) const; @@ -121,6 +127,7 @@ class FieldVisitorDump : public StaticVisitor public: String operator() (const Null & x) const; String operator() (const UInt64 & x) const; + String operator() (const UInt128 & x) const; String operator() (const Int64 & x) const; String operator() (const Float64 & x) const; String operator() (const String & x) const; @@ -155,6 +162,7 @@ public: } T operator() (const UInt64 & x) const { return x; } + T operator() (const UInt128 & x) const { return x; } T operator() (const Int64 & x) const { return x; } T operator() (const Float64 & x) const { return x; } }; @@ -170,6 +178,7 @@ public: void operator() (const Null & x) const; void operator() (const UInt64 & x) const; + void operator() (const UInt128 & x) const; void operator() (const Int64 & x) const; void operator() (const Float64 & x) const; void operator() (const String & x) const; @@ -186,38 +195,52 @@ class FieldVisitorAccurateEquals : public StaticVisitor public: bool operator() (const Null &, const Null &) const { return true; } bool operator() (const Null &, const UInt64 &) const { return false; } + bool operator() (const Null &, const UInt128 &) const { return false; } bool operator() (const Null &, const Int64 &) const { return false; } bool operator() (const Null &, const Float64 &) const { return false; } bool operator() (const Null &, const String &) const { return false; } bool operator() (const Null &, const Array &) const { return false; } bool operator() (const Null &, const Tuple &) const { return false; } - bool operator() (const UInt64 &, const Null &) const { return false; } + bool operator() (const UInt64 &, const Null &) const { return false; } bool operator() (const UInt64 & l, const UInt64 & r) const { return l == r; } + bool operator() (const UInt64 &, const UInt128) const { return false; } bool operator() (const UInt64 & l, const Int64 & r) const { return accurate::equalsOp(l, r); } bool operator() (const UInt64 & l, const Float64 & r) const { return accurate::equalsOp(l, r); } - bool operator() (const UInt64 &, const String &) const { return false; } - bool operator() (const UInt64 &, const Array &) const { return false; } - bool operator() (const UInt64 &, const Tuple &) const { return false; } + bool operator() (const UInt64 &, const String &) const { return false; } + bool operator() (const UInt64 &, const Array &) const { return false; } + bool operator() (const UInt64 &, const Tuple &) const { return false; } - bool operator() (const Int64 &, const Null &) const { return false; } + bool operator() (const UInt128 &, const Null &) const { return false; } + bool operator() (const UInt128 &, const UInt64) const { return false; } + bool operator() (const UInt128 & l, const UInt128 & r) const { return l == r; } + bool operator() (const UInt128 &, const Int64) const { return false; } + bool operator() (const UInt128 &, const Float64) const { return false; } + bool operator() (const UInt128 &, const String &) const { return false; } + bool operator() (const UInt128 &, const Array &) const { return false; } + bool operator() (const UInt128 &, const Tuple &) const { return false; } + + bool operator() (const Int64 &, const Null &) const { return false; } bool operator() (const Int64 & l, const UInt64 & r) const { return accurate::equalsOp(l, r); } + bool operator() (const Int64 &, const UInt128) const { return false; } bool operator() (const Int64 & l, const Int64 & r) const { return l == r; } bool operator() (const Int64 & l, const Float64 & r) const { return accurate::equalsOp(l, r); } - bool operator() (const Int64 &, const String &) const { return false; } - bool operator() (const Int64 &, const Array &) const { return false; } - bool operator() (const Int64 &, const Tuple &) const { return false; } + bool operator() (const Int64 &, const String &) const { return false; } + bool operator() (const Int64 &, const Array &) const { return false; } + bool operator() (const Int64 &, const Tuple &) const { return false; } - bool operator() (const Float64 &, const Null &) const { return false; } + bool operator() (const Float64 &, const Null &) const { return false; } bool operator() (const Float64 & l, const UInt64 & r) const { return accurate::equalsOp(l, r); } + bool operator() (const Float64 &, const UInt128) const { return false; } bool operator() (const Float64 & l, const Int64 & r) const { return accurate::equalsOp(l, r); } bool operator() (const Float64 & l, const Float64 & r) const { return l == r; } - bool operator() (const Float64 &, const String &) const { return false; } - bool operator() (const Float64 &, const Array &) const { return false; } - bool operator() (const Float64 &, const Tuple &) const { return false; } + bool operator() (const Float64 &, const String &) const { return false; } + bool operator() (const Float64 &, const Array &) const { return false; } + bool operator() (const Float64 &, const Tuple &) const { return false; } bool operator() (const String &, const Null &) const { return false; } bool operator() (const String &, const UInt64 &) const { return false; } + bool operator() (const String &, const UInt128 &) const { return false; } bool operator() (const String &, const Int64 &) const { return false; } bool operator() (const String &, const Float64 &) const { return false; } bool operator() (const String & l, const String & r) const { return l == r; } @@ -226,6 +249,7 @@ public: bool operator() (const Array &, const Null &) const { return false; } bool operator() (const Array &, const UInt64 &) const { return false; } + bool operator() (const Array &, const UInt128 &) const { return false; } bool operator() (const Array &, const Int64 &) const { return false; } bool operator() (const Array &, const Float64 &) const { return false; } bool operator() (const Array &, const String &) const { return false; } @@ -234,6 +258,7 @@ public: bool operator() (const Tuple &, const Null &) const { return false; } bool operator() (const Tuple &, const UInt64 &) const { return false; } + bool operator() (const Tuple &, const UInt128 &) const { return false; } bool operator() (const Tuple &, const Int64 &) const { return false; } bool operator() (const Tuple &, const Float64 &) const { return false; } bool operator() (const Tuple &, const String &) const { return false; } @@ -247,45 +272,60 @@ public: bool operator() (const Null &, const Null &) const { return false; } bool operator() (const Null &, const UInt64 &) const { return true; } bool operator() (const Null &, const Int64 &) const { return true; } + bool operator() (const Null &, const UInt128 &) const { return true; } bool operator() (const Null &, const Float64 &) const { return true; } bool operator() (const Null &, const String &) const { return true; } bool operator() (const Null &, const Array &) const { return true; } bool operator() (const Null &, const Tuple &) const { return true; } - bool operator() (const UInt64 &, const Null &) const { return false; } + bool operator() (const UInt64 &, const Null &) const { return false; } bool operator() (const UInt64 & l, const UInt64 & r) const { return l < r; } + bool operator() (const UInt64 &, const UInt128 &) const { return false; } bool operator() (const UInt64 & l, const Int64 & r) const { return accurate::lessOp(l, r); } bool operator() (const UInt64 & l, const Float64 & r) const { return accurate::lessOp(l, r); } - bool operator() (const UInt64 &, const String &) const { return true; } - bool operator() (const UInt64 &, const Array &) const { return true; } - bool operator() (const UInt64 &, const Tuple &) const { return true; } + bool operator() (const UInt64 &, const String &) const { return true; } + bool operator() (const UInt64 &, const Array &) const { return true; } + bool operator() (const UInt64 &, const Tuple &) const { return true; } - bool operator() (const Int64 &, const Null &) const { return false; } + bool operator() (const UInt128 &, const Null &) const { return false; } + bool operator() (const UInt128 &, const UInt64) const { return false; } + bool operator() (const UInt128 & l, const UInt128 & r) const { return l < r; } + bool operator() (const UInt128 &, const Int64) const { return false; } + bool operator() (const UInt128 &, const Float64) const { return false; } + bool operator() (const UInt128 &, const String &) const { return false; } + bool operator() (const UInt128 &, const Array &) const { return false; } + bool operator() (const UInt128 &, const Tuple &) const { return false; } + + bool operator() (const Int64 &, const Null &) const { return false; } bool operator() (const Int64 & l, const UInt64 & r) const { return accurate::lessOp(l, r); } + bool operator() (const Int64 &, const UInt128 &) const { return false; } bool operator() (const Int64 & l, const Int64 & r) const { return l < r; } bool operator() (const Int64 & l, const Float64 & r) const { return accurate::lessOp(l, r); } - bool operator() (const Int64 &, const String &) const { return true; } - bool operator() (const Int64 &, const Array &) const { return true; } - bool operator() (const Int64 &, const Tuple &) const { return true; } + bool operator() (const Int64 &, const String &) const { return true; } + bool operator() (const Int64 &, const Array &) const { return true; } + bool operator() (const Int64 &, const Tuple &) const { return true; } - bool operator() (const Float64 &, const Null &) const { return false; } + bool operator() (const Float64 &, const Null &) const { return false; } bool operator() (const Float64 & l, const UInt64 & r) const { return accurate::lessOp(l, r); } + bool operator() (const Float64, const UInt128 &) const { return false; } bool operator() (const Float64 & l, const Int64 & r) const { return accurate::lessOp(l, r); } bool operator() (const Float64 & l, const Float64 & r) const { return l < r; } - bool operator() (const Float64 &, const String &) const { return true; } - bool operator() (const Float64 &, const Array &) const { return true; } - bool operator() (const Float64 &, const Tuple &) const { return true; } + bool operator() (const Float64 &, const String &) const { return true; } + bool operator() (const Float64 &, const Array &) const { return true; } + bool operator() (const Float64 &, const Tuple &) const { return true; } - bool operator() (const String &, const Null &) const { return false; } - bool operator() (const String &, const UInt64 &) const { return false; } - bool operator() (const String &, const Int64 &) const { return false; } - bool operator() (const String &, const Float64 &) const { return false; } + bool operator() (const String &, const Null &) const { return false; } + bool operator() (const String &, const UInt64 &) const { return false; } + bool operator() (const String &, const UInt128 &) const { return false; } + bool operator() (const String &, const Int64 &) const { return false; } + bool operator() (const String &, const Float64 &) const { return false; } bool operator() (const String & l, const String & r) const { return l < r; } - bool operator() (const String &, const Array &) const { return true; } - bool operator() (const String &, const Tuple &) const { return true; } + bool operator() (const String &, const Array &) const { return true; } + bool operator() (const String &, const Tuple &) const { return true; } bool operator() (const Array &, const Null &) const { return false; } bool operator() (const Array &, const UInt64 &) const { return false; } + bool operator() (const Array &, const UInt128 &) const { return false; } bool operator() (const Array &, const Int64 &) const { return false; } bool operator() (const Array &, const Float64 &) const { return false; } bool operator() (const Array &, const String &) const { return false; } @@ -294,6 +334,7 @@ public: bool operator() (const Tuple &, const Null &) const { return false; } bool operator() (const Tuple &, const UInt64 &) const { return false; } + bool operator() (const Tuple &, const UInt128 &) const { return false; } bool operator() (const Tuple &, const Int64 &) const { return false; } bool operator() (const Tuple &, const Float64 &) const { return false; } bool operator() (const Tuple &, const String &) const { return false; } @@ -318,6 +359,7 @@ public: bool operator() (Null &) const { throw Exception("Cannot sum Nulls", ErrorCodes::LOGICAL_ERROR); } bool operator() (String &) const { throw Exception("Cannot sum Strings", ErrorCodes::LOGICAL_ERROR); } bool operator() (Array &) const { throw Exception("Cannot sum Arrays", ErrorCodes::LOGICAL_ERROR); } + bool operator() (UInt128 &) const { throw Exception("Cannot sum UUIDs", ErrorCodes::LOGICAL_ERROR); } }; } diff --git a/dbms/src/DataTypes/FieldToDataType.cpp b/dbms/src/DataTypes/FieldToDataType.cpp index 1b4fbd53c6b..52ffd58aa2d 100644 --- a/dbms/src/DataTypes/FieldToDataType.cpp +++ b/dbms/src/DataTypes/FieldToDataType.cpp @@ -34,6 +34,11 @@ DataTypePtr FieldToDataType::operator() (const UInt64 & x) const return std::make_shared(); } +DataTypePtr FieldToDataType::operator() (const Uint128 & x) const +{ + return std::make_shared(); +} + DataTypePtr FieldToDataType::operator() (const Int64 & x) const { if (x <= std::numeric_limits::max() && x >= std::numeric_limits::min()) return std::make_shared(); diff --git a/dbms/src/DataTypes/FieldToDataType.h b/dbms/src/DataTypes/FieldToDataType.h index c6256a6f04b..a60c6a725d8 100644 --- a/dbms/src/DataTypes/FieldToDataType.h +++ b/dbms/src/DataTypes/FieldToDataType.h @@ -19,6 +19,7 @@ class FieldToDataType : public StaticVisitor public: DataTypePtr operator() (const Null & x) const; DataTypePtr operator() (const UInt64 & x) const; + DataTypePtr operator() (const UInt128 & x) const; DataTypePtr operator() (const Int64 & x) const; DataTypePtr operator() (const Float64 & x) const; DataTypePtr operator() (const String & x) const; From 708063242b69fba7ed9ab8753836dff9214f49e6 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Mon, 16 Jul 2018 18:28:30 +0300 Subject: [PATCH 008/425] Additional .gitignore entries --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index fc68eb07c10..8d1a188befb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /build /docs/build +/docs/edit /docs/tools/venv/ /docs/en/development/build/ /docs/ru/development/build/ @@ -238,3 +239,5 @@ node_modules public website/docs website/presentations +.DS_Store +*/.DS_Store From 9819889b4dc1114a6985dcc0aebacac5564c58bf Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Mon, 16 Jul 2018 18:50:55 +0300 Subject: [PATCH 009/425] Merge a bunch of small articles about system tables into single one --- docs/en/operations/system_tables.md | 414 ++++++++++++++++++ docs/en/system_tables/index.md | 8 - .../system.asynchronous_metrics.md | 8 - docs/en/system_tables/system.clusters.md | 15 - docs/en/system_tables/system.columns.md | 14 - docs/en/system_tables/system.databases.md | 6 - docs/en/system_tables/system.dictionaries.md | 21 - docs/en/system_tables/system.events.md | 8 - docs/en/system_tables/system.functions.md | 8 - docs/en/system_tables/system.merges.md | 18 - docs/en/system_tables/system.metrics.md | 4 - docs/en/system_tables/system.numbers.md | 6 - docs/en/system_tables/system.numbers_mt.md | 5 - docs/en/system_tables/system.one.md | 6 - docs/en/system_tables/system.parts.md | 29 -- docs/en/system_tables/system.processes.md | 25 -- docs/en/system_tables/system.replicas.md | 125 ------ docs/en/system_tables/system.settings.md | 30 -- docs/en/system_tables/system.tables.md | 7 - docs/en/system_tables/system.zookeeper.md | 71 --- docs/mkdocs_en.yml | 22 +- docs/mkdocs_ru.yml | 22 +- docs/redirects.txt | 20 +- docs/ru/operations/system_tables.md | 402 +++++++++++++++++ docs/ru/system_tables/index.md | 7 - .../system.asynchronous_metrics.md | 8 - docs/ru/system_tables/system.clusters.md | 15 - docs/ru/system_tables/system.columns.md | 13 - docs/ru/system_tables/system.databases.md | 5 - docs/ru/system_tables/system.dictionaries.md | 22 - docs/ru/system_tables/system.events.md | 7 - docs/ru/system_tables/system.functions.md | 8 - docs/ru/system_tables/system.merges.md | 18 - docs/ru/system_tables/system.metrics.md | 3 - docs/ru/system_tables/system.numbers.md | 5 - docs/ru/system_tables/system.numbers_mt.md | 4 - docs/ru/system_tables/system.one.md | 5 - docs/ru/system_tables/system.parts.md | 28 -- docs/ru/system_tables/system.processes.md | 24 - docs/ru/system_tables/system.replicas.md | 124 ------ docs/ru/system_tables/system.settings.md | 29 -- docs/ru/system_tables/system.tables.md | 6 - docs/ru/system_tables/system.zookeeper.md | 71 --- 43 files changed, 837 insertions(+), 859 deletions(-) create mode 100644 docs/en/operations/system_tables.md delete mode 100644 docs/en/system_tables/index.md delete mode 100644 docs/en/system_tables/system.asynchronous_metrics.md delete mode 100644 docs/en/system_tables/system.clusters.md delete mode 100644 docs/en/system_tables/system.columns.md delete mode 100644 docs/en/system_tables/system.databases.md delete mode 100644 docs/en/system_tables/system.dictionaries.md delete mode 100644 docs/en/system_tables/system.events.md delete mode 100644 docs/en/system_tables/system.functions.md delete mode 100644 docs/en/system_tables/system.merges.md delete mode 100644 docs/en/system_tables/system.metrics.md delete mode 100644 docs/en/system_tables/system.numbers.md delete mode 100644 docs/en/system_tables/system.numbers_mt.md delete mode 100644 docs/en/system_tables/system.one.md delete mode 100644 docs/en/system_tables/system.parts.md delete mode 100644 docs/en/system_tables/system.processes.md delete mode 100644 docs/en/system_tables/system.replicas.md delete mode 100644 docs/en/system_tables/system.settings.md delete mode 100644 docs/en/system_tables/system.tables.md delete mode 100644 docs/en/system_tables/system.zookeeper.md create mode 100644 docs/ru/operations/system_tables.md delete mode 100644 docs/ru/system_tables/index.md delete mode 100644 docs/ru/system_tables/system.asynchronous_metrics.md delete mode 100644 docs/ru/system_tables/system.clusters.md delete mode 100644 docs/ru/system_tables/system.columns.md delete mode 100644 docs/ru/system_tables/system.databases.md delete mode 100644 docs/ru/system_tables/system.dictionaries.md delete mode 100644 docs/ru/system_tables/system.events.md delete mode 100644 docs/ru/system_tables/system.functions.md delete mode 100644 docs/ru/system_tables/system.merges.md delete mode 100644 docs/ru/system_tables/system.metrics.md delete mode 100644 docs/ru/system_tables/system.numbers.md delete mode 100644 docs/ru/system_tables/system.numbers_mt.md delete mode 100644 docs/ru/system_tables/system.one.md delete mode 100644 docs/ru/system_tables/system.parts.md delete mode 100644 docs/ru/system_tables/system.processes.md delete mode 100644 docs/ru/system_tables/system.replicas.md delete mode 100644 docs/ru/system_tables/system.settings.md delete mode 100644 docs/ru/system_tables/system.tables.md delete mode 100644 docs/ru/system_tables/system.zookeeper.md diff --git a/docs/en/operations/system_tables.md b/docs/en/operations/system_tables.md new file mode 100644 index 00000000000..b0a8aa55236 --- /dev/null +++ b/docs/en/operations/system_tables.md @@ -0,0 +1,414 @@ +# System tables + +System tables are used for implementing part of the system's functionality, and for providing access to information about how the system is working. +You can't delete a system table (but you can perform DETACH). +System tables don't have files with data on the disk or files with metadata. The server creates all the system tables when it starts. +System tables are read-only. +They are located in the 'system' database. + + + +## system.asynchronous_metrics + +Contain metrics used for profiling and monitoring. +They usually reflect the number of events currently in the system, or the total resources consumed by the system. +Example: The number of SELECT queries currently running; the amount of memory in use.`system.asynchronous_metrics`and`system.metrics` differ in their sets of metrics and how they are calculated. + +## system.clusters + +Contains information about clusters available in the config file and the servers in them. +Columns: + +```text +cluster String – Cluster name. +shard_num UInt32 – Number of a shard in the cluster, starting from 1. +shard_weight UInt32 – Relative weight of a shard when writing data. +replica_num UInt32 – Number of a replica in the shard, starting from 1. +host_name String – Host name as specified in the config. +host_address String – Host's IP address obtained from DNS. +port UInt16 – The port used to access the server. +user String – The username to use for connecting to the server. +``` +## system.columns + +Contains information about the columns in all tables. +You can use this table to get information similar to `DESCRIBE TABLE`, but for multiple tables at once. + +```text +database String - Name of the database the table is located in. +table String - Table name. +name String - Column name. +type String - Column type. +default_type String - Expression type (DEFAULT, MATERIALIZED, ALIAS) for the default value, or an empty string if it is not defined. +default_expression String - Expression for the default value, or an empty string if it is not defined. +``` + +## system.databases + +This table contains a single String column called 'name' – the name of a database. +Each database that the server knows about has a corresponding entry in the table. +This system table is used for implementing the `SHOW DATABASES` query. + +## system.dictionaries + +Contains information about external dictionaries. + +Columns: + +- `name String` – Dictionary name. +- `type String` – Dictionary type: Flat, Hashed, Cache. +- `origin String` – Path to the config file where the dictionary is described. +- `attribute.names Array(String)` – Array of attribute names provided by the dictionary. +- `attribute.types Array(String)` – Corresponding array of attribute types provided by the dictionary. +- `has_hierarchy UInt8` – Whether the dictionary is hierarchical. +- `bytes_allocated UInt64` – The amount of RAM used by the dictionary. +- `hit_rate Float64` – For cache dictionaries, the percent of usage for which the value was in the cache. +- `element_count UInt64` – The number of items stored in the dictionary. +- `load_factor Float64` – The filled percentage of the dictionary (for a hashed dictionary, it is the filled percentage of the hash table). +- `creation_time DateTime` – Time spent for the creation or last successful reload of the dictionary. +- `last_exception String` – Text of an error that occurred when creating or reloading the dictionary, if the dictionary couldn't be created. +- `source String` – Text describing the data source for the dictionary. + +Note that the amount of memory used by the dictionary is not proportional to the number of items stored in it. So for flat and cached dictionaries, all the memory cells are pre-assigned, regardless of how full the dictionary actually is. + + +## system.events + +Contains information about the number of events that have occurred in the system. This is used for profiling and monitoring purposes. +Example: The number of processed SELECT queries. +Columns: 'event String' – the event name, and 'value UInt64' – the quantity. + +## system.functions + +Contains information about normal and aggregate functions. + +Columns: + +- `name` (`String`) – Function name. +- `is_aggregate` (`UInt8`) – Whether it is an aggregate function. +## system.merges + +Contains information about merges currently in process for tables in the MergeTree family. + +Columns: + +- `database String` — Name of the database the table is located in. +- `table String` — Name of the table. +- `elapsed Float64` — Time in seconds since the merge started. +- `progress Float64` — Percent of progress made, from 0 to 1. +- `num_parts UInt64` — Number of parts to merge. +- `result_part_name String` — Name of the part that will be formed as the result of the merge. +- `total_size_bytes_compressed UInt64` — Total size of compressed data in the parts being merged. +- `total_size_marks UInt64` — Total number of marks in the parts being merged. +- `bytes_read_uncompressed UInt64` — Amount of bytes read, decompressed. +- `rows_read UInt64` — Number of rows read. +- `bytes_written_uncompressed UInt64` — Amount of bytes written, uncompressed. +- `rows_written UInt64` — Number of rows written. + + +## system.metrics + +## system.numbers + +This table contains a single UInt64 column named 'number' that contains almost all the natural numbers starting from zero. +You can use this table for tests, or if you need to do a brute force search. +Reads from this table are not parallelized. + +## system.numbers_mt + +The same as 'system.numbers' but reads are parallelized. The numbers can be returned in any order. +Used for tests. + +## system.one + +This table contains a single row with a single 'dummy' UInt8 column containing the value 0. +This table is used if a SELECT query doesn't specify the FROM clause. +This is similar to the DUAL table found in other DBMSs. + +## system.parts + +Contains information about parts of a table in the [MergeTree](../table_engines/mergetree.md#table_engines-mergetree) family. + +Each row describes one part of the data. + +Columns: + +- partition (String) – The partition name. It's in YYYYMM format in case of old-style partitioning and is arbitary serialized value in case of custom partitioning. To learn what a partition is, see the description of the [ALTER](../query_language/queries.md#query_language_queries_alter) query. +- name (String) – Name of the data part. +- active (UInt8) – Indicates whether the part is active. If a part is active, it is used in a table; otherwise, it will be deleted. Inactive data parts remain after merging. +- marks (UInt64) – The number of marks. To get the approximate number of rows in a data part, multiply ``marks`` by the index granularity (usually 8192). +- marks_size (UInt64) – The size of the file with marks. +- rows (UInt64) – The number of rows. +- bytes (UInt64) – The number of bytes when compressed. +- modification_time (DateTime) – The modification time of the directory with the data part. This usually corresponds to the time of data part creation.| +- remove_time (DateTime) – The time when the data part became inactive. +- refcount (UInt32) – The number of places where the data part is used. A value greater than 2 indicates that the data part is used in queries or merges. +- min_date (Date) – The minimum value of the date key in the data part. +- max_date (Date) – The maximum value of the date key in the data part. +- min_block_number (UInt64) – The minimum number of data parts that make up the current part after merging. +- max_block_number (UInt64) – The maximum number of data parts that make up the current part after merging. +- level (UInt32) – Depth of the merge tree. If a merge was not performed, ``level=0``. +- primary_key_bytes_in_memory (UInt64) – The amount of memory (in bytes) used by primary key values. +- primary_key_bytes_in_memory_allocated (UInt64) – The amount of memory (in bytes) reserved for primary key values. +- database (String) – Name of the database. +- table (String) – Name of the table. +- engine (String) – Name of the table engine without parameters. + +## system.processes + +This system table is used for implementing the `SHOW PROCESSLIST` query. +Columns: + +```text +user String – Name of the user who made the request. For distributed query processing, this is the user who helped the requestor server send the query to this server, not the user who made the distributed request on the requestor server. + +address String – The IP address that the query was made from. The same is true for distributed query processing. + +elapsed Float64 – The time in seconds since request execution started. + +rows_read UInt64 – The number of rows read from the table. For distributed processing, on the requestor server, this is the total for all remote servers. + +bytes_read UInt64 – The number of uncompressed bytes read from the table. For distributed processing, on the requestor server, this is the total for all remote servers. + +UInt64 total_rows_approx – The approximate total number of rows that must be read. For distributed processing, on the requestor server, this is the total for all remote servers. It can be updated during request processing, when new sources to process become known. + +memory_usage UInt64 – Memory consumption by the query. It might not include some types of dedicated memory. + +query String – The query text. For INSERT, it doesn't include the data to insert. + +query_id – Query ID, if defined. +``` + +## system.replicas + +Contains information and status for replicated tables residing on the local server. +This table can be used for monitoring. The table contains a row for every Replicated\* table. + +Example: + +```sql +SELECT * +FROM system.replicas +WHERE table = 'visits' +FORMAT Vertical +``` + +```text +Row 1: +────── +database: merge +table: visits +engine: ReplicatedCollapsingMergeTree +is_leader: 1 +is_readonly: 0 +is_session_expired: 0 +future_parts: 1 +parts_to_check: 0 +zookeeper_path: /clickhouse/tables/01-06/visits +replica_name: example01-06-1.yandex.ru +replica_path: /clickhouse/tables/01-06/visits/replicas/example01-06-1.yandex.ru +columns_version: 9 +queue_size: 1 +inserts_in_queue: 0 +merges_in_queue: 1 +log_max_index: 596273 +log_pointer: 596274 +total_replicas: 2 +active_replicas: 2 +``` + +Columns: + +```text +database: database name +table: table name +engine: table engine name + +is_leader: whether the replica is the leader + +Only one replica at a time can be the leader. The leader is responsible for selecting background merges to perform. +Note that writes can be performed to any replica that is available and has a session in ZK, regardless of whether it is a leader. + +is_readonly: Whether the replica is in read-only mode. +This mode is turned on if the config doesn't have sections with ZK, if an unknown error occurred when reinitializing sessions in ZK, and during session reinitialization in ZK. + +is_session_expired: Whether the ZK session expired. +Basically, the same thing as is_readonly. + +future_parts: The number of data parts that will appear as the result of INSERTs or merges that haven't been done yet. + +parts_to_check: The number of data parts in the queue for verification. +A part is put in the verification queue if there is suspicion that it might be damaged. + +zookeeper_path: The path to the table data in ZK. +replica_name: Name of the replica in ZK. Different replicas of the same table have different names. +replica_path: The path to the replica data in ZK. The same as concatenating zookeeper_path/replicas/replica_path. + +columns_version: Version number of the table structure. +Indicates how many times ALTER was performed. If replicas have different versions, it means some replicas haven't made all of the ALTERs yet. + +queue_size: Size of the queue for operations waiting to be performed. +Operations include inserting blocks of data, merges, and certain other actions. +Normally coincides with future_parts. + +inserts_in_queue: Number of inserts of blocks of data that need to be made. +Insertions are usually replicated fairly quickly. If the number is high, something is wrong. + +merges_in_queue: The number of merges waiting to be made. +Sometimes merges are lengthy, so this value may be greater than zero for a long time. + +The next 4 columns have a non-null value only if the ZK session is active. + +log_max_index: Maximum entry number in the log of general activity. +log_pointer: Maximum entry number in the log of general activity that the replica copied to its execution queue, plus one. +If log_pointer is much smaller than log_max_index, something is wrong. + +total_replicas: Total number of known replicas of this table. +active_replicas: Number of replicas of this table that have a ZK session (the number of active replicas). +``` + +If you request all the columns, the table may work a bit slowly, since several reads from ZK are made for each row. +If you don't request the last 4 columns (log_max_index, log_pointer, total_replicas, active_replicas), the table works quickly. + +For example, you can check that everything is working correctly like this: + +```sql +SELECT + database, + table, + is_leader, + is_readonly, + is_session_expired, + future_parts, + parts_to_check, + columns_version, + queue_size, + inserts_in_queue, + merges_in_queue, + log_max_index, + log_pointer, + total_replicas, + active_replicas +FROM system.replicas +WHERE + is_readonly + OR is_session_expired + OR future_parts > 20 + OR parts_to_check > 10 + OR queue_size > 20 + OR inserts_in_queue > 10 + OR log_max_index - log_pointer > 10 + OR total_replicas < 2 + OR active_replicas < total_replicas +``` + +If this query doesn't return anything, it means that everything is fine. + +## system.settings + +Contains information about settings that are currently in use. +I.e. used for executing the query you are using to read from the system.settings table). + +Columns: + +```text +name String – Setting name. +value String – Setting value. +changed UInt8 - Whether the setting was explicitly defined in the config or explicitly changed. +``` + +Example: + +```sql +SELECT * +FROM system.settings +WHERE changed +``` + +```text +┌─name───────────────────┬─value───────┬─changed─┐ +│ max_threads │ 8 │ 1 │ +│ use_uncompressed_cache │ 0 │ 1 │ +│ load_balancing │ random │ 1 │ +│ max_memory_usage │ 10000000000 │ 1 │ +└────────────────────────┴─────────────┴─────────┘ +``` + +## system.tables + +This table contains the String columns 'database', 'name', and 'engine'. +The table also contains three virtual columns: metadata_modification_time (DateTime type), create_table_query, and engine_full (String type). +Each table that the server knows about is entered in the 'system.tables' table. +This system table is used for implementing SHOW TABLES queries. + +## system.zookeeper + +This table presents when ZooKeeper is configured. It allows reading data from the ZooKeeper cluster defined in the config. +The query must have a 'path' equality condition in the WHERE clause. This is the path in ZooKeeper for the children that you want to get data for. + +The query `SELECT * FROM system.zookeeper WHERE path = '/clickhouse'` outputs data for all children on the `/clickhouse` node. +To output data for all root nodes, write path = '/'. +If the path specified in 'path' doesn't exist, an exception will be thrown. + +Columns: + +- `name String` — Name of the node. +- `path String` — Path to the node. +- `value String` — Value of the node. +- `dataLength Int32` — Size of the value. +- `numChildren Int32` — Number of children. +- `czxid Int64` — ID of the transaction that created the node. +- `mzxid Int64` — ID of the transaction that last changed the node. +- `pzxid Int64` — ID of the transaction that last added or removed children. +- `ctime DateTime` — Time of node creation. +- `mtime DateTime` — Time of the last node modification. +- `version Int32` — Node version - the number of times the node was changed. +- `cversion Int32` — Number of added or removed children. +- `aversion Int32` — Number of changes to ACL. +- `ephemeralOwner Int64` — For ephemeral nodes, the ID of the session that owns this node. + + +Example: + +```sql +SELECT * +FROM system.zookeeper +WHERE path = '/clickhouse/tables/01-08/visits/replicas' +FORMAT Vertical +``` + +```text +Row 1: +────── +name: example01-08-1.yandex.ru +value: +czxid: 932998691229 +mzxid: 932998691229 +ctime: 2015-03-27 16:49:51 +mtime: 2015-03-27 16:49:51 +version: 0 +cversion: 47 +aversion: 0 +ephemeralOwner: 0 +dataLength: 0 +numChildren: 7 +pzxid: 987021031383 +path: /clickhouse/tables/01-08/visits/replicas + +Row 2: +────── +name: example01-08-2.yandex.ru +value: +czxid: 933002738135 +mzxid: 933002738135 +ctime: 2015-03-27 16:57:01 +mtime: 2015-03-27 16:57:01 +version: 0 +cversion: 37 +aversion: 0 +ephemeralOwner: 0 +dataLength: 0 +numChildren: 7 +pzxid: 987021252247 +path: /clickhouse/tables/01-08/visits/replicas +``` diff --git a/docs/en/system_tables/index.md b/docs/en/system_tables/index.md deleted file mode 100644 index 240105a684b..00000000000 --- a/docs/en/system_tables/index.md +++ /dev/null @@ -1,8 +0,0 @@ -# System tables - -System tables are used for implementing part of the system's functionality, and for providing access to information about how the system is working. -You can't delete a system table (but you can perform DETACH). -System tables don't have files with data on the disk or files with metadata. The server creates all the system tables when it starts. -System tables are read-only. -They are located in the 'system' database. - diff --git a/docs/en/system_tables/system.asynchronous_metrics.md b/docs/en/system_tables/system.asynchronous_metrics.md deleted file mode 100644 index 4c2c4877d66..00000000000 --- a/docs/en/system_tables/system.asynchronous_metrics.md +++ /dev/null @@ -1,8 +0,0 @@ - - -# system.asynchronous_metrics - -Contain metrics used for profiling and monitoring. -They usually reflect the number of events currently in the system, or the total resources consumed by the system. -Example: The number of SELECT queries currently running; the amount of memory in use.`system.asynchronous_metrics`and`system.metrics` differ in their sets of metrics and how they are calculated. - diff --git a/docs/en/system_tables/system.clusters.md b/docs/en/system_tables/system.clusters.md deleted file mode 100644 index 1241b22f183..00000000000 --- a/docs/en/system_tables/system.clusters.md +++ /dev/null @@ -1,15 +0,0 @@ -# system.clusters - -Contains information about clusters available in the config file and the servers in them. -Columns: - -```text -cluster String – Cluster name. -shard_num UInt32 – Number of a shard in the cluster, starting from 1. -shard_weight UInt32 – Relative weight of a shard when writing data. -replica_num UInt32 – Number of a replica in the shard, starting from 1. -host_name String – Host name as specified in the config. -host_address String – Host's IP address obtained from DNS. -port UInt16 – The port used to access the server. -user String – The username to use for connecting to the server. -``` diff --git a/docs/en/system_tables/system.columns.md b/docs/en/system_tables/system.columns.md deleted file mode 100644 index 975b84fe9d4..00000000000 --- a/docs/en/system_tables/system.columns.md +++ /dev/null @@ -1,14 +0,0 @@ -# system.columns - -Contains information about the columns in all tables. -You can use this table to get information similar to `DESCRIBE TABLE`, but for multiple tables at once. - -```text -database String - Name of the database the table is located in. -table String - Table name. -name String - Column name. -type String - Column type. -default_type String - Expression type (DEFAULT, MATERIALIZED, ALIAS) for the default value, or an empty string if it is not defined. -default_expression String - Expression for the default value, or an empty string if it is not defined. -``` - diff --git a/docs/en/system_tables/system.databases.md b/docs/en/system_tables/system.databases.md deleted file mode 100644 index ea062907c11..00000000000 --- a/docs/en/system_tables/system.databases.md +++ /dev/null @@ -1,6 +0,0 @@ -# system.databases - -This table contains a single String column called 'name' – the name of a database. -Each database that the server knows about has a corresponding entry in the table. -This system table is used for implementing the `SHOW DATABASES` query. - diff --git a/docs/en/system_tables/system.dictionaries.md b/docs/en/system_tables/system.dictionaries.md deleted file mode 100644 index 0694902c656..00000000000 --- a/docs/en/system_tables/system.dictionaries.md +++ /dev/null @@ -1,21 +0,0 @@ -# system.dictionaries - -Contains information about external dictionaries. - -Columns: - -- `name String` – Dictionary name. -- `type String` – Dictionary type: Flat, Hashed, Cache. -- `origin String` – Path to the config file where the dictionary is described. -- `attribute.names Array(String)` – Array of attribute names provided by the dictionary. -- `attribute.types Array(String)` – Corresponding array of attribute types provided by the dictionary. -- `has_hierarchy UInt8` – Whether the dictionary is hierarchical. -- `bytes_allocated UInt64` – The amount of RAM used by the dictionary. -- `hit_rate Float64` – For cache dictionaries, the percent of usage for which the value was in the cache. -- `element_count UInt64` – The number of items stored in the dictionary. -- `load_factor Float64` – The filled percentage of the dictionary (for a hashed dictionary, it is the filled percentage of the hash table). -- `creation_time DateTime` – Time spent for the creation or last successful reload of the dictionary. -- `last_exception String` – Text of an error that occurred when creating or reloading the dictionary, if the dictionary couldn't be created. -- `source String` – Text describing the data source for the dictionary. - -Note that the amount of memory used by the dictionary is not proportional to the number of items stored in it. So for flat and cached dictionaries, all the memory cells are pre-assigned, regardless of how full the dictionary actually is. diff --git a/docs/en/system_tables/system.events.md b/docs/en/system_tables/system.events.md deleted file mode 100644 index 87c0700e6d7..00000000000 --- a/docs/en/system_tables/system.events.md +++ /dev/null @@ -1,8 +0,0 @@ - - -# system.events - -Contains information about the number of events that have occurred in the system. This is used for profiling and monitoring purposes. -Example: The number of processed SELECT queries. -Columns: 'event String' – the event name, and 'value UInt64' – the quantity. - diff --git a/docs/en/system_tables/system.functions.md b/docs/en/system_tables/system.functions.md deleted file mode 100644 index a501dc54741..00000000000 --- a/docs/en/system_tables/system.functions.md +++ /dev/null @@ -1,8 +0,0 @@ -# system.functions - -Contains information about normal and aggregate functions. - -Columns: - -- `name` (`String`) – Function name. -- `is_aggregate` (`UInt8`) – Whether it is an aggregate function. diff --git a/docs/en/system_tables/system.merges.md b/docs/en/system_tables/system.merges.md deleted file mode 100644 index 2844f6ab837..00000000000 --- a/docs/en/system_tables/system.merges.md +++ /dev/null @@ -1,18 +0,0 @@ -# system.merges - -Contains information about merges currently in process for tables in the MergeTree family. - -Columns: - -- `database String` — Name of the database the table is located in. -- `table String` — Name of the table. -- `elapsed Float64` — Time in seconds since the merge started. -- `progress Float64` — Percent of progress made, from 0 to 1. -- `num_parts UInt64` — Number of parts to merge. -- `result_part_name String` — Name of the part that will be formed as the result of the merge. -- `total_size_bytes_compressed UInt64` — Total size of compressed data in the parts being merged. -- `total_size_marks UInt64` — Total number of marks in the parts being merged. -- `bytes_read_uncompressed UInt64` — Amount of bytes read, decompressed. -- `rows_read UInt64` — Number of rows read. -- `bytes_written_uncompressed UInt64` — Amount of bytes written, uncompressed. -- `rows_written UInt64` — Number of rows written. diff --git a/docs/en/system_tables/system.metrics.md b/docs/en/system_tables/system.metrics.md deleted file mode 100644 index 39acbaae0dc..00000000000 --- a/docs/en/system_tables/system.metrics.md +++ /dev/null @@ -1,4 +0,0 @@ - - -# system.metrics - diff --git a/docs/en/system_tables/system.numbers.md b/docs/en/system_tables/system.numbers.md deleted file mode 100644 index 42bbe391e2d..00000000000 --- a/docs/en/system_tables/system.numbers.md +++ /dev/null @@ -1,6 +0,0 @@ -# system.numbers - -This table contains a single UInt64 column named 'number' that contains almost all the natural numbers starting from zero. -You can use this table for tests, or if you need to do a brute force search. -Reads from this table are not parallelized. - diff --git a/docs/en/system_tables/system.numbers_mt.md b/docs/en/system_tables/system.numbers_mt.md deleted file mode 100644 index 9b8064182f7..00000000000 --- a/docs/en/system_tables/system.numbers_mt.md +++ /dev/null @@ -1,5 +0,0 @@ -# system.numbers_mt - -The same as 'system.numbers' but reads are parallelized. The numbers can be returned in any order. -Used for tests. - diff --git a/docs/en/system_tables/system.one.md b/docs/en/system_tables/system.one.md deleted file mode 100644 index cb170010104..00000000000 --- a/docs/en/system_tables/system.one.md +++ /dev/null @@ -1,6 +0,0 @@ -# system.one - -This table contains a single row with a single 'dummy' UInt8 column containing the value 0. -This table is used if a SELECT query doesn't specify the FROM clause. -This is similar to the DUAL table found in other DBMSs. - diff --git a/docs/en/system_tables/system.parts.md b/docs/en/system_tables/system.parts.md deleted file mode 100644 index 7e56d139219..00000000000 --- a/docs/en/system_tables/system.parts.md +++ /dev/null @@ -1,29 +0,0 @@ -# system.parts - -Contains information about parts of a table in the [MergeTree](../table_engines/mergetree.md#table_engines-mergetree) family. - -Each row describes one part of the data. - -Columns: - -- partition (String) – The partition name. It's in YYYYMM format in case of old-style partitioning and is arbitary serialized value in case of custom partitioning. To learn what a partition is, see the description of the [ALTER](../query_language/queries.md#query_language_queries_alter) query. -- name (String) – Name of the data part. -- active (UInt8) – Indicates whether the part is active. If a part is active, it is used in a table; otherwise, it will be deleted. Inactive data parts remain after merging. -- marks (UInt64) – The number of marks. To get the approximate number of rows in a data part, multiply ``marks`` by the index granularity (usually 8192). -- marks_size (UInt64) – The size of the file with marks. -- rows (UInt64) – The number of rows. -- bytes (UInt64) – The number of bytes when compressed. -- modification_time (DateTime) – The modification time of the directory with the data part. This usually corresponds to the time of data part creation.| -- remove_time (DateTime) – The time when the data part became inactive. -- refcount (UInt32) – The number of places where the data part is used. A value greater than 2 indicates that the data part is used in queries or merges. -- min_date (Date) – The minimum value of the date key in the data part. -- max_date (Date) – The maximum value of the date key in the data part. -- min_block_number (UInt64) – The minimum number of data parts that make up the current part after merging. -- max_block_number (UInt64) – The maximum number of data parts that make up the current part after merging. -- level (UInt32) – Depth of the merge tree. If a merge was not performed, ``level=0``. -- primary_key_bytes_in_memory (UInt64) – The amount of memory (in bytes) used by primary key values. -- primary_key_bytes_in_memory_allocated (UInt64) – The amount of memory (in bytes) reserved for primary key values. -- database (String) – Name of the database. -- table (String) – Name of the table. -- engine (String) – Name of the table engine without parameters. - diff --git a/docs/en/system_tables/system.processes.md b/docs/en/system_tables/system.processes.md deleted file mode 100644 index ba449c280e9..00000000000 --- a/docs/en/system_tables/system.processes.md +++ /dev/null @@ -1,25 +0,0 @@ -# system.processes - -This system table is used for implementing the `SHOW PROCESSLIST` query. -Columns: - -```text -user String – Name of the user who made the request. For distributed query processing, this is the user who helped the requestor server send the query to this server, not the user who made the distributed request on the requestor server. - -address String – The IP address that the query was made from. The same is true for distributed query processing. - -elapsed Float64 – The time in seconds since request execution started. - -rows_read UInt64 – The number of rows read from the table. For distributed processing, on the requestor server, this is the total for all remote servers. - -bytes_read UInt64 – The number of uncompressed bytes read from the table. For distributed processing, on the requestor server, this is the total for all remote servers. - -UInt64 total_rows_approx – The approximate total number of rows that must be read. For distributed processing, on the requestor server, this is the total for all remote servers. It can be updated during request processing, when new sources to process become known. - -memory_usage UInt64 – Memory consumption by the query. It might not include some types of dedicated memory. - -query String – The query text. For INSERT, it doesn't include the data to insert. - -query_id – Query ID, if defined. -``` - diff --git a/docs/en/system_tables/system.replicas.md b/docs/en/system_tables/system.replicas.md deleted file mode 100644 index c777e35bad0..00000000000 --- a/docs/en/system_tables/system.replicas.md +++ /dev/null @@ -1,125 +0,0 @@ -# system.replicas - -Contains information and status for replicated tables residing on the local server. -This table can be used for monitoring. The table contains a row for every Replicated\* table. - -Example: - -```sql -SELECT * -FROM system.replicas -WHERE table = 'visits' -FORMAT Vertical -``` - -```text -Row 1: -────── -database: merge -table: visits -engine: ReplicatedCollapsingMergeTree -is_leader: 1 -is_readonly: 0 -is_session_expired: 0 -future_parts: 1 -parts_to_check: 0 -zookeeper_path: /clickhouse/tables/01-06/visits -replica_name: example01-06-1.yandex.ru -replica_path: /clickhouse/tables/01-06/visits/replicas/example01-06-1.yandex.ru -columns_version: 9 -queue_size: 1 -inserts_in_queue: 0 -merges_in_queue: 1 -log_max_index: 596273 -log_pointer: 596274 -total_replicas: 2 -active_replicas: 2 -``` - -Columns: - -```text -database: database name -table: table name -engine: table engine name - -is_leader: whether the replica is the leader - -Only one replica at a time can be the leader. The leader is responsible for selecting background merges to perform. -Note that writes can be performed to any replica that is available and has a session in ZK, regardless of whether it is a leader. - -is_readonly: Whether the replica is in read-only mode. -This mode is turned on if the config doesn't have sections with ZK, if an unknown error occurred when reinitializing sessions in ZK, and during session reinitialization in ZK. - -is_session_expired: Whether the ZK session expired. -Basically, the same thing as is_readonly. - -future_parts: The number of data parts that will appear as the result of INSERTs or merges that haven't been done yet. - -parts_to_check: The number of data parts in the queue for verification. -A part is put in the verification queue if there is suspicion that it might be damaged. - -zookeeper_path: The path to the table data in ZK. -replica_name: Name of the replica in ZK. Different replicas of the same table have different names. -replica_path: The path to the replica data in ZK. The same as concatenating zookeeper_path/replicas/replica_path. - -columns_version: Version number of the table structure. -Indicates how many times ALTER was performed. If replicas have different versions, it means some replicas haven't made all of the ALTERs yet. - -queue_size: Size of the queue for operations waiting to be performed. -Operations include inserting blocks of data, merges, and certain other actions. -Normally coincides with future_parts. - -inserts_in_queue: Number of inserts of blocks of data that need to be made. -Insertions are usually replicated fairly quickly. If the number is high, something is wrong. - -merges_in_queue: The number of merges waiting to be made. -Sometimes merges are lengthy, so this value may be greater than zero for a long time. - -The next 4 columns have a non-null value only if the ZK session is active. - -log_max_index: Maximum entry number in the log of general activity. -log_pointer: Maximum entry number in the log of general activity that the replica copied to its execution queue, plus one. -If log_pointer is much smaller than log_max_index, something is wrong. - -total_replicas: Total number of known replicas of this table. -active_replicas: Number of replicas of this table that have a ZK session (the number of active replicas). -``` - -If you request all the columns, the table may work a bit slowly, since several reads from ZK are made for each row. -If you don't request the last 4 columns (log_max_index, log_pointer, total_replicas, active_replicas), the table works quickly. - -For example, you can check that everything is working correctly like this: - -```sql -SELECT - database, - table, - is_leader, - is_readonly, - is_session_expired, - future_parts, - parts_to_check, - columns_version, - queue_size, - inserts_in_queue, - merges_in_queue, - log_max_index, - log_pointer, - total_replicas, - active_replicas -FROM system.replicas -WHERE - is_readonly - OR is_session_expired - OR future_parts > 20 - OR parts_to_check > 10 - OR queue_size > 20 - OR inserts_in_queue > 10 - OR log_max_index - log_pointer > 10 - OR total_replicas < 2 - OR active_replicas < total_replicas -``` - -If this query doesn't return anything, it means that everything is fine. - diff --git a/docs/en/system_tables/system.settings.md b/docs/en/system_tables/system.settings.md deleted file mode 100644 index 90a392bcc24..00000000000 --- a/docs/en/system_tables/system.settings.md +++ /dev/null @@ -1,30 +0,0 @@ -# system.settings - -Contains information about settings that are currently in use. -I.e. used for executing the query you are using to read from the system.settings table). - -Columns: - -```text -name String – Setting name. -value String – Setting value. -changed UInt8 - Whether the setting was explicitly defined in the config or explicitly changed. -``` - -Example: - -```sql -SELECT * -FROM system.settings -WHERE changed -``` - -```text -┌─name───────────────────┬─value───────┬─changed─┐ -│ max_threads │ 8 │ 1 │ -│ use_uncompressed_cache │ 0 │ 1 │ -│ load_balancing │ random │ 1 │ -│ max_memory_usage │ 10000000000 │ 1 │ -└────────────────────────┴─────────────┴─────────┘ -``` - diff --git a/docs/en/system_tables/system.tables.md b/docs/en/system_tables/system.tables.md deleted file mode 100644 index 5757a8ac3da..00000000000 --- a/docs/en/system_tables/system.tables.md +++ /dev/null @@ -1,7 +0,0 @@ -# system.tables - -This table contains the String columns 'database', 'name', and 'engine'. -The table also contains three virtual columns: metadata_modification_time (DateTime type), create_table_query, and engine_full (String type). -Each table that the server knows about is entered in the 'system.tables' table. -This system table is used for implementing SHOW TABLES queries. - diff --git a/docs/en/system_tables/system.zookeeper.md b/docs/en/system_tables/system.zookeeper.md deleted file mode 100644 index ec3046ebc16..00000000000 --- a/docs/en/system_tables/system.zookeeper.md +++ /dev/null @@ -1,71 +0,0 @@ -# system.zookeeper - -This table presents when ZooKeeper is configured. It allows reading data from the ZooKeeper cluster defined in the config. -The query must have a 'path' equality condition in the WHERE clause. This is the path in ZooKeeper for the children that you want to get data for. - -The query `SELECT * FROM system.zookeeper WHERE path = '/clickhouse'` outputs data for all children on the `/clickhouse` node. -To output data for all root nodes, write path = '/'. -If the path specified in 'path' doesn't exist, an exception will be thrown. - -Columns: - -- `name String` — Name of the node. -- `path String` — Path to the node. -- `value String` — Value of the node. -- `dataLength Int32` — Size of the value. -- `numChildren Int32` — Number of children. -- `czxid Int64` — ID of the transaction that created the node. -- `mzxid Int64` — ID of the transaction that last changed the node. -- `pzxid Int64` — ID of the transaction that last added or removed children. -- `ctime DateTime` — Time of node creation. -- `mtime DateTime` — Time of the last node modification. -- `version Int32` — Node version - the number of times the node was changed. -- `cversion Int32` — Number of added or removed children. -- `aversion Int32` — Number of changes to ACL. -- `ephemeralOwner Int64` — For ephemeral nodes, the ID of the session that owns this node. - - -Example: - -```sql -SELECT * -FROM system.zookeeper -WHERE path = '/clickhouse/tables/01-08/visits/replicas' -FORMAT Vertical -``` - -```text -Row 1: -────── -name: example01-08-1.yandex.ru -value: -czxid: 932998691229 -mzxid: 932998691229 -ctime: 2015-03-27 16:49:51 -mtime: 2015-03-27 16:49:51 -version: 0 -cversion: 47 -aversion: 0 -ephemeralOwner: 0 -dataLength: 0 -numChildren: 7 -pzxid: 987021031383 -path: /clickhouse/tables/01-08/visits/replicas - -Row 2: -────── -name: example01-08-2.yandex.ru -value: -czxid: 933002738135 -mzxid: 933002738135 -ctime: 2015-03-27 16:57:01 -mtime: 2015-03-27 16:57:01 -version: 0 -cversion: 37 -aversion: 0 -ephemeralOwner: 0 -dataLength: 0 -numChildren: 7 -pzxid: 987021252247 -path: /clickhouse/tables/01-08/visits/replicas -``` diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 6d25d7fec81..9d07d7711db 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -60,27 +60,6 @@ pages: - 'MySQL': 'table_engines/mysql.md' - 'External data for query processing': 'table_engines/external_data.md' -- 'System tables': - - 'Introduction': 'system_tables/index.md' - - 'system.one': 'system_tables/system.one.md' - - 'system.numbers': 'system_tables/system.numbers.md' - - 'system.numbers_mt': 'system_tables/system.numbers_mt.md' - - 'system.databases': 'system_tables/system.databases.md' - - 'system.tables': 'system_tables/system.tables.md' - - 'system.columns': 'system_tables/system.columns.md' - - 'system.parts': 'system_tables/system.parts.md' - - 'system.processes': 'system_tables/system.processes.md' - - 'system.merges': 'system_tables/system.merges.md' - - 'system.events': 'system_tables/system.events.md' - - 'system.metrics': 'system_tables/system.metrics.md' - - 'system.asynchronous_metrics': 'system_tables/system.asynchronous_metrics.md' - - 'system.replicas': 'system_tables/system.replicas.md' - - 'system.dictionaries': 'system_tables/system.dictionaries.md' - - 'system.clusters': 'system_tables/system.clusters.md' - - 'system.functions': 'system_tables/system.functions.md' - - 'system.settings': 'system_tables/system.settings.md' - - 'system.zookeeper': 'system_tables/system.zookeeper.md' - - 'Table functions': - 'Introduction': 'table_functions/index.md' - 'file': 'table_functions/file.md' @@ -188,6 +167,7 @@ pages: - 'Access rights': 'operations/access_rights.md' - 'Configuration files': 'operations/configuration_files.md' - 'Quotas': 'operations/quotas.md' + - 'System tables': 'operations/system_tables.md' - 'Usage recommendations': 'operations/tips.md' - 'Server configuration parameters': - 'Introduction': 'operations/server_settings/index.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index d0ee6805e73..646456eb32b 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -60,27 +60,6 @@ pages: - 'MySQL': 'table_engines/mysql.md' - 'Внешние данные для обработки запроса': 'table_engines/external_data.md' -- 'Системные таблицы': - - 'Введение': 'system_tables/index.md' - - 'system.one': 'system_tables/system.one.md' - - 'system.numbers': 'system_tables/system.numbers.md' - - 'system.numbers_mt': 'system_tables/system.numbers_mt.md' - - 'system.databases': 'system_tables/system.databases.md' - - 'system.tables': 'system_tables/system.tables.md' - - 'system.columns': 'system_tables/system.columns.md' - - 'system.parts': 'system_tables/system.parts.md' - - 'system.processes': 'system_tables/system.processes.md' - - 'system.merges': 'system_tables/system.merges.md' - - 'system.events': 'system_tables/system.events.md' - - 'system.metrics': 'system_tables/system.metrics.md' - - 'system.asynchronous_metrics': 'system_tables/system.asynchronous_metrics.md' - - 'system.replicas': 'system_tables/system.replicas.md' - - 'system.dictionaries': 'system_tables/system.dictionaries.md' - - 'system.clusters': 'system_tables/system.clusters.md' - - 'system.functions': 'system_tables/system.functions.md' - - 'system.settings': 'system_tables/system.settings.md' - - 'system.zookeeper': 'system_tables/system.zookeeper.md' - - 'Табличные функции': - 'Введение': 'table_functions/index.md' - 'file': 'table_functions/file.md' @@ -189,6 +168,7 @@ pages: - 'Права доступа': 'operations/access_rights.md' - 'Конфигурационные файлы': 'operations/configuration_files.md' - 'Квоты': 'operations/quotas.md' + - 'Системные таблицы': 'operations/system_tables.md' - 'Советы по эксплуатации': 'operations/tips.md' - 'Конфигурационные параметры сервера': - 'Введение': 'operations/server_settings/index.md' diff --git a/docs/redirects.txt b/docs/redirects.txt index f6df51ba9c7..230c8919098 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -1 +1,19 @@ -test.md roadmap.md +system_tables.md operations/system_tables.md +system_tables/system.asynchronous_metrics.md operations/system_tables.md +system_tables/system.clusters.md operations/system_tables.md +system_tables/system.columns.md operations/system_tables.md +system_tables/system.databases.md operations/system_tables.md +system_tables/system.dictionaries.md operations/system_tables.md +system_tables/system.events.md operations/system_tables.md +system_tables/system.functions.md operations/system_tables.md +system_tables/system.merges.md operations/system_tables.md +system_tables/system.metrics.md operations/system_tables.md +system_tables/system.numbers.md operations/system_tables.md +system_tables/system.numbers_mt.md operations/system_tables.md +system_tables/system.one.md operations/system_tables.md +system_tables/system.parts.md operations/system_tables.md +system_tables/system.processes.md operations/system_tables.md +system_tables/system.replicas.md operations/system_tables.md +system_tables/system.settings.md operations/system_tables.md +system_tables/system.tables.md operations/system_tables.md +system_tables/system.zookeeper.md operations/system_tables.md diff --git a/docs/ru/operations/system_tables.md b/docs/ru/operations/system_tables.md new file mode 100644 index 00000000000..277e89d644f --- /dev/null +++ b/docs/ru/operations/system_tables.md @@ -0,0 +1,402 @@ +# Системные таблицы + +Системные таблицы используются для реализации части функциональности системы, а также предоставляют доступ к информации о работе системы. +Вы не можете удалить системную таблицу (хотя можете сделать DETACH). +Для системных таблиц нет файлов с данными на диске и файлов с метаданными. Сервер создаёт все системные таблицы при старте. +В системные таблицы нельзя записывать данные - можно только читать. +Системные таблицы расположены в базе данных system. + + +# system.asynchronous_metrics + +Содержат метрики, используемые для профилирования и мониторинга. +Обычно отражают количество событий, происходящих в данный момент в системе, или ресурсов, суммарно потребляемых системой. +Пример: количество запросов типа SELECT, исполняемых в текущий момент; количество потребляемой памяти. +`system.asynchronous_metrics` и `system.metrics` отличаются набором и способом вычисления метрик. +# system.clusters + +Содержит информацию о доступных в конфигурационном файле кластерах и серверах, которые в них входят. +Столбцы: + +```text +cluster String - имя кластера +shard_num UInt32 - номер шарда в кластере, начиная с 1 +shard_weight UInt32 - относительный вес шарда при записи данных +replica_num UInt32 - номер реплики в шарде, начиная с 1 +host_name String - имя хоста, как прописано в конфиге +host_address String - IP-адрес хоста, полученный из DNS +port UInt16 - порт, на который обращаться для соединения с сервером +user String - имя пользователя, которого использовать для соединения с сервером +``` +# system.columns + +Содержит информацию о столбцах всех таблиц. +С помощью этой таблицы можно получить информацию аналогично запросу `DESCRIBE TABLE`, но для многих таблиц сразу. + +```text +database String - имя базы данных, в которой находится таблица +table String - имя таблицы +name String - имя столбца +type String - тип столбца +default_type String - тип (DEFAULT, MATERIALIZED, ALIAS) выражения для значения по умолчанию, или пустая строка, если оно не описано +default_expression String - выражение для значения по умолчанию, или пустая строка, если оно не описано +``` +# system.databases + +Таблица содержит один столбец name типа String - имя базы данных. +Для каждой базы данных, о которой знает сервер, будет присутствовать соответствующая запись в таблице. +Эта системная таблица используется для реализации запроса `SHOW DATABASES`. +# system.dictionaries + +Содержит информацию о внешних словарях. + +Столбцы: + +- `name String` — Имя словаря. +- `type String` — Тип словаря: Flat, Hashed, Cache. +- `origin String` — Путь к конфигурационному файлу, в котором описан словарь. +- `attribute.names Array(String)` — Массив имён атрибутов, предоставляемых словарём. +- `attribute.types Array(String)` — Соответствующий массив типов атрибутов, предоставляемых словарём. +- `has_hierarchy UInt8` — Является ли словарь иерархическим. +- `bytes_allocated UInt64` — Количество оперативной памяти, которое использует словарь. +- `hit_rate Float64` — Для cache-словарей - доля использований, для которых значение было в кэше. +- `element_count UInt64` — Количество хранящихся в словаре элементов. +- `load_factor Float64` — Доля заполненности словаря (для hashed словаря - доля заполнения хэш-таблицы). +- `creation_time DateTime` — Время создания или последней успешной перезагрузки словаря. +- `last_exception String` — Текст ошибки, возникшей при создании или перезагрузке словаря, если словарь не удалось создать. +- `source String` - Текст, описывающий источник данных для словаря. + + +Заметим, что количество оперативной памяти, которое использует словарь, не является пропорциональным количеству элементов, хранящихся в словаре. Так, для flat и cached словарей, все ячейки памяти выделяются заранее, независимо от реальной заполненности словаря. + + +# system.events + +Содержит информацию о количестве произошедших в системе событий, для профилирования и мониторинга. +Пример: количество обработанных запросов типа SELECT. +Столбцы: event String - имя события, value UInt64 - количество. +# system.functions + +Содержит информацию об обычных и агрегатных функциях. + +Столбцы: + +- `name` (`String`) – Имя функции. +- `is_aggregate` (`UInt8`) – Признак, является ли функция агрегатной. +# system.merges + +Содержит информацию о производящихся прямо сейчас слияниях для таблиц семейства MergeTree. + +Столбцы: + +- `database String` — Имя базы данных, в которой находится таблица. +- `table String` — Имя таблицы. +- `elapsed Float64` — Время в секундах, прошедшее от начала выполнения слияния. +- `progress Float64` — Доля выполненной работы от 0 до 1. +- `num_parts UInt64` — Количество сливаемых кусков. +- `result_part_name String` — Имя куска, который будет образован в результате слияния. +- `total_size_bytes_compressed UInt64` — Суммарный размер сжатых данных сливаемых кусков. +- `total_size_marks UInt64` — Суммарное количество засечек в сливаемых кусках. +- `bytes_read_uncompressed UInt64` — Количество прочитанных байт, разжатых. +- `rows_read UInt64` — Количество прочитанных строк. +- `bytes_written_uncompressed UInt64` — Количество записанных байт, несжатых. +- `rows_written UInt64` — Количество записанных строк. + + +# system.metrics +# system.numbers + +Таблица содержит один столбец с именем number типа UInt64, содержащим почти все натуральные числа, начиная с нуля. +Эту таблицу можно использовать для тестов, а также если вам нужно сделать перебор. +Чтения из этой таблицы не распараллеливаются. +# system.numbers_mt + +То же самое, что и system.numbers, но чтение распараллеливается. Числа могут возвращаться в произвольном порядке. +Используется для тестов. +# system.one + +Таблица содержит одну строку с одним столбцом dummy типа UInt8, содержащим значение 0. +Эта таблица используется, если в SELECT запросе не указана секция FROM. +То есть, это - аналог таблицы DUAL, которую можно найти в других СУБД. +# system.parts + +Содержит информацию о кусках таблиц семейства [MergeTree](../table_engines/mergetree.md#table_engines-mergetree). + +Каждая строка описывает один кусок данных. + +Столбцы: + +- partition (String) - Имя партиции. Формат YYYYMM. Что такое партиция можно узнать из описания запроса [ALTER](../query_language/queries.md#query_language_queries_alter). +- name (String) - Имя куска. +- active (UInt8) - Признак активности. Если кусок активен, то он используется таблице, в противном случает он будет удален. Неактивные куски остаются после слияний. +- marks (UInt64) - Количество засечек. Чтобы получить примерное количество строк в куске, умножьте ``marks`` на гранулированность индекса (обычно 8192). +- marks_size (UInt64) - Размер файла с засечками. +- rows (UInt64) - Количество строк. +- bytes (UInt64) - Количество байт в сжатом виде. +- modification_time (DateTime) - Время модификации директории с куском. Обычно соответствует времени создания куска.| +- remove_time (DateTime) - Время, когда кусок стал неактивным. +- refcount (UInt32) - Количество мест, в котором кусок используется. Значение больше 2 говорит о том, что кусок участвует в запросах или в слияниях. +- min_date (Date) - Минимальное значение ключа даты в куске. +- max_date (Date) - Максимальное значение ключа даты в куске. +- min_block_number (UInt64) - Минимальный номер куска из которых состоит текущий после слияния. +- max_block_number (UInt64) - Максимальный номер куска из которых состоит текущий после слияния. +- level (UInt32) - Глубина дерева слияний. Если слияний не было, то ``level=0``. +- primary_key_bytes_in_memory (UInt64) - Объем памяти (в байтах), занимаемой значениями первичных ключей. +- primary_key_bytes_in_memory_allocated (UInt64) - Выделенный с резервом объем памяти (в байтах) для размещения первичных ключей. +- database (String) - Имя базы данных. +- table (String) - Имя таблицы. +- engine (String) - Имя движка таблицы, без параметров. +# system.processes + +Эта системная таблица используется для реализации запроса `SHOW PROCESSLIST`. +Столбцы: + +```text +user String - имя пользователя, который задал запрос. При распределённой обработке запроса, относится к пользователю, с помощью которого сервер-инициатор запроса отправил запрос на данный сервер, а не к имени пользователя, который задал распределённый запрос на сервер-инициатор запроса. + +address String - IP-адрес, с которого задан запрос. При распределённой обработке запроса, аналогично. + +elapsed Float64 - время в секундах, прошедшее от начала выполнения запроса. + +rows_read UInt64 - количество прочитанных из таблиц строк. При распределённой обработке запроса, на сервере-инициаторе запроса, представляет собой сумму по всем удалённым серверам. + +bytes_read UInt64 - количество прочитанных из таблиц байт, в несжатом виде. При распределённой обработке запроса, на сервере-инициаторе запроса, представляет собой сумму по всем удалённым серверам. + +total_rows_approx UInt64 - приблизительная оценка общего количества строк, которые должны быть прочитаны. При распределённой обработке запроса, на сервере-инициаторе запроса, представляет собой сумму по всем удалённым серверам. Может обновляться в процессе выполнения запроса, когда становятся известны новые источники для обработки. + +memory_usage UInt64 - потребление памяти запросом. Может не учитывать некоторые виды выделенной памяти. + +query String - текст запроса. В случае INSERT - без данных для INSERT-а. + +query_id String - идентификатор запроса, если был задан. +``` +# system.replicas + +Содержит информацию и статус для реплицируемых таблиц, расположенных на локальном сервере. +Эту таблицу можно использовать для мониторинга. Таблица содержит по строчке для каждой Replicated\*-таблицы. + +Пример: + +```sql +SELECT * +FROM system.replicas +WHERE table = 'visits' +FORMAT Vertical +``` + +```text +Row 1: +────── +database: merge +table: visits +engine: ReplicatedCollapsingMergeTree +is_leader: 1 +is_readonly: 0 +is_session_expired: 0 +future_parts: 1 +parts_to_check: 0 +zookeeper_path: /clickhouse/tables/01-06/visits +replica_name: example01-06-1.yandex.ru +replica_path: /clickhouse/tables/01-06/visits/replicas/example01-06-1.yandex.ru +columns_version: 9 +queue_size: 1 +inserts_in_queue: 0 +merges_in_queue: 1 +log_max_index: 596273 +log_pointer: 596274 +total_replicas: 2 +active_replicas: 2 +``` + +Столбцы: + +```text +database: имя БД +table: имя таблицы +engine: имя движка таблицы + +is_leader: является ли реплика лидером + +В один момент времени, не более одной из реплик является лидером. Лидер отвечает за выбор фоновых слияний, которые следует произвести. +Замечу, что запись можно осуществлять на любую реплику (доступную и имеющую сессию в ZK), независимо от лидерства. + +is_readonly: находится ли реплика в режиме "только для чтения" +Этот режим включается, если в конфиге нет секции с ZK; если при переинициализации сессии в ZK произошла неизвестная ошибка; во время переинициализации сессии с ZK. + +is_session_expired: истекла ли сессия с ZK. +В основном, то же самое, что и is_readonly. + +future_parts: количество кусков с данными, которые появятся в результате INSERT-ов или слияний, которых ещё предстоит сделать + +parts_to_check: количество кусков с данными в очереди на проверку +Кусок помещается в очередь на проверку, если есть подозрение, что он может быть битым. + +zookeeper_path: путь к данным таблицы в ZK +replica_name: имя реплики в ZK; разные реплики одной таблицы имеют разное имя +replica_path: путь к данным реплики в ZK. То же самое, что конкатенация zookeeper_path/replicas/replica_path. + +columns_version: номер версии структуры таблицы +Обозначает, сколько раз был сделан ALTER. Если на репликах разные версии, значит некоторые реплики сделали ещё не все ALTER-ы. + +queue_size: размер очереди действий, которых предстоит сделать +К действиям относятся вставки блоков данных, слияния, и некоторые другие действия. +Как правило, совпадает с future_parts. + +inserts_in_queue: количество вставок блоков данных, которых предстоит сделать +Обычно вставки должны быстро реплицироваться. Если величина большая - значит что-то не так. + +merges_in_queue: количество слияний, которых предстоит сделать +Бывают длинные слияния - то есть, это значение может быть больше нуля продолжительное время. + +Следующие 4 столбца имеют ненулевое значение только если активна сессия с ZK. + +log_max_index: максимальный номер записи в общем логе действий +log_pointer: максимальный номер записи из общего лога действий, которую реплика скопировала в свою очередь для выполнения, плюс единица +Если log_pointer сильно меньше log_max_index, значит что-то не так. + +total_replicas: общее число известных реплик этой таблицы +active_replicas: число реплик этой таблицы, имеющих сессию в ZK; то есть, число работающих реплик +``` + +Если запрашивать все столбцы, то таблица может работать слегка медленно, так как на каждую строчку делается несколько чтений из ZK. +Если не запрашивать последние 4 столбца (log_max_index, log_pointer, total_replicas, active_replicas), то таблица работает быстро. + +Например, так можно проверить, что всё хорошо: + +```sql +SELECT + database, + table, + is_leader, + is_readonly, + is_session_expired, + future_parts, + parts_to_check, + columns_version, + queue_size, + inserts_in_queue, + merges_in_queue, + log_max_index, + log_pointer, + total_replicas, + active_replicas +FROM system.replicas +WHERE + is_readonly + OR is_session_expired + OR future_parts > 20 + OR parts_to_check > 10 + OR queue_size > 20 + OR inserts_in_queue > 10 + OR log_max_index - log_pointer > 10 + OR total_replicas < 2 + OR active_replicas < total_replicas +``` + +Если этот запрос ничего не возвращает - значит всё хорошо. +# system.settings + +Содержит информацию о настройках, используемых в данный момент. +То есть, используемых для выполнения запроса, с помощью которого вы читаете из таблицы system.settings. + +Столбцы: + +```text +name String - имя настройки +value String - значение настройки +changed UInt8 - была ли настройка явно задана в конфиге или изменена явным образом +``` + +Пример: + +```sql +SELECT * +FROM system.settings +WHERE changed +``` + +```text +┌─name───────────────────┬─value───────┬─changed─┐ +│ max_threads │ 8 │ 1 │ +│ use_uncompressed_cache │ 0 │ 1 │ +│ load_balancing │ random │ 1 │ +│ max_memory_usage │ 10000000000 │ 1 │ +└────────────────────────┴─────────────┴─────────┘ +``` +# system.tables + +Таблица содержит столбцы database, name, engine типа String. +Также таблица содержит три виртуальных столбца: metadata_modification_time типа DateTime, create_table_query и engine_full типа String. +Для каждой таблицы, о которой знает сервер, будет присутствовать соответствующая запись в таблице system.tables. +Эта системная таблица используется для реализации запросов SHOW TABLES. +# system.zookeeper + +Позволяет читать данные из ZooKeeper кластера, описанного в конфигурации. +В запросе обязательно в секции WHERE должно присутствовать условие на равенство path - путь в ZooKeeper, для детей которого вы хотите получить данные. + +Запрос `SELECT * FROM system.zookeeper WHERE path = '/clickhouse'` выведет данные по всем детям узла `/clickhouse`. +Чтобы вывести данные по всем узлам в корне, напишите path = '/'. +Если узла, указанного в path не существует, то будет брошено исключение. + +Столбцы: + +- `name String` — Имя узла. +- `path String` — Путь к узлу. +- `value String` — Значение узла. +- `dataLength Int32` — Размер значения. +- `numChildren Int32` — Количество детей. +- `czxid Int64` — Идентификатор транзакции, в которой узел был создан. +- `mzxid Int64` — Идентификатор транзакции, в которой узел был последний раз изменён. +- `pzxid Int64` — Идентификатор транзакции, последний раз удаливший или добавивший детей. +- `ctime DateTime` — Время создания узла. +- `mtime DateTime` — Время последней модификации узла. +- `version Int32` — Версия узла - количество раз, когда узел был изменён. +- `cversion Int32` — Количество добавлений или удалений детей. +- `aversion Int32` — Количество изменений ACL. +- `ephemeralOwner Int64` — Для эфемерных узлов - идентификатор сессии, которая владеет этим узлом. + + +Пример: + +```sql +SELECT * +FROM system.zookeeper +WHERE path = '/clickhouse/tables/01-08/visits/replicas' +FORMAT Vertical +``` + +```text +Row 1: +────── +name: example01-08-1.yandex.ru +value: +czxid: 932998691229 +mzxid: 932998691229 +ctime: 2015-03-27 16:49:51 +mtime: 2015-03-27 16:49:51 +version: 0 +cversion: 47 +aversion: 0 +ephemeralOwner: 0 +dataLength: 0 +numChildren: 7 +pzxid: 987021031383 +path: /clickhouse/tables/01-08/visits/replicas + +Row 2: +────── +name: example01-08-2.yandex.ru +value: +czxid: 933002738135 +mzxid: 933002738135 +ctime: 2015-03-27 16:57:01 +mtime: 2015-03-27 16:57:01 +version: 0 +cversion: 37 +aversion: 0 +ephemeralOwner: 0 +dataLength: 0 +numChildren: 7 +pzxid: 987021252247 +path: /clickhouse/tables/01-08/visits/replicas +``` diff --git a/docs/ru/system_tables/index.md b/docs/ru/system_tables/index.md deleted file mode 100644 index e45ba75b7a4..00000000000 --- a/docs/ru/system_tables/index.md +++ /dev/null @@ -1,7 +0,0 @@ -# Системные таблицы - -Системные таблицы используются для реализации части функциональности системы, а также предоставляют доступ к информации о работе системы. -Вы не можете удалить системную таблицу (хотя можете сделать DETACH). -Для системных таблиц нет файлов с данными на диске и файлов с метаданными. Сервер создаёт все системные таблицы при старте. -В системные таблицы нельзя записывать данные - можно только читать. -Системные таблицы расположены в базе данных system. diff --git a/docs/ru/system_tables/system.asynchronous_metrics.md b/docs/ru/system_tables/system.asynchronous_metrics.md deleted file mode 100644 index b1e649ac16a..00000000000 --- a/docs/ru/system_tables/system.asynchronous_metrics.md +++ /dev/null @@ -1,8 +0,0 @@ - - -# system.asynchronous_metrics - -Содержат метрики, используемые для профилирования и мониторинга. -Обычно отражают количество событий, происходящих в данный момент в системе, или ресурсов, суммарно потребляемых системой. -Пример: количество запросов типа SELECT, исполняемых в текущий момент; количество потребляемой памяти. -`system.asynchronous_metrics` и `system.metrics` отличаются набором и способом вычисления метрик. diff --git a/docs/ru/system_tables/system.clusters.md b/docs/ru/system_tables/system.clusters.md deleted file mode 100644 index 52116a127cb..00000000000 --- a/docs/ru/system_tables/system.clusters.md +++ /dev/null @@ -1,15 +0,0 @@ -# system.clusters - -Содержит информацию о доступных в конфигурационном файле кластерах и серверах, которые в них входят. -Столбцы: - -```text -cluster String - имя кластера -shard_num UInt32 - номер шарда в кластере, начиная с 1 -shard_weight UInt32 - относительный вес шарда при записи данных -replica_num UInt32 - номер реплики в шарде, начиная с 1 -host_name String - имя хоста, как прописано в конфиге -host_address String - IP-адрес хоста, полученный из DNS -port UInt16 - порт, на который обращаться для соединения с сервером -user String - имя пользователя, которого использовать для соединения с сервером -``` diff --git a/docs/ru/system_tables/system.columns.md b/docs/ru/system_tables/system.columns.md deleted file mode 100644 index c458f24d95f..00000000000 --- a/docs/ru/system_tables/system.columns.md +++ /dev/null @@ -1,13 +0,0 @@ -# system.columns - -Содержит информацию о столбцах всех таблиц. -С помощью этой таблицы можно получить информацию аналогично запросу `DESCRIBE TABLE`, но для многих таблиц сразу. - -```text -database String - имя базы данных, в которой находится таблица -table String - имя таблицы -name String - имя столбца -type String - тип столбца -default_type String - тип (DEFAULT, MATERIALIZED, ALIAS) выражения для значения по умолчанию, или пустая строка, если оно не описано -default_expression String - выражение для значения по умолчанию, или пустая строка, если оно не описано -``` diff --git a/docs/ru/system_tables/system.databases.md b/docs/ru/system_tables/system.databases.md deleted file mode 100644 index 10087837b5c..00000000000 --- a/docs/ru/system_tables/system.databases.md +++ /dev/null @@ -1,5 +0,0 @@ -# system.databases - -Таблица содержит один столбец name типа String - имя базы данных. -Для каждой базы данных, о которой знает сервер, будет присутствовать соответствующая запись в таблице. -Эта системная таблица используется для реализации запроса `SHOW DATABASES`. diff --git a/docs/ru/system_tables/system.dictionaries.md b/docs/ru/system_tables/system.dictionaries.md deleted file mode 100644 index df588920bc1..00000000000 --- a/docs/ru/system_tables/system.dictionaries.md +++ /dev/null @@ -1,22 +0,0 @@ -# system.dictionaries - -Содержит информацию о внешних словарях. - -Столбцы: - -- `name String` — Имя словаря. -- `type String` — Тип словаря: Flat, Hashed, Cache. -- `origin String` — Путь к конфигурационному файлу, в котором описан словарь. -- `attribute.names Array(String)` — Массив имён атрибутов, предоставляемых словарём. -- `attribute.types Array(String)` — Соответствующий массив типов атрибутов, предоставляемых словарём. -- `has_hierarchy UInt8` — Является ли словарь иерархическим. -- `bytes_allocated UInt64` — Количество оперативной памяти, которое использует словарь. -- `hit_rate Float64` — Для cache-словарей - доля использований, для которых значение было в кэше. -- `element_count UInt64` — Количество хранящихся в словаре элементов. -- `load_factor Float64` — Доля заполненности словаря (для hashed словаря - доля заполнения хэш-таблицы). -- `creation_time DateTime` — Время создания или последней успешной перезагрузки словаря. -- `last_exception String` — Текст ошибки, возникшей при создании или перезагрузке словаря, если словарь не удалось создать. -- `source String` - Текст, описывающий источник данных для словаря. - - -Заметим, что количество оперативной памяти, которое использует словарь, не является пропорциональным количеству элементов, хранящихся в словаре. Так, для flat и cached словарей, все ячейки памяти выделяются заранее, независимо от реальной заполненности словаря. diff --git a/docs/ru/system_tables/system.events.md b/docs/ru/system_tables/system.events.md deleted file mode 100644 index 89ced73459c..00000000000 --- a/docs/ru/system_tables/system.events.md +++ /dev/null @@ -1,7 +0,0 @@ - - -# system.events - -Содержит информацию о количестве произошедших в системе событий, для профилирования и мониторинга. -Пример: количество обработанных запросов типа SELECT. -Столбцы: event String - имя события, value UInt64 - количество. diff --git a/docs/ru/system_tables/system.functions.md b/docs/ru/system_tables/system.functions.md deleted file mode 100644 index f4ec19d1dbf..00000000000 --- a/docs/ru/system_tables/system.functions.md +++ /dev/null @@ -1,8 +0,0 @@ -# system.functions - -Содержит информацию об обычных и агрегатных функциях. - -Столбцы: - -- `name` (`String`) – Имя функции. -- `is_aggregate` (`UInt8`) – Признак, является ли функция агрегатной. diff --git a/docs/ru/system_tables/system.merges.md b/docs/ru/system_tables/system.merges.md deleted file mode 100644 index c0b52a4675c..00000000000 --- a/docs/ru/system_tables/system.merges.md +++ /dev/null @@ -1,18 +0,0 @@ -# system.merges - -Содержит информацию о производящихся прямо сейчас слияниях для таблиц семейства MergeTree. - -Столбцы: - -- `database String` — Имя базы данных, в которой находится таблица. -- `table String` — Имя таблицы. -- `elapsed Float64` — Время в секундах, прошедшее от начала выполнения слияния. -- `progress Float64` — Доля выполненной работы от 0 до 1. -- `num_parts UInt64` — Количество сливаемых кусков. -- `result_part_name String` — Имя куска, который будет образован в результате слияния. -- `total_size_bytes_compressed UInt64` — Суммарный размер сжатых данных сливаемых кусков. -- `total_size_marks UInt64` — Суммарное количество засечек в сливаемых кусках. -- `bytes_read_uncompressed UInt64` — Количество прочитанных байт, разжатых. -- `rows_read UInt64` — Количество прочитанных строк. -- `bytes_written_uncompressed UInt64` — Количество записанных байт, несжатых. -- `rows_written UInt64` — Количество записанных строк. diff --git a/docs/ru/system_tables/system.metrics.md b/docs/ru/system_tables/system.metrics.md deleted file mode 100644 index 3fdc8b0daee..00000000000 --- a/docs/ru/system_tables/system.metrics.md +++ /dev/null @@ -1,3 +0,0 @@ - - -# system.metrics diff --git a/docs/ru/system_tables/system.numbers.md b/docs/ru/system_tables/system.numbers.md deleted file mode 100644 index 6a7ebc78cf5..00000000000 --- a/docs/ru/system_tables/system.numbers.md +++ /dev/null @@ -1,5 +0,0 @@ -# system.numbers - -Таблица содержит один столбец с именем number типа UInt64, содержащим почти все натуральные числа, начиная с нуля. -Эту таблицу можно использовать для тестов, а также если вам нужно сделать перебор. -Чтения из этой таблицы не распараллеливаются. diff --git a/docs/ru/system_tables/system.numbers_mt.md b/docs/ru/system_tables/system.numbers_mt.md deleted file mode 100644 index 113abbf4a26..00000000000 --- a/docs/ru/system_tables/system.numbers_mt.md +++ /dev/null @@ -1,4 +0,0 @@ -# system.numbers_mt - -То же самое, что и system.numbers, но чтение распараллеливается. Числа могут возвращаться в произвольном порядке. -Используется для тестов. diff --git a/docs/ru/system_tables/system.one.md b/docs/ru/system_tables/system.one.md deleted file mode 100644 index b3666757e3a..00000000000 --- a/docs/ru/system_tables/system.one.md +++ /dev/null @@ -1,5 +0,0 @@ -# system.one - -Таблица содержит одну строку с одним столбцом dummy типа UInt8, содержащим значение 0. -Эта таблица используется, если в SELECT запросе не указана секция FROM. -То есть, это - аналог таблицы DUAL, которую можно найти в других СУБД. diff --git a/docs/ru/system_tables/system.parts.md b/docs/ru/system_tables/system.parts.md deleted file mode 100644 index 8a5a0f34576..00000000000 --- a/docs/ru/system_tables/system.parts.md +++ /dev/null @@ -1,28 +0,0 @@ -# system.parts - -Содержит информацию о кусках таблиц семейства [MergeTree](../table_engines/mergetree.md#table_engines-mergetree). - -Каждая строка описывает один кусок данных. - -Столбцы: - -- partition (String) - Имя партиции. Формат YYYYMM. Что такое партиция можно узнать из описания запроса [ALTER](../query_language/queries.md#query_language_queries_alter). -- name (String) - Имя куска. -- active (UInt8) - Признак активности. Если кусок активен, то он используется таблице, в противном случает он будет удален. Неактивные куски остаются после слияний. -- marks (UInt64) - Количество засечек. Чтобы получить примерное количество строк в куске, умножьте ``marks`` на гранулированность индекса (обычно 8192). -- marks_size (UInt64) - Размер файла с засечками. -- rows (UInt64) - Количество строк. -- bytes (UInt64) - Количество байт в сжатом виде. -- modification_time (DateTime) - Время модификации директории с куском. Обычно соответствует времени создания куска.| -- remove_time (DateTime) - Время, когда кусок стал неактивным. -- refcount (UInt32) - Количество мест, в котором кусок используется. Значение больше 2 говорит о том, что кусок участвует в запросах или в слияниях. -- min_date (Date) - Минимальное значение ключа даты в куске. -- max_date (Date) - Максимальное значение ключа даты в куске. -- min_block_number (UInt64) - Минимальный номер куска из которых состоит текущий после слияния. -- max_block_number (UInt64) - Максимальный номер куска из которых состоит текущий после слияния. -- level (UInt32) - Глубина дерева слияний. Если слияний не было, то ``level=0``. -- primary_key_bytes_in_memory (UInt64) - Объем памяти (в байтах), занимаемой значениями первичных ключей. -- primary_key_bytes_in_memory_allocated (UInt64) - Выделенный с резервом объем памяти (в байтах) для размещения первичных ключей. -- database (String) - Имя базы данных. -- table (String) - Имя таблицы. -- engine (String) - Имя движка таблицы, без параметров. diff --git a/docs/ru/system_tables/system.processes.md b/docs/ru/system_tables/system.processes.md deleted file mode 100644 index 82264c0b794..00000000000 --- a/docs/ru/system_tables/system.processes.md +++ /dev/null @@ -1,24 +0,0 @@ -# system.processes - -Эта системная таблица используется для реализации запроса `SHOW PROCESSLIST`. -Столбцы: - -```text -user String - имя пользователя, который задал запрос. При распределённой обработке запроса, относится к пользователю, с помощью которого сервер-инициатор запроса отправил запрос на данный сервер, а не к имени пользователя, который задал распределённый запрос на сервер-инициатор запроса. - -address String - IP-адрес, с которого задан запрос. При распределённой обработке запроса, аналогично. - -elapsed Float64 - время в секундах, прошедшее от начала выполнения запроса. - -rows_read UInt64 - количество прочитанных из таблиц строк. При распределённой обработке запроса, на сервере-инициаторе запроса, представляет собой сумму по всем удалённым серверам. - -bytes_read UInt64 - количество прочитанных из таблиц байт, в несжатом виде. При распределённой обработке запроса, на сервере-инициаторе запроса, представляет собой сумму по всем удалённым серверам. - -total_rows_approx UInt64 - приблизительная оценка общего количества строк, которые должны быть прочитаны. При распределённой обработке запроса, на сервере-инициаторе запроса, представляет собой сумму по всем удалённым серверам. Может обновляться в процессе выполнения запроса, когда становятся известны новые источники для обработки. - -memory_usage UInt64 - потребление памяти запросом. Может не учитывать некоторые виды выделенной памяти. - -query String - текст запроса. В случае INSERT - без данных для INSERT-а. - -query_id String - идентификатор запроса, если был задан. -``` diff --git a/docs/ru/system_tables/system.replicas.md b/docs/ru/system_tables/system.replicas.md deleted file mode 100644 index 5647dd24edb..00000000000 --- a/docs/ru/system_tables/system.replicas.md +++ /dev/null @@ -1,124 +0,0 @@ -# system.replicas - -Содержит информацию и статус для реплицируемых таблиц, расположенных на локальном сервере. -Эту таблицу можно использовать для мониторинга. Таблица содержит по строчке для каждой Replicated\*-таблицы. - -Пример: - -```sql -SELECT * -FROM system.replicas -WHERE table = 'visits' -FORMAT Vertical -``` - -```text -Row 1: -────── -database: merge -table: visits -engine: ReplicatedCollapsingMergeTree -is_leader: 1 -is_readonly: 0 -is_session_expired: 0 -future_parts: 1 -parts_to_check: 0 -zookeeper_path: /clickhouse/tables/01-06/visits -replica_name: example01-06-1.yandex.ru -replica_path: /clickhouse/tables/01-06/visits/replicas/example01-06-1.yandex.ru -columns_version: 9 -queue_size: 1 -inserts_in_queue: 0 -merges_in_queue: 1 -log_max_index: 596273 -log_pointer: 596274 -total_replicas: 2 -active_replicas: 2 -``` - -Столбцы: - -```text -database: имя БД -table: имя таблицы -engine: имя движка таблицы - -is_leader: является ли реплика лидером - -В один момент времени, не более одной из реплик является лидером. Лидер отвечает за выбор фоновых слияний, которые следует произвести. -Замечу, что запись можно осуществлять на любую реплику (доступную и имеющую сессию в ZK), независимо от лидерства. - -is_readonly: находится ли реплика в режиме "только для чтения" -Этот режим включается, если в конфиге нет секции с ZK; если при переинициализации сессии в ZK произошла неизвестная ошибка; во время переинициализации сессии с ZK. - -is_session_expired: истекла ли сессия с ZK. -В основном, то же самое, что и is_readonly. - -future_parts: количество кусков с данными, которые появятся в результате INSERT-ов или слияний, которых ещё предстоит сделать - -parts_to_check: количество кусков с данными в очереди на проверку -Кусок помещается в очередь на проверку, если есть подозрение, что он может быть битым. - -zookeeper_path: путь к данным таблицы в ZK -replica_name: имя реплики в ZK; разные реплики одной таблицы имеют разное имя -replica_path: путь к данным реплики в ZK. То же самое, что конкатенация zookeeper_path/replicas/replica_path. - -columns_version: номер версии структуры таблицы -Обозначает, сколько раз был сделан ALTER. Если на репликах разные версии, значит некоторые реплики сделали ещё не все ALTER-ы. - -queue_size: размер очереди действий, которых предстоит сделать -К действиям относятся вставки блоков данных, слияния, и некоторые другие действия. -Как правило, совпадает с future_parts. - -inserts_in_queue: количество вставок блоков данных, которых предстоит сделать -Обычно вставки должны быстро реплицироваться. Если величина большая - значит что-то не так. - -merges_in_queue: количество слияний, которых предстоит сделать -Бывают длинные слияния - то есть, это значение может быть больше нуля продолжительное время. - -Следующие 4 столбца имеют ненулевое значение только если активна сессия с ZK. - -log_max_index: максимальный номер записи в общем логе действий -log_pointer: максимальный номер записи из общего лога действий, которую реплика скопировала в свою очередь для выполнения, плюс единица -Если log_pointer сильно меньше log_max_index, значит что-то не так. - -total_replicas: общее число известных реплик этой таблицы -active_replicas: число реплик этой таблицы, имеющих сессию в ZK; то есть, число работающих реплик -``` - -Если запрашивать все столбцы, то таблица может работать слегка медленно, так как на каждую строчку делается несколько чтений из ZK. -Если не запрашивать последние 4 столбца (log_max_index, log_pointer, total_replicas, active_replicas), то таблица работает быстро. - -Например, так можно проверить, что всё хорошо: - -```sql -SELECT - database, - table, - is_leader, - is_readonly, - is_session_expired, - future_parts, - parts_to_check, - columns_version, - queue_size, - inserts_in_queue, - merges_in_queue, - log_max_index, - log_pointer, - total_replicas, - active_replicas -FROM system.replicas -WHERE - is_readonly - OR is_session_expired - OR future_parts > 20 - OR parts_to_check > 10 - OR queue_size > 20 - OR inserts_in_queue > 10 - OR log_max_index - log_pointer > 10 - OR total_replicas < 2 - OR active_replicas < total_replicas -``` - -Если этот запрос ничего не возвращает - значит всё хорошо. diff --git a/docs/ru/system_tables/system.settings.md b/docs/ru/system_tables/system.settings.md deleted file mode 100644 index 6fd12cd39fd..00000000000 --- a/docs/ru/system_tables/system.settings.md +++ /dev/null @@ -1,29 +0,0 @@ -# system.settings - -Содержит информацию о настройках, используемых в данный момент. -То есть, используемых для выполнения запроса, с помощью которого вы читаете из таблицы system.settings. - -Столбцы: - -```text -name String - имя настройки -value String - значение настройки -changed UInt8 - была ли настройка явно задана в конфиге или изменена явным образом -``` - -Пример: - -```sql -SELECT * -FROM system.settings -WHERE changed -``` - -```text -┌─name───────────────────┬─value───────┬─changed─┐ -│ max_threads │ 8 │ 1 │ -│ use_uncompressed_cache │ 0 │ 1 │ -│ load_balancing │ random │ 1 │ -│ max_memory_usage │ 10000000000 │ 1 │ -└────────────────────────┴─────────────┴─────────┘ -``` diff --git a/docs/ru/system_tables/system.tables.md b/docs/ru/system_tables/system.tables.md deleted file mode 100644 index ff8f4405032..00000000000 --- a/docs/ru/system_tables/system.tables.md +++ /dev/null @@ -1,6 +0,0 @@ -# system.tables - -Таблица содержит столбцы database, name, engine типа String. -Также таблица содержит три виртуальных столбца: metadata_modification_time типа DateTime, create_table_query и engine_full типа String. -Для каждой таблицы, о которой знает сервер, будет присутствовать соответствующая запись в таблице system.tables. -Эта системная таблица используется для реализации запросов SHOW TABLES. diff --git a/docs/ru/system_tables/system.zookeeper.md b/docs/ru/system_tables/system.zookeeper.md deleted file mode 100644 index be4222d1a76..00000000000 --- a/docs/ru/system_tables/system.zookeeper.md +++ /dev/null @@ -1,71 +0,0 @@ -# system.zookeeper - -Позволяет читать данные из ZooKeeper кластера, описанного в конфигурации. -В запросе обязательно в секции WHERE должно присутствовать условие на равенство path - путь в ZooKeeper, для детей которого вы хотите получить данные. - -Запрос `SELECT * FROM system.zookeeper WHERE path = '/clickhouse'` выведет данные по всем детям узла `/clickhouse`. -Чтобы вывести данные по всем узлам в корне, напишите path = '/'. -Если узла, указанного в path не существует, то будет брошено исключение. - -Столбцы: - -- `name String` — Имя узла. -- `path String` — Путь к узлу. -- `value String` — Значение узла. -- `dataLength Int32` — Размер значения. -- `numChildren Int32` — Количество детей. -- `czxid Int64` — Идентификатор транзакции, в которой узел был создан. -- `mzxid Int64` — Идентификатор транзакции, в которой узел был последний раз изменён. -- `pzxid Int64` — Идентификатор транзакции, последний раз удаливший или добавивший детей. -- `ctime DateTime` — Время создания узла. -- `mtime DateTime` — Время последней модификации узла. -- `version Int32` — Версия узла - количество раз, когда узел был изменён. -- `cversion Int32` — Количество добавлений или удалений детей. -- `aversion Int32` — Количество изменений ACL. -- `ephemeralOwner Int64` — Для эфемерных узлов - идентификатор сессии, которая владеет этим узлом. - - -Пример: - -```sql -SELECT * -FROM system.zookeeper -WHERE path = '/clickhouse/tables/01-08/visits/replicas' -FORMAT Vertical -``` - -```text -Row 1: -────── -name: example01-08-1.yandex.ru -value: -czxid: 932998691229 -mzxid: 932998691229 -ctime: 2015-03-27 16:49:51 -mtime: 2015-03-27 16:49:51 -version: 0 -cversion: 47 -aversion: 0 -ephemeralOwner: 0 -dataLength: 0 -numChildren: 7 -pzxid: 987021031383 -path: /clickhouse/tables/01-08/visits/replicas - -Row 2: -────── -name: example01-08-2.yandex.ru -value: -czxid: 933002738135 -mzxid: 933002738135 -ctime: 2015-03-27 16:57:01 -mtime: 2015-03-27 16:57:01 -version: 0 -cversion: 37 -aversion: 0 -ephemeralOwner: 0 -dataLength: 0 -numChildren: 7 -pzxid: 987021252247 -path: /clickhouse/tables/01-08/visits/replicas -``` From 4944d1eaa4de099d2d64ec2f2f6958a01d0b15e6 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Mon, 16 Jul 2018 19:15:46 +0300 Subject: [PATCH 010/425] Merge a bunch of small articles about formats into single one --- docs/en/dicts/external_dicts_dict_sources.md | 6 +- docs/en/formats/capnproto.md | 26 - docs/en/formats/csv.md | 12 - docs/en/formats/csvwithnames.md | 4 - docs/en/formats/index.md | 6 - docs/en/formats/json.md | 85 --- docs/en/formats/jsoncompact.md | 46 -- docs/en/formats/jsoneachrow.md | 21 - docs/en/formats/native.md | 6 - docs/en/formats/null.md | 5 - docs/en/formats/pretty.md | 37 -- docs/en/formats/prettycompact.md | 5 - docs/en/formats/prettycompactmonoblock.md | 4 - docs/en/formats/prettynoescapes.md | 20 - docs/en/formats/prettyspace.md | 4 - docs/en/formats/rowbinary.md | 13 - docs/en/formats/tabseparated.md | 59 -- docs/en/formats/tabseparatedraw.md | 7 - docs/en/formats/tabseparatedwithnames.md | 8 - .../formats/tabseparatedwithnamesandtypes.md | 7 - docs/en/formats/tskv.md | 23 - docs/en/formats/values.md | 8 - docs/en/formats/vertical.md | 5 - docs/en/formats/verticalraw.md | 28 - docs/en/formats/xml.md | 74 --- docs/en/interfaces/formats.md | 513 ++++++++++++++++ .../en/operations/server_settings/settings.md | 2 +- docs/en/query_language/queries.md | 2 +- docs/en/table_functions/file.md | 2 +- docs/mkdocs_en.yml | 27 +- docs/mkdocs_ru.yml | 27 +- docs/redirects.txt | 24 + docs/ru/dicts/external_dicts_dict_sources.md | 6 +- docs/ru/formats/capnproto.md | 26 - docs/ru/formats/csv.md | 13 - docs/ru/formats/csvwithnames.md | 5 - docs/ru/formats/index.md | 33 - docs/ru/formats/json.md | 87 --- docs/ru/formats/jsoncompact.md | 47 -- docs/ru/formats/jsoneachrow.md | 22 - docs/ru/formats/native.md | 7 - docs/ru/formats/null.md | 6 - docs/ru/formats/pretty.md | 38 -- docs/ru/formats/prettycompact.md | 6 - docs/ru/formats/prettycompactmonoblock.md | 5 - docs/ru/formats/prettynoescapes.md | 21 - docs/ru/formats/prettyspace.md | 5 - docs/ru/formats/rowbinary.md | 14 - docs/ru/formats/tabseparated.md | 60 -- docs/ru/formats/tabseparatedraw.md | 8 - docs/ru/formats/tabseparatedwithnames.md | 9 - .../formats/tabseparatedwithnamesandtypes.md | 8 - docs/ru/formats/tskv.md | 24 - docs/ru/formats/values.md | 9 - docs/ru/formats/vertical.md | 6 - docs/ru/formats/verticalraw.md | 28 - docs/ru/formats/xml.md | 75 --- docs/ru/interfaces/formats.md | 563 ++++++++++++++++++ .../ru/operations/server_settings/settings.md | 2 +- docs/ru/query_language/queries.md | 2 +- docs/ru/table_engines/file.md | 2 +- docs/ru/table_functions/file.md | 2 +- 62 files changed, 1115 insertions(+), 1140 deletions(-) delete mode 100644 docs/en/formats/capnproto.md delete mode 100644 docs/en/formats/csv.md delete mode 100644 docs/en/formats/csvwithnames.md delete mode 100644 docs/en/formats/index.md delete mode 100644 docs/en/formats/json.md delete mode 100644 docs/en/formats/jsoncompact.md delete mode 100644 docs/en/formats/jsoneachrow.md delete mode 100644 docs/en/formats/native.md delete mode 100644 docs/en/formats/null.md delete mode 100644 docs/en/formats/pretty.md delete mode 100644 docs/en/formats/prettycompact.md delete mode 100644 docs/en/formats/prettycompactmonoblock.md delete mode 100644 docs/en/formats/prettynoescapes.md delete mode 100644 docs/en/formats/prettyspace.md delete mode 100644 docs/en/formats/rowbinary.md delete mode 100644 docs/en/formats/tabseparated.md delete mode 100644 docs/en/formats/tabseparatedraw.md delete mode 100644 docs/en/formats/tabseparatedwithnames.md delete mode 100644 docs/en/formats/tabseparatedwithnamesandtypes.md delete mode 100644 docs/en/formats/tskv.md delete mode 100644 docs/en/formats/values.md delete mode 100644 docs/en/formats/vertical.md delete mode 100644 docs/en/formats/verticalraw.md delete mode 100644 docs/en/formats/xml.md create mode 100644 docs/en/interfaces/formats.md delete mode 100644 docs/ru/formats/capnproto.md delete mode 100644 docs/ru/formats/csv.md delete mode 100644 docs/ru/formats/csvwithnames.md delete mode 100644 docs/ru/formats/index.md delete mode 100644 docs/ru/formats/json.md delete mode 100644 docs/ru/formats/jsoncompact.md delete mode 100644 docs/ru/formats/jsoneachrow.md delete mode 100644 docs/ru/formats/native.md delete mode 100644 docs/ru/formats/null.md delete mode 100644 docs/ru/formats/pretty.md delete mode 100644 docs/ru/formats/prettycompact.md delete mode 100644 docs/ru/formats/prettycompactmonoblock.md delete mode 100644 docs/ru/formats/prettynoescapes.md delete mode 100644 docs/ru/formats/prettyspace.md delete mode 100644 docs/ru/formats/rowbinary.md delete mode 100644 docs/ru/formats/tabseparated.md delete mode 100644 docs/ru/formats/tabseparatedraw.md delete mode 100644 docs/ru/formats/tabseparatedwithnames.md delete mode 100644 docs/ru/formats/tabseparatedwithnamesandtypes.md delete mode 100644 docs/ru/formats/tskv.md delete mode 100644 docs/ru/formats/values.md delete mode 100644 docs/ru/formats/vertical.md delete mode 100644 docs/ru/formats/verticalraw.md delete mode 100644 docs/ru/formats/xml.md create mode 100644 docs/ru/interfaces/formats.md diff --git a/docs/en/dicts/external_dicts_dict_sources.md b/docs/en/dicts/external_dicts_dict_sources.md index 8d0e4952a3b..7779187d583 100644 --- a/docs/en/dicts/external_dicts_dict_sources.md +++ b/docs/en/dicts/external_dicts_dict_sources.md @@ -52,7 +52,7 @@ Example of settings: Setting fields: - `path` – The absolute path to the file. -- `format` – The file format. All the formats described in "[Formats](../formats/index.md#formats)" are supported. +- `format` – The file format. All the formats described in "[Formats](../interfaces/formats.md#formats)" are supported. @@ -74,7 +74,7 @@ Example of settings: Setting fields: - `command` – The absolute path to the executable file, or the file name (if the program directory is written to `PATH`). -- `format` – The file format. All the formats described in "[Formats](../formats/index.md#formats)" are supported. +- `format` – The file format. All the formats described in "[Formats](../interfaces/formats.md#formats)" are supported. @@ -98,7 +98,7 @@ In order for ClickHouse to access an HTTPS resource, you must [configure openSSL Setting fields: - `url` – The source URL. -- `format` – The file format. All the formats described in "[Formats](../formats/index.md#formats)" are supported. +- `format` – The file format. All the formats described in "[Formats](../interfaces/formats.md#formats)" are supported. diff --git a/docs/en/formats/capnproto.md b/docs/en/formats/capnproto.md deleted file mode 100644 index 918197b2bd9..00000000000 --- a/docs/en/formats/capnproto.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# CapnProto - -Cap'n Proto is a binary message format similar to Protocol Buffers and Thrift, but not like JSON or MessagePack. - -Cap'n Proto messages are strictly typed and not self-describing, meaning they need an external schema description. The schema is applied on the fly and cached for each query. - -```sql -SELECT SearchPhrase, count() AS c FROM test.hits - GROUP BY SearchPhrase FORMAT CapnProto SETTINGS schema = 'schema:Message' -``` - -Where `schema.capnp` looks like this: - -``` -struct Message { - SearchPhrase @0 :Text; - c @1 :Uint64; -} -``` - -Schema files are in the file that is located in the directory specified in [ format_schema_path](../operations/server_settings/settings.md#server_settings-format_schema_path) in the server configuration. - -Deserialization is effective and usually doesn't increase the system load. - diff --git a/docs/en/formats/csv.md b/docs/en/formats/csv.md deleted file mode 100644 index 39b69765604..00000000000 --- a/docs/en/formats/csv.md +++ /dev/null @@ -1,12 +0,0 @@ -# CSV - -Comma Separated Values format ([RFC](https://tools.ietf.org/html/rfc4180)). - -When formatting, rows are enclosed in double quotes. A double quote inside a string is output as two double quotes in a row. There are no other rules for escaping characters. Date and date-time are enclosed in double quotes. Numbers are output without quotes. Values ​​are separated by a delimiter*. Rows are separated using the Unix line feed (LF). Arrays are serialized in CSV as follows: first the array is serialized to a string as in TabSeparated format, and then the resulting string is output to CSV in double quotes. Tuples in CSV format are serialized as separate columns (that is, their nesting in the tuple is lost). - -*By default — `,`. See a [format_csv_delimiter](/docs/en/operations/settings/settings/#format_csv_delimiter) setting for additional info. - -When parsing, all values can be parsed either with or without quotes. Both double and single quotes are supported. Rows can also be arranged without quotes. In this case, they are parsed up to a delimiter or line feed (CR or LF). In violation of the RFC, when parsing rows without quotes, the leading and trailing spaces and tabs are ignored. For the line feed, Unix (LF), Windows (CR LF) and Mac OS Classic (CR LF) are all supported. - -The CSV format supports the output of totals and extremes the same way as `TabSeparated`. - diff --git a/docs/en/formats/csvwithnames.md b/docs/en/formats/csvwithnames.md deleted file mode 100644 index 8933bcb33a0..00000000000 --- a/docs/en/formats/csvwithnames.md +++ /dev/null @@ -1,4 +0,0 @@ -# CSVWithNames - -Also prints the header row, similar to `TabSeparatedWithNames`. - diff --git a/docs/en/formats/index.md b/docs/en/formats/index.md deleted file mode 100644 index 112a13ff5e5..00000000000 --- a/docs/en/formats/index.md +++ /dev/null @@ -1,6 +0,0 @@ - - -# Formats - -The format determines how data is returned to you after SELECTs (how it is written and formatted by the server), and how it is accepted for INSERTs (how it is read and parsed by the server). - diff --git a/docs/en/formats/json.md b/docs/en/formats/json.md deleted file mode 100644 index 554510c2d7a..00000000000 --- a/docs/en/formats/json.md +++ /dev/null @@ -1,85 +0,0 @@ -# JSON - -Outputs data in JSON format. Besides data tables, it also outputs column names and types, along with some additional information: the total number of output rows, and the number of rows that could have been output if there weren't a LIMIT. Example: - -```sql -SELECT SearchPhrase, count() AS c FROM test.hits GROUP BY SearchPhrase WITH TOTALS ORDER BY c DESC LIMIT 5 FORMAT JSON -``` - -```json -{ - "meta": - [ - { - "name": "SearchPhrase", - "type": "String" - }, - { - "name": "c", - "type": "UInt64" - } - ], - - "data": - [ - { - "SearchPhrase": "", - "c": "8267016" - }, - { - "SearchPhrase": "bathroom interior design", - "c": "2166" - }, - { - "SearchPhrase": "yandex", - "c": "1655" - }, - { - "SearchPhrase": "spring 2014 fashion", - "c": "1549" - }, - { - "SearchPhrase": "freeform photos", - "c": "1480" - } - ], - - "totals": - { - "SearchPhrase": "", - "c": "8873898" - }, - - "extremes": - { - "min": - { - "SearchPhrase": "", - "c": "1480" - }, - "max": - { - "SearchPhrase": "", - "c": "8267016" - } - }, - - "rows": 5, - - "rows_before_limit_at_least": 141137 -} -``` - -The JSON is compatible with JavaScript. To ensure this, some characters are additionally escaped: the slash ` /` is escaped as ` \/`; alternative line breaks ` U+2028` and ` U+2029`, which break some browsers, are escaped as ` \uXXXX`. ASCII control characters are escaped: backspace, form feed, line feed, carriage return, and horizontal tab are replaced with `\b`, `\f`, `\n`, `\r`, `\t` , as well as the remaining bytes in the 00-1F range using `\uXXXX` sequences. Invalid UTF-8 sequences are changed to the replacement character � so the output text will consist of valid UTF-8 sequences. For compatibility with JavaScript, Int64 and UInt64 integers are enclosed in double quotes by default. To remove the quotes, you can set the configuration parameter output_format_json_quote_64bit_integers to 0. - -`rows` – The total number of output rows. - -`rows_before_limit_at_least` The minimal number of rows there would have been without LIMIT. Output only if the query contains LIMIT. -If the query contains GROUP BY, rows_before_limit_at_least is the exact number of rows there would have been without a LIMIT. - -`totals` – Total values (when using WITH TOTALS). - -`extremes` – Extreme values (when extremes is set to 1). - -This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). -See also the JSONEachRow format. diff --git a/docs/en/formats/jsoncompact.md b/docs/en/formats/jsoncompact.md deleted file mode 100644 index e4ce0867bc2..00000000000 --- a/docs/en/formats/jsoncompact.md +++ /dev/null @@ -1,46 +0,0 @@ -# JSONCompact - -Differs from JSON only in that data rows are output in arrays, not in objects. - -Example: - -```json -{ - "meta": - [ - { - "name": "SearchPhrase", - "type": "String" - }, - { - "name": "c", - "type": "UInt64" - } - ], - - "data": - [ - ["", "8267016"], - ["bathroom interior design", "2166"], - ["yandex", "1655"], - ["spring 2014 fashion", "1549"], - ["freeform photos", "1480"] - ], - - "totals": ["","8873898"], - - "extremes": - { - "min": ["","1480"], - "max": ["","8267016"] - }, - - "rows": 5, - - "rows_before_limit_at_least": 141137 -} -``` - -This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). -See also the `JSONEachRow` format. - diff --git a/docs/en/formats/jsoneachrow.md b/docs/en/formats/jsoneachrow.md deleted file mode 100644 index 510da367fe5..00000000000 --- a/docs/en/formats/jsoneachrow.md +++ /dev/null @@ -1,21 +0,0 @@ -# JSONEachRow - -Outputs data as separate JSON objects for each row (newline delimited JSON). - -```json -{"SearchPhrase":"","count()":"8267016"} -{"SearchPhrase":"bathroom interior design","count()":"2166"} -{"SearchPhrase":"yandex","count()":"1655"} -{"SearchPhrase":"spring 2014 fashion","count()":"1549"} -{"SearchPhrase":"freeform photo","count()":"1480"} -{"SearchPhrase":"angelina jolie","count()":"1245"} -{"SearchPhrase":"omsk","count()":"1112"} -{"SearchPhrase":"photos of dog breeds","count()":"1091"} -{"SearchPhrase":"curtain design","count()":"1064"} -{"SearchPhrase":"baku","count()":"1000"} -``` - -Unlike the JSON format, there is no substitution of invalid UTF-8 sequences. Any set of bytes can be output in the rows. This is necessary so that data can be formatted without losing any information. Values are escaped in the same way as for JSON. - -For parsing, any order is supported for the values of different columns. It is acceptable for some values to be omitted – they are treated as equal to their default values. In this case, zeros and blank rows are used as default values. Complex values that could be specified in the table are not supported as defaults. Whitespace between elements is ignored. If a comma is placed after the objects, it is ignored. Objects don't necessarily have to be separated by new lines. - diff --git a/docs/en/formats/native.md b/docs/en/formats/native.md deleted file mode 100644 index c3cd06c7bb0..00000000000 --- a/docs/en/formats/native.md +++ /dev/null @@ -1,6 +0,0 @@ -# Native - -The most efficient format. Data is written and read by blocks in binary format. For each block, the number of rows, number of columns, column names and types, and parts of columns in this block are recorded one after another. In other words, this format is "columnar" – it doesn't convert columns to rows. This is the format used in the native interface for interaction between servers, for using the command-line client, and for C++ clients. - -You can use this format to quickly generate dumps that can only be read by the ClickHouse DBMS. It doesn't make sense to work with this format yourself. - diff --git a/docs/en/formats/null.md b/docs/en/formats/null.md deleted file mode 100644 index 119f9d445d4..00000000000 --- a/docs/en/formats/null.md +++ /dev/null @@ -1,5 +0,0 @@ -# Null - -Nothing is output. However, the query is processed, and when using the command-line client, data is transmitted to the client. This is used for tests, including productivity testing. -Obviously, this format is only appropriate for output, not for parsing. - diff --git a/docs/en/formats/pretty.md b/docs/en/formats/pretty.md deleted file mode 100644 index df31e29381d..00000000000 --- a/docs/en/formats/pretty.md +++ /dev/null @@ -1,37 +0,0 @@ -# Pretty - -Outputs data as Unicode-art tables, also using ANSI-escape sequences for setting colors in the terminal. -A full grid of the table is drawn, and each row occupies two lines in the terminal. -Each result block is output as a separate table. This is necessary so that blocks can be output without buffering results (buffering would be necessary in order to pre-calculate the visible width of all the values). -To avoid dumping too much data to the terminal, only the first 10,000 rows are printed. If the number of rows is greater than or equal to 10,000, the message "Showed first 10 000" is printed. -This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). - -The Pretty format supports outputting total values (when using WITH TOTALS) and extremes (when 'extremes' is set to 1). In these cases, total values and extreme values are output after the main data, in separate tables. Example (shown for the PrettyCompact format): - -```sql -SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT PrettyCompact -``` - -```text -┌──EventDate─┬───────c─┐ -│ 2014-03-17 │ 1406958 │ -│ 2014-03-18 │ 1383658 │ -│ 2014-03-19 │ 1405797 │ -│ 2014-03-20 │ 1353623 │ -│ 2014-03-21 │ 1245779 │ -│ 2014-03-22 │ 1031592 │ -│ 2014-03-23 │ 1046491 │ -└────────────┴─────────┘ - -Totals: -┌──EventDate─┬───────c─┐ -│ 0000-00-00 │ 8873898 │ -└────────────┴─────────┘ - -Extremes: -┌──EventDate─┬───────c─┐ -│ 2014-03-17 │ 1031592 │ -│ 2014-03-23 │ 1406958 │ -└────────────┴─────────┘ -``` - diff --git a/docs/en/formats/prettycompact.md b/docs/en/formats/prettycompact.md deleted file mode 100644 index 52b0dd87b2b..00000000000 --- a/docs/en/formats/prettycompact.md +++ /dev/null @@ -1,5 +0,0 @@ -# PrettyCompact - -Differs from `Pretty` in that the grid is drawn between rows and the result is more compact. -This format is used by default in the command-line client in interactive mode. - diff --git a/docs/en/formats/prettycompactmonoblock.md b/docs/en/formats/prettycompactmonoblock.md deleted file mode 100644 index 6c1fd9a0df8..00000000000 --- a/docs/en/formats/prettycompactmonoblock.md +++ /dev/null @@ -1,4 +0,0 @@ -# PrettyCompactMonoBlock - -Differs from `PrettyCompact` in that up to 10,000 rows are buffered, then output as a single table, not by blocks. - diff --git a/docs/en/formats/prettynoescapes.md b/docs/en/formats/prettynoescapes.md deleted file mode 100644 index 51c6ec2e5bf..00000000000 --- a/docs/en/formats/prettynoescapes.md +++ /dev/null @@ -1,20 +0,0 @@ -# PrettyNoEscapes - -Differs from Pretty in that ANSI-escape sequences aren't used. This is necessary for displaying this format in a browser, as well as for using the 'watch' command-line utility. - -Example: - -```bash -watch -n1 "clickhouse-client --query='SELECT * FROM system.events FORMAT PrettyCompactNoEscapes'" -``` - -You can use the HTTP interface for displaying in the browser. - -## PrettyCompactNoEscapes - -The same as the previous setting. - -## PrettySpaceNoEscapes - -The same as the previous setting. - diff --git a/docs/en/formats/prettyspace.md b/docs/en/formats/prettyspace.md deleted file mode 100644 index 5c352a6ee54..00000000000 --- a/docs/en/formats/prettyspace.md +++ /dev/null @@ -1,4 +0,0 @@ -# PrettySpace - -Differs from `PrettyCompact` in that whitespace (space characters) is used instead of the grid. - diff --git a/docs/en/formats/rowbinary.md b/docs/en/formats/rowbinary.md deleted file mode 100644 index aeb3df4c8a8..00000000000 --- a/docs/en/formats/rowbinary.md +++ /dev/null @@ -1,13 +0,0 @@ -# RowBinary - -Formats and parses data by row in binary format. Rows and values are listed consecutively, without separators. -This format is less efficient than the Native format, since it is row-based. - -Integers use fixed-length little endian representation. For example, UInt64 uses 8 bytes. -DateTime is represented as UInt32 containing the Unix timestamp as the value. -Date is represented as a UInt16 object that contains the number of days since 1970-01-01 as the value. -String is represented as a varint length (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), followed by the bytes of the string. -FixedString is represented simply as a sequence of bytes. - -Array is represented as a varint length (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), followed by successive elements of the array. - diff --git a/docs/en/formats/tabseparated.md b/docs/en/formats/tabseparated.md deleted file mode 100644 index 6f4cba79e2f..00000000000 --- a/docs/en/formats/tabseparated.md +++ /dev/null @@ -1,59 +0,0 @@ -# TabSeparated - -In TabSeparated format, data is written by row. Each row contains values separated by tabs. Each value is follow by a tab, except the last value in the row, which is followed by a line feed. Strictly Unix line feeds are assumed everywhere. The last row also must contain a line feed at the end. Values are written in text format, without enclosing quotation marks, and with special characters escaped. - -Integer numbers are written in decimal form. Numbers can contain an extra "+" character at the beginning (ignored when parsing, and not recorded when formatting). Non-negative numbers can't contain the negative sign. When reading, it is allowed to parse an empty string as a zero, or (for signed types) a string consisting of just a minus sign as a zero. Numbers that do not fit into the corresponding data type may be parsed as a different number, without an error message. - -Floating-point numbers are written in decimal form. The dot is used as the decimal separator. Exponential entries are supported, as are 'inf', '+inf', '-inf', and 'nan'. An entry of floating-point numbers may begin or end with a decimal point. -During formatting, accuracy may be lost on floating-point numbers. -During parsing, it is not strictly required to read the nearest machine-representable number. - -Dates are written in YYYY-MM-DD format and parsed in the same format, but with any characters as separators. -Dates with times are written in the format YYYY-MM-DD hh:mm:ss and parsed in the same format, but with any characters as separators. -This all occurs in the system time zone at the time the client or server starts (depending on which one formats data). For dates with times, daylight saving time is not specified. So if a dump has times during daylight saving time, the dump does not unequivocally match the data, and parsing will select one of the two times. -During a read operation, incorrect dates and dates with times can be parsed with natural overflow or as null dates and times, without an error message. - -As an exception, parsing dates with times is also supported in Unix timestamp format, if it consists of exactly 10 decimal digits. The result is not time zone-dependent. The formats YYYY-MM-DD hh:mm:ss and NNNNNNNNNN are differentiated automatically. - -Strings are output with backslash-escaped special characters. The following escape sequences are used for output: `\b`, `\f`, `\r`, `\n`, `\t`, `\0`, `\'`, `\\`. Parsing also supports the sequences `\a`, `\v`, and `\xHH` (hex escape sequences) and any `\c` sequences, where `c` is any character (these sequences are converted to `c`). Thus, reading data supports formats where a line feed can be written as `\n` or `\`, or as a line feed. For example, the string `Hello world` with a line feed between the words instead of a space can be parsed in any of the following variations: - -```text -Hello\nworld - -Hello\ -world -``` - -The second variant is supported because MySQL uses it when writing tab-separated dumps. - -The minimum set of characters that you need to escape when passing data in TabSeparated format: tab, line feed (LF) and backslash. - -Only a small set of symbols are escaped. You can easily stumble onto a string value that your terminal will ruin in output. - -Arrays are written as a list of comma-separated values in square brackets. Number items in the array are fomratted as normally, but dates, dates with times, and strings are written in single quotes with the same escaping rules as above. - -The TabSeparated format is convenient for processing data using custom programs and scripts. It is used by default in the HTTP interface, and in the command-line client's batch mode. This format also allows transferring data between different DBMSs. For example, you can get a dump from MySQL and upload it to ClickHouse, or vice versa. - -The TabSeparated format supports outputting total values (when using WITH TOTALS) and extreme values (when 'extremes' is set to 1). In these cases, the total values and extremes are output after the main data. The main result, total values, and extremes are separated from each other by an empty line. Example: - -```sql -SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT TabSeparated`` -``` - -```text -2014-03-17 1406958 -2014-03-18 1383658 -2014-03-19 1405797 -2014-03-20 1353623 -2014-03-21 1245779 -2014-03-22 1031592 -2014-03-23 1046491 - -0000-00-00 8873898 - -2014-03-17 1031592 -2014-03-23 1406958 -``` - -This format is also available under the name `TSV`. - diff --git a/docs/en/formats/tabseparatedraw.md b/docs/en/formats/tabseparatedraw.md deleted file mode 100644 index 526742f838d..00000000000 --- a/docs/en/formats/tabseparatedraw.md +++ /dev/null @@ -1,7 +0,0 @@ -# TabSeparatedRaw - -Differs from `TabSeparated` format in that the rows are written without escaping. -This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). - -This format is also available under the name ` TSVRaw`. - diff --git a/docs/en/formats/tabseparatedwithnames.md b/docs/en/formats/tabseparatedwithnames.md deleted file mode 100644 index e8d42690bf4..00000000000 --- a/docs/en/formats/tabseparatedwithnames.md +++ /dev/null @@ -1,8 +0,0 @@ -# TabSeparatedWithNames - -Differs from the `TabSeparated` format in that the column names are written in the first row. -During parsing, the first row is completely ignored. You can't use column names to determine their position or to check their correctness. -(Support for parsing the header row may be added in the future.) - -This format is also available under the name ` TSVWithNames`. - diff --git a/docs/en/formats/tabseparatedwithnamesandtypes.md b/docs/en/formats/tabseparatedwithnamesandtypes.md deleted file mode 100644 index 461481fb586..00000000000 --- a/docs/en/formats/tabseparatedwithnamesandtypes.md +++ /dev/null @@ -1,7 +0,0 @@ -# TabSeparatedWithNamesAndTypes - -Differs from the `TabSeparated` format in that the column names are written to the first row, while the column types are in the second row. -During parsing, the first and second rows are completely ignored. - -This format is also available under the name ` TSVWithNamesAndTypes`. - diff --git a/docs/en/formats/tskv.md b/docs/en/formats/tskv.md deleted file mode 100644 index 12de5ccf6e6..00000000000 --- a/docs/en/formats/tskv.md +++ /dev/null @@ -1,23 +0,0 @@ -# TSKV - -Similar to TabSeparated, but outputs a value in name=value format. Names are escaped the same way as in TabSeparated format, and the = symbol is also escaped. - -```text -SearchPhrase= count()=8267016 -SearchPhrase=bathroom interior design count()=2166 -SearchPhrase=yandex count()=1655 -SearchPhrase=spring 2014 fashion count()=1549 -SearchPhrase=freeform photos count()=1480 -SearchPhrase=angelina jolia count()=1245 -SearchPhrase=omsk count()=1112 -SearchPhrase=photos of dog breeds count()=1091 -SearchPhrase=curtain design count()=1064 -SearchPhrase=baku count()=1000 -``` - -When there is a large number of small columns, this format is ineffective, and there is generally no reason to use it. It is used in some departments of Yandex. - -Both data output and parsing are supported in this format. For parsing, any order is supported for the values of different columns. It is acceptable for some values to be omitted – they are treated as equal to their default values. In this case, zeros and blank rows are used as default values. Complex values that could be specified in the table are not supported as defaults. - -Parsing allows the presence of the additional field `tskv` without the equal sign or a value. This field is ignored. - diff --git a/docs/en/formats/values.md b/docs/en/formats/values.md deleted file mode 100644 index a672723f33d..00000000000 --- a/docs/en/formats/values.md +++ /dev/null @@ -1,8 +0,0 @@ -# Values - -Prints every row in brackets. Rows are separated by commas. There is no comma after the last row. The values inside the brackets are also comma-separated. Numbers are output in decimal format without quotes. Arrays are output in square brackets. Strings, dates, and dates with times are output in quotes. Escaping rules and parsing are similar to the TabSeparated format. During formatting, extra spaces aren't inserted, but during parsing, they are allowed and skipped (except for spaces inside array values, which are not allowed). - -The minimum set of characters that you need to escape when passing data in Values ​​format: single quotes and backslashes. - -This is the format that is used in `INSERT INTO t VALUES ...`, but you can also use it for formatting query results. - diff --git a/docs/en/formats/vertical.md b/docs/en/formats/vertical.md deleted file mode 100644 index 71ec816a3f2..00000000000 --- a/docs/en/formats/vertical.md +++ /dev/null @@ -1,5 +0,0 @@ -# Vertical - -Prints each value on a separate line with the column name specified. This format is convenient for printing just one or a few rows, if each row consists of a large number of columns. -This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). - diff --git a/docs/en/formats/verticalraw.md b/docs/en/formats/verticalraw.md deleted file mode 100644 index edff754a7cd..00000000000 --- a/docs/en/formats/verticalraw.md +++ /dev/null @@ -1,28 +0,0 @@ -# VerticalRaw - -Differs from `Vertical` format in that the rows are not escaped. -This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). - -Examples: - -``` -:) SHOW CREATE TABLE geonames FORMAT VerticalRaw; -Row 1: -────── -statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) - -:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; -Row 1: -────── -test: string with 'quotes' and with some special - characters -``` - -Compare with the Vertical format: - -``` -:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical; -Row 1: -────── -test: string with \'quotes\' and \t with some special \n characters -``` diff --git a/docs/en/formats/xml.md b/docs/en/formats/xml.md deleted file mode 100644 index 5188b9514a8..00000000000 --- a/docs/en/formats/xml.md +++ /dev/null @@ -1,74 +0,0 @@ -# XML - -XML format is suitable only for output, not for parsing. Example: - -```xml - - - - - - SearchPhrase - String - - - count() - UInt64 - - - - - - - 8267016 - - - bathroom interior design - 2166 - - - yandex - 1655 - - - spring 2014 fashion - 1549 - - - freeform photos - 1480 - - - angelina jolie - 1245 - - - omsk - 1112 - - - photos of dog breeds - 1091 - - - curtain design - 1064 - - - baku - 1000 - - - 10 - 141137 - -``` - -If the column name does not have an acceptable format, just 'field' is used as the element name. In general, the XML structure follows the JSON structure. -Just as for JSON, invalid UTF-8 sequences are changed to the replacement character � so the output text will consist of valid UTF-8 sequences. - -In string values, the characters `<` and `&` are escaped as `<` and `&`. - -Arrays are output as `HelloWorld...`, -and tuples as `HelloWorld...`. - diff --git a/docs/en/interfaces/formats.md b/docs/en/interfaces/formats.md new file mode 100644 index 00000000000..5284aa0665e --- /dev/null +++ b/docs/en/interfaces/formats.md @@ -0,0 +1,513 @@ + + +# Formats + +The format determines how data is returned to you after SELECTs (how it is written and formatted by the server), and how it is accepted for INSERTs (how it is read and parsed by the server). + + + +## CapnProto + +Cap'n Proto is a binary message format similar to Protocol Buffers and Thrift, but not like JSON or MessagePack. + +Cap'n Proto messages are strictly typed and not self-describing, meaning they need an external schema description. The schema is applied on the fly and cached for each query. + +```sql +SELECT SearchPhrase, count() AS c FROM test.hits + GROUP BY SearchPhrase FORMAT CapnProto SETTINGS schema = 'schema:Message' +``` + +Where `schema.capnp` looks like this: + +``` +struct Message { + SearchPhrase @0 :Text; + c @1 :Uint64; +} +``` + +Schema files are in the file that is located in the directory specified in [ format_schema_path](../operations/server_settings/settings.md#server_settings-format_schema_path) in the server configuration. + +Deserialization is effective and usually doesn't increase the system load. + +## CSV + +Comma Separated Values format ([RFC](https://tools.ietf.org/html/rfc4180)). + +When formatting, rows are enclosed in double quotes. A double quote inside a string is output as two double quotes in a row. There are no other rules for escaping characters. Date and date-time are enclosed in double quotes. Numbers are output without quotes. Values ​​are separated by a delimiter*. Rows are separated using the Unix line feed (LF). Arrays are serialized in CSV as follows: first the array is serialized to a string as in TabSeparated format, and then the resulting string is output to CSV in double quotes. Tuples in CSV format are serialized as separate columns (that is, their nesting in the tuple is lost). + +*By default — `,`. See a [format_csv_delimiter](/docs/en/operations/settings/settings/#format_csv_delimiter) setting for additional info. + +When parsing, all values can be parsed either with or without quotes. Both double and single quotes are supported. Rows can also be arranged without quotes. In this case, they are parsed up to a delimiter or line feed (CR or LF). In violation of the RFC, when parsing rows without quotes, the leading and trailing spaces and tabs are ignored. For the line feed, Unix (LF), Windows (CR LF) and Mac OS Classic (CR LF) are all supported. + +The CSV format supports the output of totals and extremes the same way as `TabSeparated`. + +## CSVWithNames + +Also prints the header row, similar to `TabSeparatedWithNames`. + +## JSON + +Outputs data in JSON format. Besides data tables, it also outputs column names and types, along with some additional information: the total number of output rows, and the number of rows that could have been output if there weren't a LIMIT. Example: + +```sql +SELECT SearchPhrase, count() AS c FROM test.hits GROUP BY SearchPhrase WITH TOTALS ORDER BY c DESC LIMIT 5 FORMAT JSON +``` + +```json +{ + "meta": + [ + { + "name": "SearchPhrase", + "type": "String" + }, + { + "name": "c", + "type": "UInt64" + } + ], + + "data": + [ + { + "SearchPhrase": "", + "c": "8267016" + }, + { + "SearchPhrase": "bathroom interior design", + "c": "2166" + }, + { + "SearchPhrase": "yandex", + "c": "1655" + }, + { + "SearchPhrase": "spring 2014 fashion", + "c": "1549" + }, + { + "SearchPhrase": "freeform photos", + "c": "1480" + } + ], + + "totals": + { + "SearchPhrase": "", + "c": "8873898" + }, + + "extremes": + { + "min": + { + "SearchPhrase": "", + "c": "1480" + }, + "max": + { + "SearchPhrase": "", + "c": "8267016" + } + }, + + "rows": 5, + + "rows_before_limit_at_least": 141137 +} +``` + +The JSON is compatible with JavaScript. To ensure this, some characters are additionally escaped: the slash ` /` is escaped as ` \/`; alternative line breaks ` U+2028` and ` U+2029`, which break some browsers, are escaped as ` \uXXXX`. ASCII control characters are escaped: backspace, form feed, line feed, carriage return, and horizontal tab are replaced with `\b`, `\f`, `\n`, `\r`, `\t` , as well as the remaining bytes in the 00-1F range using `\uXXXX` sequences. Invalid UTF-8 sequences are changed to the replacement character � so the output text will consist of valid UTF-8 sequences. For compatibility with JavaScript, Int64 and UInt64 integers are enclosed in double quotes by default. To remove the quotes, you can set the configuration parameter output_format_json_quote_64bit_integers to 0. + +`rows` – The total number of output rows. + +`rows_before_limit_at_least` The minimal number of rows there would have been without LIMIT. Output only if the query contains LIMIT. +If the query contains GROUP BY, rows_before_limit_at_least is the exact number of rows there would have been without a LIMIT. + +`totals` – Total values (when using WITH TOTALS). + +`extremes` – Extreme values (when extremes is set to 1). + +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). +See also the JSONEachRow format. +## JSONCompact + +Differs from JSON only in that data rows are output in arrays, not in objects. + +Example: + +```json +{ + "meta": + [ + { + "name": "SearchPhrase", + "type": "String" + }, + { + "name": "c", + "type": "UInt64" + } + ], + + "data": + [ + ["", "8267016"], + ["bathroom interior design", "2166"], + ["yandex", "1655"], + ["spring 2014 fashion", "1549"], + ["freeform photos", "1480"] + ], + + "totals": ["","8873898"], + + "extremes": + { + "min": ["","1480"], + "max": ["","8267016"] + }, + + "rows": 5, + + "rows_before_limit_at_least": 141137 +} +``` + +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). +See also the `JSONEachRow` format. + +## JSONEachRow + +Outputs data as separate JSON objects for each row (newline delimited JSON). + +```json +{"SearchPhrase":"","count()":"8267016"} +{"SearchPhrase":"bathroom interior design","count()":"2166"} +{"SearchPhrase":"yandex","count()":"1655"} +{"SearchPhrase":"spring 2014 fashion","count()":"1549"} +{"SearchPhrase":"freeform photo","count()":"1480"} +{"SearchPhrase":"angelina jolie","count()":"1245"} +{"SearchPhrase":"omsk","count()":"1112"} +{"SearchPhrase":"photos of dog breeds","count()":"1091"} +{"SearchPhrase":"curtain design","count()":"1064"} +{"SearchPhrase":"baku","count()":"1000"} +``` + +Unlike the JSON format, there is no substitution of invalid UTF-8 sequences. Any set of bytes can be output in the rows. This is necessary so that data can be formatted without losing any information. Values are escaped in the same way as for JSON. + +For parsing, any order is supported for the values of different columns. It is acceptable for some values to be omitted – they are treated as equal to their default values. In this case, zeros and blank rows are used as default values. Complex values that could be specified in the table are not supported as defaults. Whitespace between elements is ignored. If a comma is placed after the objects, it is ignored. Objects don't necessarily have to be separated by new lines. + +## Native + +The most efficient format. Data is written and read by blocks in binary format. For each block, the number of rows, number of columns, column names and types, and parts of columns in this block are recorded one after another. In other words, this format is "columnar" – it doesn't convert columns to rows. This is the format used in the native interface for interaction between servers, for using the command-line client, and for C++ clients. + +You can use this format to quickly generate dumps that can only be read by the ClickHouse DBMS. It doesn't make sense to work with this format yourself. + +## Null + +Nothing is output. However, the query is processed, and when using the command-line client, data is transmitted to the client. This is used for tests, including productivity testing. +Obviously, this format is only appropriate for output, not for parsing. + +## Pretty + +Outputs data as Unicode-art tables, also using ANSI-escape sequences for setting colors in the terminal. +A full grid of the table is drawn, and each row occupies two lines in the terminal. +Each result block is output as a separate table. This is necessary so that blocks can be output without buffering results (buffering would be necessary in order to pre-calculate the visible width of all the values). +To avoid dumping too much data to the terminal, only the first 10,000 rows are printed. If the number of rows is greater than or equal to 10,000, the message "Showed first 10 000" is printed. +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). + +The Pretty format supports outputting total values (when using WITH TOTALS) and extremes (when 'extremes' is set to 1). In these cases, total values and extreme values are output after the main data, in separate tables. Example (shown for the PrettyCompact format): + +```sql +SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT PrettyCompact +``` + +```text +┌──EventDate─┬───────c─┐ +│ 2014-03-17 │ 1406958 │ +│ 2014-03-18 │ 1383658 │ +│ 2014-03-19 │ 1405797 │ +│ 2014-03-20 │ 1353623 │ +│ 2014-03-21 │ 1245779 │ +│ 2014-03-22 │ 1031592 │ +│ 2014-03-23 │ 1046491 │ +└────────────┴─────────┘ + +Totals: +┌──EventDate─┬───────c─┐ +│ 0000-00-00 │ 8873898 │ +└────────────┴─────────┘ + +Extremes: +┌──EventDate─┬───────c─┐ +│ 2014-03-17 │ 1031592 │ +│ 2014-03-23 │ 1406958 │ +└────────────┴─────────┘ +``` + +## PrettyCompact + +Differs from `Pretty` in that the grid is drawn between rows and the result is more compact. +This format is used by default in the command-line client in interactive mode. + +## PrettyCompactMonoBlock + +Differs from `PrettyCompact` in that up to 10,000 rows are buffered, then output as a single table, not by blocks. + +## PrettyNoEscapes + +Differs from Pretty in that ANSI-escape sequences aren't used. This is necessary for displaying this format in a browser, as well as for using the 'watch' command-line utility. + +Example: + +```bash +watch -n1 "clickhouse-client --query='SELECT * FROM system.events FORMAT PrettyCompactNoEscapes'" +``` + +You can use the HTTP interface for displaying in the browser. + +### PrettyCompactNoEscapes + +The same as the previous setting. + +### PrettySpaceNoEscapes + +The same as the previous setting. + +## PrettySpace + +Differs from `PrettyCompact` in that whitespace (space characters) is used instead of the grid. + +## RowBinary + +Formats and parses data by row in binary format. Rows and values are listed consecutively, without separators. +This format is less efficient than the Native format, since it is row-based. + +Integers use fixed-length little endian representation. For example, UInt64 uses 8 bytes. +DateTime is represented as UInt32 containing the Unix timestamp as the value. +Date is represented as a UInt16 object that contains the number of days since 1970-01-01 as the value. +String is represented as a varint length (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), followed by the bytes of the string. +FixedString is represented simply as a sequence of bytes. + +Array is represented as a varint length (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), followed by successive elements of the array. + +## TabSeparated + +In TabSeparated format, data is written by row. Each row contains values separated by tabs. Each value is follow by a tab, except the last value in the row, which is followed by a line feed. Strictly Unix line feeds are assumed everywhere. The last row also must contain a line feed at the end. Values are written in text format, without enclosing quotation marks, and with special characters escaped. + +Integer numbers are written in decimal form. Numbers can contain an extra "+" character at the beginning (ignored when parsing, and not recorded when formatting). Non-negative numbers can't contain the negative sign. When reading, it is allowed to parse an empty string as a zero, or (for signed types) a string consisting of just a minus sign as a zero. Numbers that do not fit into the corresponding data type may be parsed as a different number, without an error message. + +Floating-point numbers are written in decimal form. The dot is used as the decimal separator. Exponential entries are supported, as are 'inf', '+inf', '-inf', and 'nan'. An entry of floating-point numbers may begin or end with a decimal point. +During formatting, accuracy may be lost on floating-point numbers. +During parsing, it is not strictly required to read the nearest machine-representable number. + +Dates are written in YYYY-MM-DD format and parsed in the same format, but with any characters as separators. +Dates with times are written in the format YYYY-MM-DD hh:mm:ss and parsed in the same format, but with any characters as separators. +This all occurs in the system time zone at the time the client or server starts (depending on which one formats data). For dates with times, daylight saving time is not specified. So if a dump has times during daylight saving time, the dump does not unequivocally match the data, and parsing will select one of the two times. +During a read operation, incorrect dates and dates with times can be parsed with natural overflow or as null dates and times, without an error message. + +As an exception, parsing dates with times is also supported in Unix timestamp format, if it consists of exactly 10 decimal digits. The result is not time zone-dependent. The formats YYYY-MM-DD hh:mm:ss and NNNNNNNNNN are differentiated automatically. + +Strings are output with backslash-escaped special characters. The following escape sequences are used for output: `\b`, `\f`, `\r`, `\n`, `\t`, `\0`, `\'`, `\\`. Parsing also supports the sequences `\a`, `\v`, and `\xHH` (hex escape sequences) and any `\c` sequences, where `c` is any character (these sequences are converted to `c`). Thus, reading data supports formats where a line feed can be written as `\n` or `\`, or as a line feed. For example, the string `Hello world` with a line feed between the words instead of a space can be parsed in any of the following variations: + +```text +Hello\nworld + +Hello\ +world +``` + +The second variant is supported because MySQL uses it when writing tab-separated dumps. + +The minimum set of characters that you need to escape when passing data in TabSeparated format: tab, line feed (LF) and backslash. + +Only a small set of symbols are escaped. You can easily stumble onto a string value that your terminal will ruin in output. + +Arrays are written as a list of comma-separated values in square brackets. Number items in the array are fomratted as normally, but dates, dates with times, and strings are written in single quotes with the same escaping rules as above. + +The TabSeparated format is convenient for processing data using custom programs and scripts. It is used by default in the HTTP interface, and in the command-line client's batch mode. This format also allows transferring data between different DBMSs. For example, you can get a dump from MySQL and upload it to ClickHouse, or vice versa. + +The TabSeparated format supports outputting total values (when using WITH TOTALS) and extreme values (when 'extremes' is set to 1). In these cases, the total values and extremes are output after the main data. The main result, total values, and extremes are separated from each other by an empty line. Example: + +```sql +SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT TabSeparated`` +``` + +```text +2014-03-17 1406958 +2014-03-18 1383658 +2014-03-19 1405797 +2014-03-20 1353623 +2014-03-21 1245779 +2014-03-22 1031592 +2014-03-23 1046491 + +0000-00-00 8873898 + +2014-03-17 1031592 +2014-03-23 1406958 +``` + +This format is also available under the name `TSV`. + +## TabSeparatedRaw + +Differs from `TabSeparated` format in that the rows are written without escaping. +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). + +This format is also available under the name ` TSVRaw`. + +## TabSeparatedWithNames + +Differs from the `TabSeparated` format in that the column names are written in the first row. +During parsing, the first row is completely ignored. You can't use column names to determine their position or to check their correctness. +(Support for parsing the header row may be added in the future.) + +This format is also available under the name ` TSVWithNames`. + +## TabSeparatedWithNamesAndTypes + +Differs from the `TabSeparated` format in that the column names are written to the first row, while the column types are in the second row. +During parsing, the first and second rows are completely ignored. + +This format is also available under the name ` TSVWithNamesAndTypes`. + +## TSKV + +Similar to TabSeparated, but outputs a value in name=value format. Names are escaped the same way as in TabSeparated format, and the = symbol is also escaped. + +```text +SearchPhrase= count()=8267016 +SearchPhrase=bathroom interior design count()=2166 +SearchPhrase=yandex count()=1655 +SearchPhrase=spring 2014 fashion count()=1549 +SearchPhrase=freeform photos count()=1480 +SearchPhrase=angelina jolia count()=1245 +SearchPhrase=omsk count()=1112 +SearchPhrase=photos of dog breeds count()=1091 +SearchPhrase=curtain design count()=1064 +SearchPhrase=baku count()=1000 +``` + +When there is a large number of small columns, this format is ineffective, and there is generally no reason to use it. It is used in some departments of Yandex. + +Both data output and parsing are supported in this format. For parsing, any order is supported for the values of different columns. It is acceptable for some values to be omitted – they are treated as equal to their default values. In this case, zeros and blank rows are used as default values. Complex values that could be specified in the table are not supported as defaults. + +Parsing allows the presence of the additional field `tskv` without the equal sign or a value. This field is ignored. + +## Values + +Prints every row in brackets. Rows are separated by commas. There is no comma after the last row. The values inside the brackets are also comma-separated. Numbers are output in decimal format without quotes. Arrays are output in square brackets. Strings, dates, and dates with times are output in quotes. Escaping rules and parsing are similar to the TabSeparated format. During formatting, extra spaces aren't inserted, but during parsing, they are allowed and skipped (except for spaces inside array values, which are not allowed). + +The minimum set of characters that you need to escape when passing data in Values ​​format: single quotes and backslashes. + +This is the format that is used in `INSERT INTO t VALUES ...`, but you can also use it for formatting query results. + +## Vertical + +Prints each value on a separate line with the column name specified. This format is convenient for printing just one or a few rows, if each row consists of a large number of columns. +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). + +## VerticalRaw + +Differs from `Vertical` format in that the rows are not escaped. +This format is only appropriate for outputting a query result, but not for parsing (retrieving data to insert in a table). + +Examples: + +``` +:) SHOW CREATE TABLE geonames FORMAT VerticalRaw; +Row 1: +────── +statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) + +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; +Row 1: +────── +test: string with 'quotes' and with some special + characters +``` + +Compare with the Vertical format: + +``` +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical; +Row 1: +────── +test: string with \'quotes\' and \t with some special \n characters +``` +## XML + +XML format is suitable only for output, not for parsing. Example: + +```xml + + + + + + SearchPhrase + String + + + count() + UInt64 + + + + + + + 8267016 + + + bathroom interior design + 2166 + + + yandex + 1655 + + + spring 2014 fashion + 1549 + + + freeform photos + 1480 + + + angelina jolie + 1245 + + + omsk + 1112 + + + photos of dog breeds + 1091 + + + curtain design + 1064 + + + baku + 1000 + + + 10 + 141137 + +``` + +If the column name does not have an acceptable format, just 'field' is used as the element name. In general, the XML structure follows the JSON structure. +Just as for JSON, invalid UTF-8 sequences are changed to the replacement character � so the output text will consist of valid UTF-8 sequences. + +In string values, the characters `<` and `&` are escaped as `<` and `&`. + +Arrays are output as `HelloWorld...`, +and tuples as `HelloWorld...`. + diff --git a/docs/en/operations/server_settings/settings.md b/docs/en/operations/server_settings/settings.md index 5a169a69550..ed0bbe5b893 100644 --- a/docs/en/operations/server_settings/settings.md +++ b/docs/en/operations/server_settings/settings.md @@ -130,7 +130,7 @@ The default is ` true`. ## format_schema_path -The path to the directory with the schemes for the input data, such as schemas for the [CapnProto](../../formats/capnproto.md#format_capnproto) format. +The path to the directory with the schemes for the input data, such as schemas for the [CapnProto](../../interfaces/formats.md#format_capnproto) format. **Example** diff --git a/docs/en/query_language/queries.md b/docs/en/query_language/queries.md index d2078a65d46..a7f7a7cbc32 100644 --- a/docs/en/query_language/queries.md +++ b/docs/en/query_language/queries.md @@ -615,7 +615,7 @@ The query can specify a list of columns to insert `[(c1, c2, c3)]`. In this case If [strict_insert_defaults=1](../operations/settings/settings.md#settings-strict_insert_defaults), columns that do not have `DEFAULT` defined must be listed in the query. -Data can be passed to the INSERT in any [format](../formats/index.md#formats) supported by ClickHouse. The format must be specified explicitly in the query: +Data can be passed to the INSERT in any [format](../interfaces/formats.md#formats) supported by ClickHouse. The format must be specified explicitly in the query: ```sql INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set diff --git a/docs/en/table_functions/file.md b/docs/en/table_functions/file.md index c0b15e7cc9a..1ec3634c6b5 100644 --- a/docs/en/table_functions/file.md +++ b/docs/en/table_functions/file.md @@ -6,7 +6,7 @@ path - a relative path to a file from [user_files_path](../operations/server_settings/settings.md#user_files_path). -format - file [format](../formats/index.md#formats). +format - file [format](../interfaces/formats.md#formats). structure - table structure in 'UserID UInt64, URL String' format. Determines column names and types. diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 9d07d7711db..a96fbe27409 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -27,6 +27,7 @@ pages: - 'Native interface (TCP)': 'interfaces/tcp.md' - 'Libraries from third-party developers': 'interfaces/third-party_client_libraries.md' - 'Visual interfaces from third-party developers': 'interfaces/third-party_gui.md' + - 'Formats': 'interfaces/formats.md' - 'Query language': # - 'Query language': 'query_language/index.md' @@ -67,32 +68,6 @@ pages: - 'numbers': 'table_functions/numbers.md' - 'remote': 'table_functions/remote.md' -- 'Formats': - - 'Introduction': 'formats/index.md' - - 'TabSeparated': 'formats/tabseparated.md' - - 'TabSeparatedRaw': 'formats/tabseparatedraw.md' - - 'TabSeparatedWithNames': 'formats/tabseparatedwithnames.md' - - 'TabSeparatedWithNamesAndTypes': 'formats/tabseparatedwithnamesandtypes.md' - - 'CSV': 'formats/csv.md' - - 'CSVWithNames': 'formats/csvwithnames.md' - - 'Values': 'formats/values.md' - - 'Vertical': 'formats/vertical.md' - - 'VerticalRaw': 'formats/verticalraw.md' - - 'JSON': 'formats/json.md' - - 'JSONCompact': 'formats/jsoncompact.md' - - 'JSONEachRow': 'formats/jsoneachrow.md' - - 'TSKV': 'formats/tskv.md' - - 'Pretty': 'formats/pretty.md' - - 'PrettyCompact': 'formats/prettycompact.md' - - 'PrettyCompactMonoBlock': 'formats/prettycompactmonoblock.md' - - 'PrettyNoEscapes': 'formats/prettynoescapes.md' - - 'PrettySpace': 'formats/prettyspace.md' - - 'RowBinary': 'formats/rowbinary.md' - - 'Native': 'formats/native.md' - - 'Null': 'formats/null.md' - - 'XML': 'formats/xml.md' - - 'CapnProto': 'formats/capnproto.md' - - 'Data types': - 'Introduction': 'data_types/index.md' - 'UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64': 'data_types/int_uint.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 646456eb32b..de5f255db2b 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -27,6 +27,7 @@ pages: - 'Родной интерфейс (TCP)': 'interfaces/tcp.md' - 'Библиотеки от сторонних разработчиков': 'interfaces/third-party_client_libraries.md' - 'Визуальные интерфейсы от сторонних разработчиков': 'interfaces/third-party_gui.md' + - 'Форматы входных и выходных данных': 'interfaces/formats.md' - 'Язык запросов': # - 'Язык запросов': 'query_language/index.md' @@ -67,32 +68,6 @@ pages: - 'numbers': 'table_functions/numbers.md' - 'remote': 'table_functions/remote.md' -- 'Форматы': - - 'Введение': 'formats/index.md' - - 'TabSeparated': 'formats/tabseparated.md' - - 'TabSeparatedRaw': 'formats/tabseparatedraw.md' - - 'TabSeparatedWithNames': 'formats/tabseparatedwithnames.md' - - 'TabSeparatedWithNamesAndTypes': 'formats/tabseparatedwithnamesandtypes.md' - - 'CSV': 'formats/csv.md' - - 'CSVWithNames': 'formats/csvwithnames.md' - - 'Values': 'formats/values.md' - - 'Vertical': 'formats/vertical.md' - - 'VerticalRaw': 'formats/verticalraw.md' - - 'JSON': 'formats/json.md' - - 'JSONCompact': 'formats/jsoncompact.md' - - 'JSONEachRow': 'formats/jsoneachrow.md' - - 'TSKV': 'formats/tskv.md' - - 'Pretty': 'formats/pretty.md' - - 'PrettyCompact': 'formats/prettycompact.md' - - 'PrettyCompactMonoBlock': 'formats/prettycompactmonoblock.md' - - 'PrettyNoEscapes': 'formats/prettynoescapes.md' - - 'PrettySpace': 'formats/prettyspace.md' - - 'RowBinary': 'formats/rowbinary.md' - - 'Native': 'formats/native.md' - - 'Null': 'formats/null.md' - - 'XML': 'formats/xml.md' - - 'CapnProto': 'formats/capnproto.md' - - 'Типы данных': - 'Введение': 'data_types/index.md' - 'UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64': 'data_types/int_uint.md' diff --git a/docs/redirects.txt b/docs/redirects.txt index 230c8919098..a7d1be92f5e 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -17,3 +17,27 @@ system_tables/system.replicas.md operations/system_tables.md system_tables/system.settings.md operations/system_tables.md system_tables/system.tables.md operations/system_tables.md system_tables/system.zookeeper.md operations/system_tables.md +formats/capnproto.md formats/interfaces.md +formats/csv.md formats/interfaces.md +formats/csvwithnames.md formats/interfaces.md +formats/index.md formats/interfaces.md +formats/json.md formats/interfaces.md +formats/jsoncompact.md formats/interfaces.md +formats/jsoneachrow.md formats/interfaces.md +formats/native.md formats/interfaces.md +formats/null.md formats/interfaces.md +formats/pretty.md formats/interfaces.md +formats/prettycompact.md formats/interfaces.md +formats/prettycompactmonoblock.md formats/interfaces.md +formats/prettynoescapes.md formats/interfaces.md +formats/prettyspace.md formats/interfaces.md +formats/rowbinary.md formats/interfaces.md +formats/tabseparated.md formats/interfaces.md +formats/tabseparatedraw.md formats/interfaces.md +formats/tabseparatedwithnames.md formats/interfaces.md +formats/tabseparatedwithnamesandtypes.md formats/interfaces.md +formats/tskv.md formats/interfaces.md +formats/values.md formats/interfaces.md +formats/vertical.md formats/interfaces.md +formats/verticalraw.md formats/interfaces.md +formats/xml.md formats/interfaces.md diff --git a/docs/ru/dicts/external_dicts_dict_sources.md b/docs/ru/dicts/external_dicts_dict_sources.md index 9faf164abe3..083d14d4159 100644 --- a/docs/ru/dicts/external_dicts_dict_sources.md +++ b/docs/ru/dicts/external_dicts_dict_sources.md @@ -52,7 +52,7 @@ Поля настройки: - `path` - Абсолютный путь к файлу. -- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../formats/index.md#formats)". +- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../interfaces/formats.md#formats)". @@ -74,7 +74,7 @@ Поля настройки: - `command` - Абсолютный путь к исполняемому файлу или имя файла (если каталог программы прописан в `PATH`). -- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../formats/index.md#formats)". +- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../interfaces/formats.md#formats)". @@ -98,7 +98,7 @@ Поля настройки: - `url` - URL источника. -- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../formats/index.md#formats)". +- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../interfaces/formats.md#formats)". diff --git a/docs/ru/formats/capnproto.md b/docs/ru/formats/capnproto.md deleted file mode 100644 index f3a309434f4..00000000000 --- a/docs/ru/formats/capnproto.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# CapnProto - -Cap'n Proto - формат бинарных сообщений, похож на Protocol Buffers и Thrift, но не похож на JSON или MessagePack. - -Сообщения Cap'n Proto строго типизированы и не самоописывающиеся, т.е. нуждаются во внешнем описании схемы. Схема применяется "на лету" и кешируется для каждого запроса. - -```sql -SELECT SearchPhrase, count() AS c FROM test.hits - GROUP BY SearchPhrase FORMAT CapnProto SETTINGS schema = 'schema:Message' -``` - -Где `schema.capnp` выглядит следующим образом: - -``` -struct Message { - SearchPhrase @0 :Text; - c @1 :Uint64; -} -``` - - -Файлы со схемами находятся в файле, который находится в каталоге указанном в параметре [format_schema_path](../operations/server_settings/settings.md#server_settings-format_schema_path) конфигурации сервера. - -Десериализация эффективна и обычно не повышает нагрузку на систему. diff --git a/docs/ru/formats/csv.md b/docs/ru/formats/csv.md deleted file mode 100644 index a1d0dee45c9..00000000000 --- a/docs/ru/formats/csv.md +++ /dev/null @@ -1,13 +0,0 @@ - - -# CSV - -Формат comma separated values ([RFC](https://tools.ietf.org/html/rfc4180)). - -При форматировании, строки выводятся в двойных кавычках. Двойная кавычка внутри строки выводится как две двойные кавычки подряд. Других правил экранирования нет. Даты и даты-с-временем выводятся в двойных кавычках. Числа выводятся без кавычек. Значения разделяются символом-разделителем*. Строки разделяются unix переводом строки (LF). Массивы сериализуются в CSV следующим образом: сначала массив сериализуется в строку, как в формате TabSeparated, а затем полученная строка выводится в CSV в двойных кавычках. Кортежи в формате CSV сериализуются, как отдельные столбцы (то есть, теряется их вложенность в кортеж). - -*По умолчанию — `,`. См. настройку [format_csv_delimiter](/docs/ru/operations/settings/settings/#format_csv_delimiter) для дополнительной информации. - -При парсинге, все значения могут парситься как в кавычках, так и без кавычек. Поддерживаются как двойные, так и одинарные кавычки. В том числе, строки могут быть расположены без кавычек - тогда они парсятся до символа-разделителя или перевода строки (CR или LF). В нарушение RFC, в случае парсинга строк не в кавычках, начальные и конечные пробелы и табы игнорируются. В качестве перевода строки, поддерживаются как Unix (LF), так и Windows (CR LF) и Mac OS Classic (LF CR) варианты. - -Формат CSV поддерживает вывод totals и extremes аналогично `TabSeparated`. diff --git a/docs/ru/formats/csvwithnames.md b/docs/ru/formats/csvwithnames.md deleted file mode 100644 index 1755713ee6e..00000000000 --- a/docs/ru/formats/csvwithnames.md +++ /dev/null @@ -1,5 +0,0 @@ - - -# CSVWithNames - -Выводит также заголовок, аналогично `TabSeparatedWithNames`. diff --git a/docs/ru/formats/index.md b/docs/ru/formats/index.md deleted file mode 100644 index 1646cce452b..00000000000 --- a/docs/ru/formats/index.md +++ /dev/null @@ -1,33 +0,0 @@ - - -# Форматы входных и выходных данных - -ClickHouse может принимать (`INSERT`) и отдавать (`SELECT`) данные в различных форматах. - -Поддерживаемые форматы и возможность использовать их в запросах `INSERT` и `SELECT` перечислены в таблице ниже. - -Формат | INSERT | SELECT --------|--------|-------- -[TabSeparated](tabseparated.md#tabseparated) | ✔ | ✔ | -[TabSeparatedRaw](tabseparatedraw.md#tabseparatedraw) | ✗ | ✔ | -[TabSeparatedWithNames](tabseparatedwithnames.md#tabseparatedwithnames) | ✔ | ✔ | -[TabSeparatedWithNamesAndTypes](tabseparatedwithnamesandtypes.md#tabseparatedwithnamesandtypes) | ✔ | ✔ | -[CSV](csv.md#csv) | ✔ | ✔ | -[CSVWithNames](csvwithnames.md#csvwithnames) | ✔ | ✔ | -[Values](values.md#values) | ✔ | ✔ | -[Vertical](vertical.md#vertical) | ✗ | ✔ | -[VerticalRaw](verticalraw.md#verticalraw) | ✗ | ✔ | -[JSON](json.md#json) | ✗ | ✔ | -[JSONCompact](jsoncompact.md#jsoncompact) | ✗ | ✔ | -[JSONEachRow](jsoneachrow.md#jsoneachrow) | ✔ | ✔ | -[TSKV](tskv.md#tskv) | ✔ | ✔ | -[Pretty](pretty.md#pretty) | ✗ | ✔ | -[PrettyCompact](prettycompact.md#prettycompact) | ✗ | ✔ | -[PrettyCompactMonoBlock](prettycompactmonoblock.md#prettycompactmonoblock) | ✗ | ✔ | -[PrettyNoEscapes](prettynoescapes.md#prettynoescapes) | ✗ | ✔ | -[PrettySpace](prettyspace.md#prettyspace) | ✗ | ✔ | -[RowBinary](rowbinary.md#rowbinary) | ✔ | ✔ | -[Native](native.md#native) | ✔ | ✔ | -[Null](null.md#null) | ✗ | ✔ | -[XML](xml.md#xml) | ✗ | ✔ | -[CapnProto](capnproto.md#capnproto) | ✔ | ✔ | diff --git a/docs/ru/formats/json.md b/docs/ru/formats/json.md deleted file mode 100644 index 5664e54297f..00000000000 --- a/docs/ru/formats/json.md +++ /dev/null @@ -1,87 +0,0 @@ - - -# JSON - -Выводит данные в формате JSON. Кроме таблицы с данными, также выводятся имена и типы столбцов, и некоторая дополнительная информация - общее количество выведенных строк, а также количество строк, которое могло бы быть выведено, если бы не было LIMIT-а. Пример: - -```sql -SELECT SearchPhrase, count() AS c FROM test.hits GROUP BY SearchPhrase WITH TOTALS ORDER BY c DESC LIMIT 5 FORMAT JSON -``` - -```json -{ - "meta": - [ - { - "name": "SearchPhrase", - "type": "String" - }, - { - "name": "c", - "type": "UInt64" - } - ], - - "data": - [ - { - "SearchPhrase": "", - "c": "8267016" - }, - { - "SearchPhrase": "bathroom interior design", - "c": "2166" - }, - { - "SearchPhrase": "yandex", - "c": "1655" - }, - { - "SearchPhrase": "spring 2014 fashion", - "c": "1549" - }, - { - "SearchPhrase": "freeform photos", - "c": "1480" - } - ], - - "totals": - { - "SearchPhrase": "", - "c": "8873898" - }, - - "extremes": - { - "min": - { - "SearchPhrase": "", - "c": "1480" - }, - "max": - { - "SearchPhrase": "", - "c": "8267016" - } - }, - - "rows": 5, - - "rows_before_limit_at_least": 141137 -} -``` - -JSON совместим с JavaScript. Для этого, дополнительно экранируются некоторые символы: символ прямого слеша `/` экранируется в виде `\/`; альтернативные переводы строк `U+2028`, `U+2029`, на которых ломаются некоторые браузеры, экранируются в виде `\uXXXX`-последовательностей. Экранируются ASCII control characters: backspace, form feed, line feed, carriage return, horizontal tab в виде `\b`, `\f`, `\n`, `\r`, `\t` соответственно, а также остальные байты из диапазона 00-1F с помощью `\uXXXX`-последовательностей. Невалидные UTF-8 последовательности заменяются на replacement character � и, таким образом, выводимый текст будет состоять из валидных UTF-8 последовательностей. Числа типа UInt64 и Int64, для совместимости с JavaScript, по умолчанию выводятся в двойных кавычках, чтобы они выводились без кавычек можно установить конфигурационный параметр output_format_json_quote_64bit_integers равным 0. - -`rows` - общее количество выведенных строчек. - -`rows_before_limit_at_least` - не менее скольких строчек получилось бы, если бы не было LIMIT-а. Выводится только если запрос содержит LIMIT. -В случае, если запрос содержит GROUP BY, rows_before_limit_at_least - точное число строк, которое получилось бы, если бы не было LIMIT-а. - -`totals` - тотальные значения (при использовании WITH TOTALS). - -`extremes` - экстремальные значения (при настройке extremes, выставленной в 1). - -Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). -Смотрите также формат JSONEachRow. diff --git a/docs/ru/formats/jsoncompact.md b/docs/ru/formats/jsoncompact.md deleted file mode 100644 index efadc42d6e7..00000000000 --- a/docs/ru/formats/jsoncompact.md +++ /dev/null @@ -1,47 +0,0 @@ - - -# JSONCompact - -Отличается от JSON только тем, что строчки данных выводятся в массивах, а не в object-ах. - -Пример: - -```json -{ - "meta": - [ - { - "name": "SearchPhrase", - "type": "String" - }, - { - "name": "c", - "type": "UInt64" - } - ], - - "data": - [ - ["", "8267016"], - ["интерьер ванной комнаты", "2166"], - ["яндекс", "1655"], - ["весна 2014 мода", "1549"], - ["фриформ фото", "1480"] - ], - - "totals": ["","8873898"], - - "extremes": - { - "min": ["","1480"], - "max": ["","8267016"] - }, - - "rows": 5, - - "rows_before_limit_at_least": 141137 -} -``` - -Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). -Смотрите также формат `JSONEachRow`. diff --git a/docs/ru/formats/jsoneachrow.md b/docs/ru/formats/jsoneachrow.md deleted file mode 100644 index 8bf1797b2a3..00000000000 --- a/docs/ru/formats/jsoneachrow.md +++ /dev/null @@ -1,22 +0,0 @@ - - -# JSONEachRow - -Выводит данные в виде отдельных JSON объектов для каждой строки (newline delimited JSON). - -```json -{"SearchPhrase":"","count()":"8267016"} -{"SearchPhrase":"интерьер ванной комнаты","count()":"2166"} -{"SearchPhrase":"яндекс","count()":"1655"} -{"SearchPhrase":"весна 2014 мода","count()":"1549"} -{"SearchPhrase":"фриформ фото","count()":"1480"} -{"SearchPhrase":"анджелина джоли","count()":"1245"} -{"SearchPhrase":"омск","count()":"1112"} -{"SearchPhrase":"фото собак разных пород","count()":"1091"} -{"SearchPhrase":"дизайн штор","count()":"1064"} -{"SearchPhrase":"баку","count()":"1000"} -``` - -В отличие от формата JSON, нет замены невалидных UTF-8 последовательностей. В строках может выводиться произвольный набор байт. Это сделано для того, чтобы данные форматировались без потери информации. Экранирование значений осуществляется аналогично формату JSON. - -При парсинге, поддерживается расположение значений разных столбцов в произвольном порядке. Допустимо отсутствие некоторых значений - тогда они воспринимаются как равные значениям по умолчанию. При этом, в качестве значений по умолчанию используются нули, пустые строки и не поддерживаются сложные значения по умолчанию, которые могут быть заданы в таблице. Пропускаются пробельные символы между элементами. После объектов может быть расположена запятая, которая игнорируется. Объекты не обязательно должны быть разделены переводами строк. diff --git a/docs/ru/formats/native.md b/docs/ru/formats/native.md deleted file mode 100644 index 0b047301fbd..00000000000 --- a/docs/ru/formats/native.md +++ /dev/null @@ -1,7 +0,0 @@ - - -# Native - -Самый эффективный формат. Данные пишутся и читаются блоками в бинарном виде. Для каждого блока пишется количество строк, количество столбцов, имена и типы столбцов, а затем кусочки столбцов этого блока, один за другим. То есть, этот формат является "столбцовым" - не преобразует столбцы в строки. Именно этот формат используется в родном интерфейсе - при межсерверном взаимодействии, при использовании клиента командной строки, при работе клиентов, написанных на C++. - -Вы можете использовать этот формат для быстрой генерации дампов, которые могут быть прочитаны только СУБД ClickHouse. Вряд ли имеет смысл работать с этим форматом самостоятельно. diff --git a/docs/ru/formats/null.md b/docs/ru/formats/null.md deleted file mode 100644 index eba69cf73f6..00000000000 --- a/docs/ru/formats/null.md +++ /dev/null @@ -1,6 +0,0 @@ - - -# Null - -Ничего не выводит. При этом, запрос обрабатывается, а при использовании клиента командной строки, данные ещё и передаются на клиент. Используется для тестов, в том числе, тестов производительности. -Очевидно, формат подходит только для вывода, но не для парсинга. diff --git a/docs/ru/formats/pretty.md b/docs/ru/formats/pretty.md deleted file mode 100644 index 0f2434230f2..00000000000 --- a/docs/ru/formats/pretty.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# Pretty - -Выводит данные в виде Unicode-art табличек, также используя ANSI-escape последовательности для установки цветов в терминале. -Рисуется полная сетка таблицы и, таким образом, каждая строчка занимает две строки в терминале. -Каждый блок результата выводится в виде отдельной таблицы. Это нужно, чтобы можно было выводить блоки без буферизации результата (буферизация потребовалась бы, чтобы заранее вычислить видимую ширину всех значений.) -Для защиты от вываливания слишком большого количества данных в терминал, выводится только первые 10 000 строк. Если строк больше или равно 10 000, то будет написано "Showed first 10 000." -Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). - -Формат Pretty поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения, в отдельных табличках. Пример (показан для формата PrettyCompact): - -```sql -SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT PrettyCompact -``` - -```text -┌──EventDate─┬───────c─┐ -│ 2014-03-17 │ 1406958 │ -│ 2014-03-18 │ 1383658 │ -│ 2014-03-19 │ 1405797 │ -│ 2014-03-20 │ 1353623 │ -│ 2014-03-21 │ 1245779 │ -│ 2014-03-22 │ 1031592 │ -│ 2014-03-23 │ 1046491 │ -└────────────┴─────────┘ - -Totals: -┌──EventDate─┬───────c─┐ -│ 0000-00-00 │ 8873898 │ -└────────────┴─────────┘ - -Extremes: -┌──EventDate─┬───────c─┐ -│ 2014-03-17 │ 1031592 │ -│ 2014-03-23 │ 1406958 │ -└────────────┴─────────┘ -``` diff --git a/docs/ru/formats/prettycompact.md b/docs/ru/formats/prettycompact.md deleted file mode 100644 index 2e10422d7bc..00000000000 --- a/docs/ru/formats/prettycompact.md +++ /dev/null @@ -1,6 +0,0 @@ - - -# PrettyCompact - -Отличается от `Pretty` тем, что не рисуется сетка между строками - результат более компактный. -Этот формат используется по умолчанию в клиенте командной строки в интерактивном режиме. diff --git a/docs/ru/formats/prettycompactmonoblock.md b/docs/ru/formats/prettycompactmonoblock.md deleted file mode 100644 index 8e5ea89aed8..00000000000 --- a/docs/ru/formats/prettycompactmonoblock.md +++ /dev/null @@ -1,5 +0,0 @@ - - -# PrettyCompactMonoBlock - -Отличается от [PrettyCompact](prettycompact.md#prettycompact) тем, что строки (до 10 000 штук) буферизуются и затем выводятся в виде одной таблицы, а не по блокам. diff --git a/docs/ru/formats/prettynoescapes.md b/docs/ru/formats/prettynoescapes.md deleted file mode 100644 index e4320358438..00000000000 --- a/docs/ru/formats/prettynoescapes.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# PrettyNoEscapes - -Отличается от Pretty тем, что не используются ANSI-escape последовательности. Это нужно для отображения этого формата в браузере, а также при использовании утилиты командной строки watch. - -Пример: - -```bash -watch -n1 "clickhouse-client --query='SELECT * FROM system.events FORMAT PrettyCompactNoEscapes'" -``` - -Для отображения в браузере, вы можете использовать HTTP интерфейс. - -## PrettyCompactNoEscapes - -Аналогично. - -## PrettySpaceNoEscapes - -Аналогично. diff --git a/docs/ru/formats/prettyspace.md b/docs/ru/formats/prettyspace.md deleted file mode 100644 index 60c7bfbdd7e..00000000000 --- a/docs/ru/formats/prettyspace.md +++ /dev/null @@ -1,5 +0,0 @@ - - -# PrettySpace - -Отличается от [PrettyCompact](prettycompact.md#prettycompact) тем, что вместо сетки используется пустое пространство (пробелы). diff --git a/docs/ru/formats/rowbinary.md b/docs/ru/formats/rowbinary.md deleted file mode 100644 index d0d33c696c7..00000000000 --- a/docs/ru/formats/rowbinary.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# RowBinary - -Форматирует и парсит данные по строкам, в бинарном виде. Строки и значения уложены подряд, без разделителей. -Формат менее эффективен, чем формат Native, так как является строковым. - -Числа представлены в little endian формате фиксированной длины. Для примера, UInt64 занимает 8 байт. -DateTime представлены как UInt32, содержащий unix timestamp в качестве значения. -Date представлены как UInt16, содержащий количество дней, прошедших с 1970-01-01 в качестве значения. -String представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем байты строки. -FixedString представлены просто как последовательность байт. - -Array представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем элементы массива, подряд. diff --git a/docs/ru/formats/tabseparated.md b/docs/ru/formats/tabseparated.md deleted file mode 100644 index a38c418d10d..00000000000 --- a/docs/ru/formats/tabseparated.md +++ /dev/null @@ -1,60 +0,0 @@ - - -# TabSeparated - -В TabSeparated формате данные пишутся по строкам. Каждая строчка содержит значения, разделённые табами. После каждого значения идёт таб, кроме последнего значения в строке, после которого идёт перевод строки. Везде подразумеваются исключительно unix-переводы строк. Последняя строка также обязана содержать перевод строки на конце. Значения пишутся в текстовом виде, без обрамляющих кавычек, с экранированием служебных символов. - -Целые числа пишутся в десятичной форме. Числа могут содержать лишний символ "+" в начале (игнорируется при парсинге, а при форматировании не пишется). Неотрицательные числа не могут содержать знак отрицания. При чтении допустим парсинг пустой строки, как числа ноль, или (для знаковых типов) строки, состоящей из одного минуса, как числа ноль. Числа, не помещающиеся в соответствующий тип данных, могут парсится, как некоторое другое число, без сообщения об ошибке. - -Числа с плавающей запятой пишутся в десятичной форме. При этом, десятичный разделитель - точка. Поддерживается экспоненциальная запись, а также inf, +inf, -inf, nan. Запись числа с плавающей запятой может начинаться или заканчиваться на десятичную точку. -При форматировании возможна потеря точности чисел с плавающей запятой. -При парсинге, допустимо чтение не обязательно наиболее близкого к десятичной записи машинно-представимого числа. - -Даты выводятся в формате YYYY-MM-DD, парсятся в том же формате, но с любыми символами в качестве разделителей. -Даты-с-временем выводятся в формате YYYY-MM-DD hh:mm:ss, парсятся в том же формате, но с любыми символами в качестве разделителей. -Всё это происходит в системном часовом поясе на момент старта клиента (если клиент занимается форматированием данных) или сервера. Для дат-с-временем не указывается, действует ли daylight saving time. То есть, если в дампе есть времена во время перевода стрелок назад, то дамп не соответствует данным однозначно, и при парсинге будет выбрано какое-либо из двух времён. -При парсинге, некорректные даты и даты-с-временем могут парситься с естественным переполнением или как нулевые даты/даты-с-временем без сообщения об ошибке. - -В качестве исключения, поддерживается также парсинг даты-с-временем в формате unix timestamp, если он состоит ровно из 10 десятичных цифр. Результат не зависит от часового пояса. Различение форматов YYYY-MM-DD hh:mm:ss и NNNNNNNNNN делается автоматически. - -Строки выводятся с экранированием спец-символов с помощью обратного слеша. При выводе, используются следующие escape-последовательности: `\b`, `\f`, `\r`, `\n`, `\t`, `\0`, `\'`, `\\`. При парсинге, также поддерживаются последовательности `\a`, `\v`, а также `\xHH` (hex escape-последовательности) и любые последовательности вида `\c`, где `c` - любой символ - такие последовательности преобразуется в `c`. Таким образом, при чтении поддерживаются форматы, где перевод строки может быть записан как `\n` и как `\` и перевод строки. Например, строка `Hello world`, где между словами вместо пробела стоит перевод строки, может быть считана в любом из следующих вариантов: - -```text -Hello\nworld - -Hello\ -world -``` - -Второй вариант поддерживается, так как его использует MySQL при записи tab-separated дампа. - -Минимальный набор символов, которых вам необходимо экранировать при передаче в TabSeparated формате: таб, перевод строки (LF) и обратный слеш. - -Экранируется лишь небольшой набор символов. Вы можете легко наткнуться на строковое значение, которое испортит ваш терминал при выводе в него. - -Массивы форматируются в виде списка значений через запятую в квадратных скобках. Элементы массива - числа форматируются как обычно, а даты, даты-с-временем и строки - в одинарных кавычках с такими же правилами экранирования, как указано выше. - -Формат TabSeparated удобен для обработки данных произвольными программами и скриптами. Он используется по умолчанию в HTTP-интерфейсе, а также в batch-режиме клиента командной строки. Также формат позволяет переносить данные между разными СУБД. Например, вы можете получить дамп из MySQL и загрузить его в ClickHouse, или наоборот. - -Формат TabSeparated поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения. Основной результат, тотальные значения и экстремальные значения, отделяются друг от друга пустой строкой. Пример: - -```sql -SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT TabSeparated`` -``` - -```text -2014-03-17 1406958 -2014-03-18 1383658 -2014-03-19 1405797 -2014-03-20 1353623 -2014-03-21 1245779 -2014-03-22 1031592 -2014-03-23 1046491 - -0000-00-00 8873898 - -2014-03-17 1031592 -2014-03-23 1406958 -``` - -Этот формат также доступен под именем `TSV`. diff --git a/docs/ru/formats/tabseparatedraw.md b/docs/ru/formats/tabseparatedraw.md deleted file mode 100644 index a785e353b8b..00000000000 --- a/docs/ru/formats/tabseparatedraw.md +++ /dev/null @@ -1,8 +0,0 @@ - - -# TabSeparatedRaw - -Отличается от формата `TabSeparated` тем, что строки выводятся без экранирования. -Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). - -Этот формат также доступен под именем `TSVRaw`. diff --git a/docs/ru/formats/tabseparatedwithnames.md b/docs/ru/formats/tabseparatedwithnames.md deleted file mode 100644 index 51413e3b3d8..00000000000 --- a/docs/ru/formats/tabseparatedwithnames.md +++ /dev/null @@ -1,9 +0,0 @@ - - -# TabSeparatedWithNames - -Отличается от формата `TabSeparated` тем, что в первой строке пишутся имена столбцов. -При парсинге, первая строка полностью игнорируется: вы не можете использовать имена столбцов, чтобы указать их порядок расположения, или чтобы проверить их корректность. -(Поддержка обработки заголовка при парсинге может быть добавлена в будущем.) - -Этот формат также доступен под именем `TSVWithNames`. diff --git a/docs/ru/formats/tabseparatedwithnamesandtypes.md b/docs/ru/formats/tabseparatedwithnamesandtypes.md deleted file mode 100644 index 8a5ded88ffc..00000000000 --- a/docs/ru/formats/tabseparatedwithnamesandtypes.md +++ /dev/null @@ -1,8 +0,0 @@ - - -# TabSeparatedWithNamesAndTypes - -Отличается от формата `TabSeparated` тем, что в первой строке пишутся имена столбцов, а во второй - типы столбцов. -При парсинге, первая и вторая строка полностью игнорируется. - -Этот формат также доступен под именем `TSVWithNamesAndTypes`. diff --git a/docs/ru/formats/tskv.md b/docs/ru/formats/tskv.md deleted file mode 100644 index 50d95b928bc..00000000000 --- a/docs/ru/formats/tskv.md +++ /dev/null @@ -1,24 +0,0 @@ - - -# TSKV - -Похож на TabSeparated, но выводит значения в формате name=value. Имена экранируются так же, как строки в формате TabSeparated и, дополнительно, экранируется также символ =. - -```text -SearchPhrase= count()=8267016 -SearchPhrase=интерьер ванной комнаты count()=2166 -SearchPhrase=яндекс count()=1655 -SearchPhrase=весна 2014 мода count()=1549 -SearchPhrase=фриформ фото count()=1480 -SearchPhrase=анджелина джоли count()=1245 -SearchPhrase=омск count()=1112 -SearchPhrase=фото собак разных пород count()=1091 -SearchPhrase=дизайн штор count()=1064 -SearchPhrase=баку count()=1000 -``` - -При большом количестве маленьких столбцов, этот формат существенно неэффективен, и обычно нет причин его использовать. Он реализован, так как используется в некоторых отделах Яндекса. - -Поддерживается как вывод, так и парсинг данных в этом формате. При парсинге, поддерживается расположение значений разных столбцов в произвольном порядке. Допустимо отсутствие некоторых значений - тогда они воспринимаются как равные значениям по умолчанию. При этом, в качестве значений по умолчанию используются нули, пустые строки и не поддерживаются сложные значения по умолчанию, которые могут быть заданы в таблице. - -При парсинге, в качестве дополнительного поля, может присутствовать `tskv` без знака равенства и без значения. Это поле игнорируется. diff --git a/docs/ru/formats/values.md b/docs/ru/formats/values.md deleted file mode 100644 index a8037898a31..00000000000 --- a/docs/ru/formats/values.md +++ /dev/null @@ -1,9 +0,0 @@ - - -# Values - -Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату TabSeparated. При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). - -Минимальный набор символов, которых вам необходимо экранировать при передаче в Values формате: одинарная кавычка и обратный слеш. - -Именно этот формат используется в запросе `INSERT INTO t VALUES ...`, но вы также можете использовать его для форматирования результатов запросов. diff --git a/docs/ru/formats/vertical.md b/docs/ru/formats/vertical.md deleted file mode 100644 index 98da1a6686e..00000000000 --- a/docs/ru/formats/vertical.md +++ /dev/null @@ -1,6 +0,0 @@ - - -# Vertical - -Выводит каждое значение на отдельной строке, с указанием имени столбца. Формат удобно использовать для вывода одной-нескольких строк, если каждая строка состоит из большого количества столбцов. -Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). diff --git a/docs/ru/formats/verticalraw.md b/docs/ru/formats/verticalraw.md deleted file mode 100644 index 62a62e9cc9d..00000000000 --- a/docs/ru/formats/verticalraw.md +++ /dev/null @@ -1,28 +0,0 @@ - - -# VerticalRaw - -Отличается от формата `Vertical` тем, что строки выводятся без экранирования. -Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). - -Примеры: -``` -:) SHOW CREATE TABLE geonames FORMAT VerticalRaw; -Row 1: -────── -statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) - -:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; -Row 1: -────── -test: string with 'quotes' and with some special - characters -``` - -Для сравнения - формат Vertical: -``` -:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical; -Row 1: -────── -test: string with \'quotes\' and \t with some special \n characters -``` diff --git a/docs/ru/formats/xml.md b/docs/ru/formats/xml.md deleted file mode 100644 index d13524bf417..00000000000 --- a/docs/ru/formats/xml.md +++ /dev/null @@ -1,75 +0,0 @@ - - -# XML - -Формат XML подходит только для вывода данных, не для парсинга. Пример: - -```xml - - - - - - SearchPhrase - String - - - count() - UInt64 - - - - - - - 8267016 - - - интерьер ванной комнаты - 2166 - - - яндекс - 1655 - - - весна 2014 мода - 1549 - - - фриформ фото - 1480 - - - анджелина джоли - 1245 - - - омск - 1112 - - - фото собак разных пород - 1091 - - - дизайн штор - 1064 - - - баку - 1000 - - - 10 - 141137 - -``` - -Если имя столбца не имеет некоторый допустимый вид, то в качестве имени элемента используется просто field. В остальном, структура XML повторяет структуру в формате JSON. -Как и для формата JSON, невалидные UTF-8 последовательности заменяются на replacement character � и, таким образом, выводимый текст будет состоять из валидных UTF-8 последовательностей. - -В строковых значениях, экранируются символы `<` и `&` как `<` и `&`. - -Массивы выводятся как `HelloWorld...`, -а кортежи как `HelloWorld...`. diff --git a/docs/ru/interfaces/formats.md b/docs/ru/interfaces/formats.md new file mode 100644 index 00000000000..ab6f8591f4b --- /dev/null +++ b/docs/ru/interfaces/formats.md @@ -0,0 +1,563 @@ + + +# Форматы входных и выходных данных + +ClickHouse может принимать (`INSERT`) и отдавать (`SELECT`) данные в различных форматах. + +Поддерживаемые форматы и возможность использовать их в запросах `INSERT` и `SELECT` перечислены в таблице ниже. + +Формат | INSERT | SELECT +-------|--------|-------- +[TabSeparated](formats.md#tabseparated) | ✔ | ✔ | +[TabSeparatedRaw](formats.md#tabseparatedraw) | ✗ | ✔ | +[TabSeparatedWithNames](formats.md#tabseparatedwithnames) | ✔ | ✔ | +[TabSeparatedWithNamesAndTypes](formats.md#tabseparatedwithnamesandtypes) | ✔ | ✔ | +[CSV](formats.md#csv) | ✔ | ✔ | +[CSVWithNames](formats.md#csvwithnames) | ✔ | ✔ | +[Values](formats.md#values) | ✔ | ✔ | +[Vertical](formats.md#vertical) | ✗ | ✔ | +[VerticalRaw](formats.md#verticalraw) | ✗ | ✔ | +[JSON](formats.md#json) | ✗ | ✔ | +[JSONCompact](formats.md#jsoncompact) | ✗ | ✔ | +[JSONEachRow](formats.md#jsoneachrow) | ✔ | ✔ | +[TSKV](formats.md#tskv) | ✔ | ✔ | +[Pretty](formats.md#pretty) | ✗ | ✔ | +[PrettyCompact](formats.md#prettycompact) | ✗ | ✔ | +[PrettyCompactMonoBlock](formats.md#prettycompactmonoblock) | ✗ | ✔ | +[PrettyNoEscapes](formats.md#prettynoescapes) | ✗ | ✔ | +[PrettySpace](formats.md#prettyspace) | ✗ | ✔ | +[RowBinary](formats.md#rowbinary) | ✔ | ✔ | +[Native](formats.md#native) | ✔ | ✔ | +[Null](formats.md#null) | ✗ | ✔ | +[XML](formats.md#xml) | ✗ | ✔ | +[CapnProto](formats.md#capnproto) | ✔ | ✔ | + + + +## CapnProto + +Cap'n Proto - формат бинарных сообщений, похож на Protocol Buffers и Thrift, но не похож на JSON или MessagePack. + +Сообщения Cap'n Proto строго типизированы и не самоописывающиеся, т.е. нуждаются во внешнем описании схемы. Схема применяется "на лету" и кешируется для каждого запроса. + +```sql +SELECT SearchPhrase, count() AS c FROM test.hits + GROUP BY SearchPhrase FORMAT CapnProto SETTINGS schema = 'schema:Message' +``` + +Где `schema.capnp` выглядит следующим образом: + +``` +struct Message { + SearchPhrase @0 :Text; + c @1 :Uint64; +} +``` + + +Файлы со схемами находятся в файле, который находится в каталоге указанном в параметре [format_schema_path](../operations/server_settings/settings.md#server_settings-format_schema_path) конфигурации сервера. + +Десериализация эффективна и обычно не повышает нагрузку на систему. + + +## CSV + +Формат comma separated values ([RFC](https://tools.ietf.org/html/rfc4180)). + +При форматировании, строки выводятся в двойных кавычках. Двойная кавычка внутри строки выводится как две двойные кавычки подряд. Других правил экранирования нет. Даты и даты-с-временем выводятся в двойных кавычках. Числа выводятся без кавычек. Значения разделяются символом-разделителем*. Строки разделяются unix переводом строки (LF). Массивы сериализуются в CSV следующим образом: сначала массив сериализуется в строку, как в формате TabSeparated, а затем полученная строка выводится в CSV в двойных кавычках. Кортежи в формате CSV сериализуются, как отдельные столбцы (то есть, теряется их вложенность в кортеж). + +*По умолчанию — `,`. См. настройку [format_csv_delimiter](/docs/ru/operations/settings/settings/#format_csv_delimiter) для дополнительной информации. + +При парсинге, все значения могут парситься как в кавычках, так и без кавычек. Поддерживаются как двойные, так и одинарные кавычки. В том числе, строки могут быть расположены без кавычек - тогда они парсятся до символа-разделителя или перевода строки (CR или LF). В нарушение RFC, в случае парсинга строк не в кавычках, начальные и конечные пробелы и табы игнорируются. В качестве перевода строки, поддерживаются как Unix (LF), так и Windows (CR LF) и Mac OS Classic (LF CR) варианты. + +Формат CSV поддерживает вывод totals и extremes аналогично `TabSeparated`. + + +## CSVWithNames + +Выводит также заголовок, аналогично `TabSeparatedWithNames`. + + +## JSON + +Выводит данные в формате JSON. Кроме таблицы с данными, также выводятся имена и типы столбцов, и некоторая дополнительная информация - общее количество выведенных строк, а также количество строк, которое могло бы быть выведено, если бы не было LIMIT-а. Пример: + +```sql +SELECT SearchPhrase, count() AS c FROM test.hits GROUP BY SearchPhrase WITH TOTALS ORDER BY c DESC LIMIT 5 FORMAT JSON +``` + +```json +{ + "meta": + [ + { + "name": "SearchPhrase", + "type": "String" + }, + { + "name": "c", + "type": "UInt64" + } + ], + + "data": + [ + { + "SearchPhrase": "", + "c": "8267016" + }, + { + "SearchPhrase": "bathroom interior design", + "c": "2166" + }, + { + "SearchPhrase": "yandex", + "c": "1655" + }, + { + "SearchPhrase": "spring 2014 fashion", + "c": "1549" + }, + { + "SearchPhrase": "freeform photos", + "c": "1480" + } + ], + + "totals": + { + "SearchPhrase": "", + "c": "8873898" + }, + + "extremes": + { + "min": + { + "SearchPhrase": "", + "c": "1480" + }, + "max": + { + "SearchPhrase": "", + "c": "8267016" + } + }, + + "rows": 5, + + "rows_before_limit_at_least": 141137 +} +``` + +JSON совместим с JavaScript. Для этого, дополнительно экранируются некоторые символы: символ прямого слеша `/` экранируется в виде `\/`; альтернативные переводы строк `U+2028`, `U+2029`, на которых ломаются некоторые браузеры, экранируются в виде `\uXXXX`-последовательностей. Экранируются ASCII control characters: backspace, form feed, line feed, carriage return, horizontal tab в виде `\b`, `\f`, `\n`, `\r`, `\t` соответственно, а также остальные байты из диапазона 00-1F с помощью `\uXXXX`-последовательностей. Невалидные UTF-8 последовательности заменяются на replacement character � и, таким образом, выводимый текст будет состоять из валидных UTF-8 последовательностей. Числа типа UInt64 и Int64, для совместимости с JavaScript, по умолчанию выводятся в двойных кавычках, чтобы они выводились без кавычек можно установить конфигурационный параметр output_format_json_quote_64bit_integers равным 0. + +`rows` - общее количество выведенных строчек. + +`rows_before_limit_at_least` - не менее скольких строчек получилось бы, если бы не было LIMIT-а. Выводится только если запрос содержит LIMIT. +В случае, если запрос содержит GROUP BY, rows_before_limit_at_least - точное число строк, которое получилось бы, если бы не было LIMIT-а. + +`totals` - тотальные значения (при использовании WITH TOTALS). + +`extremes` - экстремальные значения (при настройке extremes, выставленной в 1). + +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). +Смотрите также формат JSONEachRow. + + +## JSONCompact + +Отличается от JSON только тем, что строчки данных выводятся в массивах, а не в object-ах. + +Пример: + +```json +{ + "meta": + [ + { + "name": "SearchPhrase", + "type": "String" + }, + { + "name": "c", + "type": "UInt64" + } + ], + + "data": + [ + ["", "8267016"], + ["интерьер ванной комнаты", "2166"], + ["яндекс", "1655"], + ["весна 2014 мода", "1549"], + ["фриформ фото", "1480"] + ], + + "totals": ["","8873898"], + + "extremes": + { + "min": ["","1480"], + "max": ["","8267016"] + }, + + "rows": 5, + + "rows_before_limit_at_least": 141137 +} +``` + +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). +Смотрите также формат `JSONEachRow`. + + +## JSONEachRow + +Выводит данные в виде отдельных JSON объектов для каждой строки (newline delimited JSON). + +```json +{"SearchPhrase":"","count()":"8267016"} +{"SearchPhrase":"интерьер ванной комнаты","count()":"2166"} +{"SearchPhrase":"яндекс","count()":"1655"} +{"SearchPhrase":"весна 2014 мода","count()":"1549"} +{"SearchPhrase":"фриформ фото","count()":"1480"} +{"SearchPhrase":"анджелина джоли","count()":"1245"} +{"SearchPhrase":"омск","count()":"1112"} +{"SearchPhrase":"фото собак разных пород","count()":"1091"} +{"SearchPhrase":"дизайн штор","count()":"1064"} +{"SearchPhrase":"баку","count()":"1000"} +``` + +В отличие от формата JSON, нет замены невалидных UTF-8 последовательностей. В строках может выводиться произвольный набор байт. Это сделано для того, чтобы данные форматировались без потери информации. Экранирование значений осуществляется аналогично формату JSON. + +При парсинге, поддерживается расположение значений разных столбцов в произвольном порядке. Допустимо отсутствие некоторых значений - тогда они воспринимаются как равные значениям по умолчанию. При этом, в качестве значений по умолчанию используются нули, пустые строки и не поддерживаются сложные значения по умолчанию, которые могут быть заданы в таблице. Пропускаются пробельные символы между элементами. После объектов может быть расположена запятая, которая игнорируется. Объекты не обязательно должны быть разделены переводами строк. + + +## Native + +Самый эффективный формат. Данные пишутся и читаются блоками в бинарном виде. Для каждого блока пишется количество строк, количество столбцов, имена и типы столбцов, а затем кусочки столбцов этого блока, один за другим. То есть, этот формат является "столбцовым" - не преобразует столбцы в строки. Именно этот формат используется в родном интерфейсе - при межсерверном взаимодействии, при использовании клиента командной строки, при работе клиентов, написанных на C++. + +Вы можете использовать этот формат для быстрой генерации дампов, которые могут быть прочитаны только СУБД ClickHouse. Вряд ли имеет смысл работать с этим форматом самостоятельно. + + +## Null + +Ничего не выводит. При этом, запрос обрабатывается, а при использовании клиента командной строки, данные ещё и передаются на клиент. Используется для тестов, в том числе, тестов производительности. +Очевидно, формат подходит только для вывода, но не для парсинга. + + +## Pretty + +Выводит данные в виде Unicode-art табличек, также используя ANSI-escape последовательности для установки цветов в терминале. +Рисуется полная сетка таблицы и, таким образом, каждая строчка занимает две строки в терминале. +Каждый блок результата выводится в виде отдельной таблицы. Это нужно, чтобы можно было выводить блоки без буферизации результата (буферизация потребовалась бы, чтобы заранее вычислить видимую ширину всех значений.) +Для защиты от вываливания слишком большого количества данных в терминал, выводится только первые 10 000 строк. Если строк больше или равно 10 000, то будет написано "Showed first 10 000." +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). + +Формат Pretty поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения, в отдельных табличках. Пример (показан для формата PrettyCompact): + +```sql +SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT PrettyCompact +``` + +```text +┌──EventDate─┬───────c─┐ +│ 2014-03-17 │ 1406958 │ +│ 2014-03-18 │ 1383658 │ +│ 2014-03-19 │ 1405797 │ +│ 2014-03-20 │ 1353623 │ +│ 2014-03-21 │ 1245779 │ +│ 2014-03-22 │ 1031592 │ +│ 2014-03-23 │ 1046491 │ +└────────────┴─────────┘ + +Totals: +┌──EventDate─┬───────c─┐ +│ 0000-00-00 │ 8873898 │ +└────────────┴─────────┘ + +Extremes: +┌──EventDate─┬───────c─┐ +│ 2014-03-17 │ 1031592 │ +│ 2014-03-23 │ 1406958 │ +└────────────┴─────────┘ +``` + + +## PrettyCompact + +Отличается от `Pretty` тем, что не рисуется сетка между строками - результат более компактный. +Этот формат используется по умолчанию в клиенте командной строки в интерактивном режиме. + + +## PrettyCompactMonoBlock + +Отличается от [PrettyCompact](formats.md#prettycompact) тем, что строки (до 10 000 штук) буферизуются и затем выводятся в виде одной таблицы, а не по блокам. + + +## PrettyNoEscapes + +Отличается от Pretty тем, что не используются ANSI-escape последовательности. Это нужно для отображения этого формата в браузере, а также при использовании утилиты командной строки watch. + +Пример: + +```bash +watch -n1 "clickhouse-client --query='SELECT * FROM system.events FORMAT PrettyCompactNoEscapes'" +``` + +Для отображения в браузере, вы можете использовать HTTP интерфейс. + +### PrettyCompactNoEscapes + +Аналогично. + +### PrettySpaceNoEscapes + +Аналогично. + + +## PrettySpace + +Отличается от [PrettyCompact](formats.md#prettycompact) тем, что вместо сетки используется пустое пространство (пробелы). + + +## RowBinary + +Форматирует и парсит данные по строкам, в бинарном виде. Строки и значения уложены подряд, без разделителей. +Формат менее эффективен, чем формат Native, так как является строковым. + +Числа представлены в little endian формате фиксированной длины. Для примера, UInt64 занимает 8 байт. +DateTime представлены как UInt32, содержащий unix timestamp в качестве значения. +Date представлены как UInt16, содержащий количество дней, прошедших с 1970-01-01 в качестве значения. +String представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем байты строки. +FixedString представлены просто как последовательность байт. + +Array представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем элементы массива, подряд. + + +## TabSeparated + +В TabSeparated формате данные пишутся по строкам. Каждая строчка содержит значения, разделённые табами. После каждого значения идёт таб, кроме последнего значения в строке, после которого идёт перевод строки. Везде подразумеваются исключительно unix-переводы строк. Последняя строка также обязана содержать перевод строки на конце. Значения пишутся в текстовом виде, без обрамляющих кавычек, с экранированием служебных символов. + +Целые числа пишутся в десятичной форме. Числа могут содержать лишний символ "+" в начале (игнорируется при парсинге, а при форматировании не пишется). Неотрицательные числа не могут содержать знак отрицания. При чтении допустим парсинг пустой строки, как числа ноль, или (для знаковых типов) строки, состоящей из одного минуса, как числа ноль. Числа, не помещающиеся в соответствующий тип данных, могут парсится, как некоторое другое число, без сообщения об ошибке. + +Числа с плавающей запятой пишутся в десятичной форме. При этом, десятичный разделитель - точка. Поддерживается экспоненциальная запись, а также inf, +inf, -inf, nan. Запись числа с плавающей запятой может начинаться или заканчиваться на десятичную точку. +При форматировании возможна потеря точности чисел с плавающей запятой. +При парсинге, допустимо чтение не обязательно наиболее близкого к десятичной записи машинно-представимого числа. + +Даты выводятся в формате YYYY-MM-DD, парсятся в том же формате, но с любыми символами в качестве разделителей. +Даты-с-временем выводятся в формате YYYY-MM-DD hh:mm:ss, парсятся в том же формате, но с любыми символами в качестве разделителей. +Всё это происходит в системном часовом поясе на момент старта клиента (если клиент занимается форматированием данных) или сервера. Для дат-с-временем не указывается, действует ли daylight saving time. То есть, если в дампе есть времена во время перевода стрелок назад, то дамп не соответствует данным однозначно, и при парсинге будет выбрано какое-либо из двух времён. +При парсинге, некорректные даты и даты-с-временем могут парситься с естественным переполнением или как нулевые даты/даты-с-временем без сообщения об ошибке. + +В качестве исключения, поддерживается также парсинг даты-с-временем в формате unix timestamp, если он состоит ровно из 10 десятичных цифр. Результат не зависит от часового пояса. Различение форматов YYYY-MM-DD hh:mm:ss и NNNNNNNNNN делается автоматически. + +Строки выводятся с экранированием спец-символов с помощью обратного слеша. При выводе, используются следующие escape-последовательности: `\b`, `\f`, `\r`, `\n`, `\t`, `\0`, `\'`, `\\`. При парсинге, также поддерживаются последовательности `\a`, `\v`, а также `\xHH` (hex escape-последовательности) и любые последовательности вида `\c`, где `c` - любой символ - такие последовательности преобразуется в `c`. Таким образом, при чтении поддерживаются форматы, где перевод строки может быть записан как `\n` и как `\` и перевод строки. Например, строка `Hello world`, где между словами вместо пробела стоит перевод строки, может быть считана в любом из следующих вариантов: + +```text +Hello\nworld + +Hello\ +world +``` + +Второй вариант поддерживается, так как его использует MySQL при записи tab-separated дампа. + +Минимальный набор символов, которых вам необходимо экранировать при передаче в TabSeparated формате: таб, перевод строки (LF) и обратный слеш. + +Экранируется лишь небольшой набор символов. Вы можете легко наткнуться на строковое значение, которое испортит ваш терминал при выводе в него. + +Массивы форматируются в виде списка значений через запятую в квадратных скобках. Элементы массива - числа форматируются как обычно, а даты, даты-с-временем и строки - в одинарных кавычках с такими же правилами экранирования, как указано выше. + +Формат TabSeparated удобен для обработки данных произвольными программами и скриптами. Он используется по умолчанию в HTTP-интерфейсе, а также в batch-режиме клиента командной строки. Также формат позволяет переносить данные между разными СУБД. Например, вы можете получить дамп из MySQL и загрузить его в ClickHouse, или наоборот. + +Формат TabSeparated поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения. Основной результат, тотальные значения и экстремальные значения, отделяются друг от друга пустой строкой. Пример: + +```sql +SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT TabSeparated`` +``` + +```text +2014-03-17 1406958 +2014-03-18 1383658 +2014-03-19 1405797 +2014-03-20 1353623 +2014-03-21 1245779 +2014-03-22 1031592 +2014-03-23 1046491 + +0000-00-00 8873898 + +2014-03-17 1031592 +2014-03-23 1406958 +``` + +Этот формат также доступен под именем `TSV`. + + +## TabSeparatedRaw + +Отличается от формата `TabSeparated` тем, что строки выводятся без экранирования. +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). + +Этот формат также доступен под именем `TSVRaw`. + + +## TabSeparatedWithNames + +Отличается от формата `TabSeparated` тем, что в первой строке пишутся имена столбцов. +При парсинге, первая строка полностью игнорируется: вы не можете использовать имена столбцов, чтобы указать их порядок расположения, или чтобы проверить их корректность. +(Поддержка обработки заголовка при парсинге может быть добавлена в будущем.) + +Этот формат также доступен под именем `TSVWithNames`. + + +## TabSeparatedWithNamesAndTypes + +Отличается от формата `TabSeparated` тем, что в первой строке пишутся имена столбцов, а во второй - типы столбцов. +При парсинге, первая и вторая строка полностью игнорируется. + +Этот формат также доступен под именем `TSVWithNamesAndTypes`. + + +## TSKV + +Похож на TabSeparated, но выводит значения в формате name=value. Имена экранируются так же, как строки в формате TabSeparated и, дополнительно, экранируется также символ =. + +```text +SearchPhrase= count()=8267016 +SearchPhrase=интерьер ванной комнаты count()=2166 +SearchPhrase=яндекс count()=1655 +SearchPhrase=весна 2014 мода count()=1549 +SearchPhrase=фриформ фото count()=1480 +SearchPhrase=анджелина джоли count()=1245 +SearchPhrase=омск count()=1112 +SearchPhrase=фото собак разных пород count()=1091 +SearchPhrase=дизайн штор count()=1064 +SearchPhrase=баку count()=1000 +``` + +При большом количестве маленьких столбцов, этот формат существенно неэффективен, и обычно нет причин его использовать. Он реализован, так как используется в некоторых отделах Яндекса. + +Поддерживается как вывод, так и парсинг данных в этом формате. При парсинге, поддерживается расположение значений разных столбцов в произвольном порядке. Допустимо отсутствие некоторых значений - тогда они воспринимаются как равные значениям по умолчанию. При этом, в качестве значений по умолчанию используются нули, пустые строки и не поддерживаются сложные значения по умолчанию, которые могут быть заданы в таблице. + +При парсинге, в качестве дополнительного поля, может присутствовать `tskv` без знака равенства и без значения. Это поле игнорируется. + + +## Values + +Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату TabSeparated. При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). + +Минимальный набор символов, которых вам необходимо экранировать при передаче в Values формате: одинарная кавычка и обратный слеш. + +Именно этот формат используется в запросе `INSERT INTO t VALUES ...`, но вы также можете использовать его для форматирования результатов запросов. + + +## Vertical + +Выводит каждое значение на отдельной строке, с указанием имени столбца. Формат удобно использовать для вывода одной-нескольких строк, если каждая строка состоит из большого количества столбцов. +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). + + +## VerticalRaw + +Отличается от формата `Vertical` тем, что строки выводятся без экранирования. +Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу). + +Примеры: +``` +:) SHOW CREATE TABLE geonames FORMAT VerticalRaw; +Row 1: +────── +statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192) + +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw; +Row 1: +────── +test: string with 'quotes' and with some special + characters +``` + +Для сравнения - формат Vertical: +``` +:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical; +Row 1: +────── +test: string with \'quotes\' and \t with some special \n characters +``` + + +## XML + +Формат XML подходит только для вывода данных, не для парсинга. Пример: + +```xml + + + + + + SearchPhrase + String + + + count() + UInt64 + + + + + + + 8267016 + + + интерьер ванной комнаты + 2166 + + + яндекс + 1655 + + + весна 2014 мода + 1549 + + + фриформ фото + 1480 + + + анджелина джоли + 1245 + + + омск + 1112 + + + фото собак разных пород + 1091 + + + дизайн штор + 1064 + + + баку + 1000 + + + 10 + 141137 + +``` + +Если имя столбца не имеет некоторый допустимый вид, то в качестве имени элемента используется просто field. В остальном, структура XML повторяет структуру в формате JSON. +Как и для формата JSON, невалидные UTF-8 последовательности заменяются на replacement character � и, таким образом, выводимый текст будет состоять из валидных UTF-8 последовательностей. + +В строковых значениях, экранируются символы `<` и `&` как `<` и `&`. + +Массивы выводятся как `HelloWorld...`, +а кортежи как `HelloWorld...`. diff --git a/docs/ru/operations/server_settings/settings.md b/docs/ru/operations/server_settings/settings.md index bc1458014ec..2992b8d4c67 100644 --- a/docs/ru/operations/server_settings/settings.md +++ b/docs/ru/operations/server_settings/settings.md @@ -130,7 +130,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat ## format_schema_path -Путь к каталогу со схемами для входных данных. Например со схемами для формата [CapnProto](../../formats/capnproto.md#format_capnproto). +Путь к каталогу со схемами для входных данных. Например со схемами для формата [CapnProto](../../interfaces/formats.md#format_capnproto). **Пример** diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index cda54356f49..8bf39a8aa71 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -619,7 +619,7 @@ INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), . Если [strict_insert_defaults=1](../operations/settings/settings.md#settings-strict_insert_defaults), то столбцы, для которых не определены `DEFAULT`, необходимо перечислить в запросе. -В INSERT можно передавать данные любого [формата](../formats/index.md#formats), который поддерживает ClickHouse. Для этого формат необходимо указать в запросе в явном виде: +В INSERT можно передавать данные любого [формата](../interfaces/formats.md#formats), который поддерживает ClickHouse. Для этого формат необходимо указать в запросе в явном виде: ```sql INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set diff --git a/docs/ru/table_engines/file.md b/docs/ru/table_engines/file.md index 2b4e934bfcc..59903a7ae5b 100644 --- a/docs/ru/table_engines/file.md +++ b/docs/ru/table_engines/file.md @@ -16,7 +16,7 @@ File(Format) ``` -`Format` должен быть таким, который ClickHouse может использовать и в запросах `INSERT` и в запросах `SELECT`. Полный список поддерживаемых форматов смотрите в разделе [Форматы](../formats/index.md#formats). +`Format` должен быть таким, который ClickHouse может использовать и в запросах `INSERT` и в запросах `SELECT`. Полный список поддерживаемых форматов смотрите в разделе [Форматы](../interfaces/formats.md#formats). Сервер ClickHouse не позволяет указать путь к файлу, с которым будет работать `File`. Используется путь к хранилищу, определенный параметром [path](../operations/server_settings/settings.md#server_settings-path) в конфигурации сервера. diff --git a/docs/ru/table_functions/file.md b/docs/ru/table_functions/file.md index 0c009133dc0..73b4edb8be3 100644 --- a/docs/ru/table_functions/file.md +++ b/docs/ru/table_functions/file.md @@ -6,7 +6,7 @@ path - относительный путь до файла от [user_files_path](../operations/server_settings/settings.md#user_files_path). -format - [формат](../formats/index.md#formats) файла. +format - [формат](../interfaces/formats.md#formats) файла. structure - структура таблицы в форме 'UserID UInt64, URL String'. Определяет имена и типы столбцов. From d7c5c2495e408fb881e4cc6f5d0f1bf2b58e7d0f Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Mon, 16 Jul 2018 19:19:13 +0300 Subject: [PATCH 011/425] Adapt table with formats to English docs too --- docs/en/interfaces/formats.md | 30 +++++++++++++++++++++++++++++- docs/mkdocs_en.yml | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/en/interfaces/formats.md b/docs/en/interfaces/formats.md index 5284aa0665e..7e45beb3e2c 100644 --- a/docs/en/interfaces/formats.md +++ b/docs/en/interfaces/formats.md @@ -1,9 +1,37 @@ -# Formats +# Input and output formats The format determines how data is returned to you after SELECTs (how it is written and formatted by the server), and how it is accepted for INSERTs (how it is read and parsed by the server). +See the table below for the list of supported formats for either kinds of queries. + +Format | INSERT | SELECT +-------|--------|-------- +[TabSeparated](formats.md#tabseparated) | ✔ | ✔ | +[TabSeparatedRaw](formats.md#tabseparatedraw) | ✗ | ✔ | +[TabSeparatedWithNames](formats.md#tabseparatedwithnames) | ✔ | ✔ | +[TabSeparatedWithNamesAndTypes](formats.md#tabseparatedwithnamesandtypes) | ✔ | ✔ | +[CSV](formats.md#csv) | ✔ | ✔ | +[CSVWithNames](formats.md#csvwithnames) | ✔ | ✔ | +[Values](formats.md#values) | ✔ | ✔ | +[Vertical](formats.md#vertical) | ✗ | ✔ | +[VerticalRaw](formats.md#verticalraw) | ✗ | ✔ | +[JSON](formats.md#json) | ✗ | ✔ | +[JSONCompact](formats.md#jsoncompact) | ✗ | ✔ | +[JSONEachRow](formats.md#jsoneachrow) | ✔ | ✔ | +[TSKV](formats.md#tskv) | ✔ | ✔ | +[Pretty](formats.md#pretty) | ✗ | ✔ | +[PrettyCompact](formats.md#prettycompact) | ✗ | ✔ | +[PrettyCompactMonoBlock](formats.md#prettycompactmonoblock) | ✗ | ✔ | +[PrettyNoEscapes](formats.md#prettynoescapes) | ✗ | ✔ | +[PrettySpace](formats.md#prettyspace) | ✗ | ✔ | +[RowBinary](formats.md#rowbinary) | ✔ | ✔ | +[Native](formats.md#native) | ✔ | ✔ | +[Null](formats.md#null) | ✗ | ✔ | +[XML](formats.md#xml) | ✗ | ✔ | +[CapnProto](formats.md#capnproto) | ✔ | ✔ | + ## CapnProto diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index a96fbe27409..2194a9c540c 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -27,7 +27,7 @@ pages: - 'Native interface (TCP)': 'interfaces/tcp.md' - 'Libraries from third-party developers': 'interfaces/third-party_client_libraries.md' - 'Visual interfaces from third-party developers': 'interfaces/third-party_gui.md' - - 'Formats': 'interfaces/formats.md' + - 'Input and output formats': 'interfaces/formats.md' - 'Query language': # - 'Query language': 'query_language/index.md' From 3a6b95870cbcb043937bb9168dedadd3b1c97dbc Mon Sep 17 00:00:00 2001 From: BayoNet Date: Tue, 17 Jul 2018 08:48:14 +0300 Subject: [PATCH 012/425] NULL in requests. --- docs/mkdocs_ru.yml | 1 + docs/ru/operations/settings/settings.md | 14 +- docs/ru/operators/index.md | 4 + docs/ru/query_language/queries.md | 202 +++++++++++++++++++++--- docs/ru/query_language/syntax.md | 2 + 5 files changed, 197 insertions(+), 26 deletions(-) diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 76e7c9dbc48..2530d85d04c 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -14,6 +14,7 @@ extra_css: markdown_extensions: - codehilite + - attr_list theme: name: null diff --git a/docs/ru/operations/settings/settings.md b/docs/ru/operations/settings/settings.md index 69fd8ab3978..3a547f687e0 100644 --- a/docs/ru/operations/settings/settings.md +++ b/docs/ru/operations/settings/settings.md @@ -10,9 +10,9 @@ ClickHouse применяет настройку в том случае, ког Условия применения: -- Только подзапросы для IN, JOIN. -- Только если в секции FROM используется распределённая таблица. -- Не используется в случае табличной функции [remote](../../table_functions/remote.md#table_functions-remote). +- Только подзапросы для IN, JOIN. +- Только если в секции FROM используется распределённая таблица. +- Не используется в случае табличной функции [remote](../../table_functions/remote.md#table_functions-remote). Возможные значения: @@ -341,3 +341,11 @@ ClickHouse применяет настройку в том случае, ког ## format_csv_delimiter Символ, интерпретируемый как разделитель в данных формата CSV. По умолчанию — `,`. + + + +## join_use_nulls {: #settings-join_use_nulls} + +Влияет на поведение [JOIN](../../query_language/queries.md#query_language-join). + +При `join_use_nulls=1` `JOIN` ведёт себя как в стандартном SQL, т.е. если при слиянии возникают пустые ячейки, то тип соответствующего поля преобразуется к [Nullable](../../data_types/nullable.md#data_type-nullable), а пустые ячейки заполняются значениями [NULL](../../query_language/syntax.md#null-literal). diff --git a/docs/ru/operators/index.md b/docs/ru/operators/index.md index 45fcb97f84d..c3b0a857a79 100644 --- a/docs/ru/operators/index.md +++ b/docs/ru/operators/index.md @@ -124,6 +124,8 @@ END ClickHouse поддерживает операторы `IS NULL` и `IS NOT NULL`. + + ### IS NULL - Для значений типа [Nullable](../data_types/nullable.md#data_type-nullable) оператор `IS NULL` возвращает: @@ -145,6 +147,8 @@ WHERE isNull(y) 1 rows in set. Elapsed: 0.002 sec. ``` + + ### IS NOT NULL - Для значений типа [Nullable](../data_types/nullable.md#data_type-nullable) оператор `IS NOT NULL` возвращает: diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md index a910636bb42..56147a7e49e 100644 --- a/docs/ru/query_language/queries.md +++ b/docs/ru/query_language/queries.md @@ -1003,6 +1003,9 @@ ARRAY JOIN nest AS n, arrayEnumerate(`nest.x`) AS num Соответствующее преобразование может выполняться как до секции WHERE/PREWHERE (если его результат нужен в этой секции), так и после выполнения WHERE/PREWHERE (чтобы уменьшить объём вычислений). + + + ### Секция JOIN Обычный JOIN, не имеет отношения к ARRAY JOIN, который описан выше. @@ -1099,29 +1102,69 @@ LIMIT 10 Если JOIN необходим для соединения с таблицами измерений (dimension tables - сравнительно небольшие таблицы, которые содержат свойства измерений - например, имена для рекламных кампаний), то использование JOIN может быть не очень удобным из-за громоздкости синтаксиса, а также из-за того, что правая таблица читается заново при каждом запросе. Специально для таких случаев существует функциональность "Внешние словари", которую следует использовать вместо JOIN. Подробнее смотрите раздел "Внешние словари". +#### Обработка NULL + +На поведение JOIN влияет настройка [join_use_nulls](../operations/settings/settings.md#settings-join_use_nulls). При `join_use_nulls=1` `JOIN` работает как в стандартном SQL. + +Если ключами JOIN выступают поля типа [Nullable](../data_types/nullable.md#data_types-nullable), то строки, где хотя бы один из ключей имеет значение [NULL](syntax.md#null-literal), не соединяются. + + + + ### Секция WHERE -Секция WHERE, если есть, должна содержать выражение, имеющее тип UInt8. Обычно это какое-либо выражение с операторами сравнения и логическими операторами. -Это выражение будет использовано для фильтрации данных перед всеми остальными преобразованиями. +Позволяет задать выражение, которое ClickHouse использует для фильтрации данных перед всеми другими действиями в запросе кроме выражений, содержащихся в секции [PREWHERE](#query_language-queries-prewhere). Обычно, это выражение с логическими операторами. -Выражение анализируется на возможность использования индексов, если индексы поддерживаются движком таблицы. +Результат выражения должен иметь тип `UInt8`. + +ClickHouse использует в выражении индексы, если это позволяет [движок таблицы](../table_engines/index.md#table_engines). + +Если в секции необходимо проверить [NULL](syntax.md#null-literal), то используйте операторы [IS NULL](../operators/index.md#operator-is-null) и [IS NOT NULL](../operators/index.md#operator-is-not-null), а также соответствующие функции `isNull` и `isNotNull`. В противном случае выражение будет считаться всегда не выполненным. + +Пример проверки на `NULL`: + +```bash +:) SELECT * FROM t_null WHERE y=NULL + +SELECT * +FROM t_null +WHERE y = NULL + +Ok. + +0 rows in set. Elapsed: 0.002 sec. + +:) SELECT * FROM t_null WHERE y IS NULL + +SELECT * +FROM t_null +WHERE isNull(y) + +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +└───┴──────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + + ### Секция PREWHERE -Имеет такой же смысл, как и секция WHERE. Отличие состоит в том, какие данные читаются из таблицы. -При использовании PREWHERE, из таблицы сначала читаются только столбцы, необходимые для выполнения PREWHERE. Затем читаются остальные столбцы, нужные для выполнения запроса, но из них только те блоки, в которых выражение в PREWHERE истинное. +Имеет такой же смысл, как и секция [WHERE](#query_language-queries-where). Отличие состоит в том, какие данные читаются из таблицы. +При использовании `PREWHERE`, из таблицы сначала читаются только столбцы, необходимые для выполнения `PREWHERE`. Затем читаются остальные столбцы, нужные для выполнения запроса, но из них только те блоки, в которых выражение в `PREWHERE` истинное. -PREWHERE имеет смысл использовать, если есть условия фильтрации, не подходящие под индексы, которые использует меньшинство столбцов из тех, что есть в запросе, но достаточно сильно фильтрует данные. Таким образом, сокращается количество читаемых данных. +`PREWHERE` имеет смысл использовать, если есть условия фильтрации, не подходящие под индексы, которые использует меньшинство столбцов из тех, что есть в запросе, но достаточно сильно фильтрует данные. Таким образом, сокращается количество читаемых данных. -Например, полезно писать PREWHERE для запросов, которые вынимают много столбцов, но в которых фильтрация производится лишь по нескольким столбцам. +Например, полезно писать `PREWHERE` для запросов, которые вынимают много столбцов, но в которых фильтрация производится лишь по нескольким столбцам. -PREWHERE поддерживается только таблицами семейства `*MergeTree`. +`PREWHERE` поддерживается только таблицами семейства `*MergeTree`. -В запросе могут быть одновременно указаны секции PREWHERE и WHERE. В этом случае, PREWHERE идёт перед WHERE. +В запросе могут быть одновременно указаны секции `PREWHERE` и `WHERE`. В этом случае, `PREWHERE` идёт перед `WHERE`. -Следует иметь ввиду, что указывать в PREWHERE только столбцы, по которым существует индекс, имеет мало смысла, так как при использовании индекса и так читаются лишь блоки данных, соответствующие индексу. +Следует иметь ввиду, что указывать в `PREWHERE` только столбцы, по которым существует индекс, имеет мало смысла, так как при использовании индекса и так читаются лишь блоки данных, соответствующие индексу. -Если настройка optimize_move_to_prewhere выставлена в 1, то при отсутствии PREWHERE, система будет автоматически переносить части выражений из WHERE в PREWHERE согласно некоторой эвристике. +Если настройка `optimize_move_to_prewhere` выставлена в `1`, то при отсутствии `PREWHERE`, система будет автоматически переносить части выражений из `WHERE` в `PREWHERE` согласно некоторой эвристике. ### Секция GROUP BY @@ -1163,6 +1206,38 @@ GROUP BY вычисляет для каждого встретившегося Не поддерживается указание констант в качестве аргументов агрегатных функций. Пример: sum(1). Вместо этого, вы можете избавиться от констант. Пример: `count()`. +#### Обработка NULL + +При группировке, ClickHouse рассматривает [NULL](syntax.md#null-literal) как значение, причём `NULL=NULL`. + +Рассмотрим, что это значит на примере. + +Пусть есть таблица: + +``` +┌─x─┬────y─┐ +│ 1 │ 2 │ +│ 2 │ ᴺᵁᴸᴸ │ +│ 3 │ 2 │ +│ 3 │ 3 │ +│ 3 │ ᴺᵁᴸᴸ │ +└───┴──────┘ +``` + +В результате запроса `SELECT sum(x),y FROM t_null_big GROUP BY y` мы получим: + +``` +┌─sum(x)─┬────y─┐ +│ 4 │ 2 │ +│ 3 │ 3 │ +│ 5 │ ᴺᵁᴸᴸ │ +└────────┴──────┘ +``` + +Видно, что `GROUP BY` для `У = NULL` просуммировал `x`, как будто `NULL` — это значение. + +Если в `GROUP BY` передать несколько ключей, то в результате мы получим все комбинации выборки, как если бы `NULL` был конкретным значением. + #### Модификатор WITH TOTALS Если указан модификатор WITH TOTALS, то будет посчитана ещё одна строчка, в которой в столбцах-ключах будут содержаться значения по умолчанию (нули, пустые строки), а в столбцах агрегатных функций - значения, посчитанные по всем строкам ("тотальные" значения). @@ -1208,7 +1283,7 @@ GROUP BY вычисляет для каждого встретившегося ### Секция LIMIT N BY -LIMIT N BY COLUMNS выбирает топ N строк для каждой группы COLUMNS. LIMIT N BY не связан с LIMIT и они могут использоваться в одном запросе. Ключ для LIMIT N BY может содержать произвольное число колонок или выражений. +`LIMIT N BY COLUMNS` выбирает топ `N` строк для каждой группы `COLUMNS`. `LIMIT N BY` не связан с `LIMIT` и они могут использоваться в одном запросе. Ключ для `LIMIT N BY` может содержать произвольное число колонок или выражений. Пример: @@ -1227,6 +1302,8 @@ LIMIT 100 Запрос выберет топ 5 рефереров для каждой пары `domain, device_type`, но не более 100 строк (`LIMIT n BY + LIMIT`). +`LIMIT n BY` работает с [NULL](syntax.md#null-literal) как если бы это было конкретное значение. Т.е. в результате запроса пользователь получит все комбинации полей, указанных в `BY`. + ### Секция HAVING Позволяет отфильтровать результат, полученный после GROUP BY, аналогично секции WHERE. @@ -1246,7 +1323,47 @@ WHERE и HAVING отличаются тем, что WHERE выполняется Строки, для которых список выражений, по которым производится сортировка, принимает одинаковые значения, выводятся в произвольном порядке, который может быть также недетерминированным (каждый раз разным). Если секция ORDER BY отсутствует, то, аналогично, порядок, в котором идут строки, не определён, и может быть недетерминированным. -При сортировке чисел с плавающей запятой, NaN-ы идут отдельно от остальных значений. Вне зависимости от порядка сортировки, NaN-ы помещаются в конец. То есть, при сортировке по возрастанию, они как будто больше всех чисел, а при сортировке по убыванию - как будто меньше всех. +Порядок сортировки `NaN` и `NULL`: + +- С модификатором `NULLS FIRST` — Сначала `NULL`, затем `NaN`, затем остальные значения. +- С модификатором `NULLS LAST` — Сначала значения, затем `NaN`, затем `NULL`. +- Без модификаторов `NULLS FIRST` или `NULLS LAST` как с модификатором `NULLS LAST`. + +Пример: + +Для таблицы + +``` +┌─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`, получим: + +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +│ 7 │ ᴺᵁᴸᴸ │ +│ 1 │ nan │ +│ 6 │ nan │ +│ 2 │ 2 │ +│ 2 │ 2 │ +│ 3 │ 4 │ +│ 5 │ 6 │ +│ 6 │ 7 │ +│ 8 │ 9 │ +└───┴──────┘ +``` Если кроме ORDER BY указан также не слишком большой LIMIT, то расходуется меньше оперативки. Иначе расходуется количество памяти, пропорциональное количеству данных для сортировки. При распределённой обработке запроса, если отсутствует GROUP BY, сортировка частично делается на удалённых серверах, а на сервере-инициаторе запроса производится слияние результатов. Таким образом, при распределённой сортировке, может сортироваться объём данных, превышающий размер памяти на одном сервере. @@ -1265,14 +1382,16 @@ WHERE и HAVING отличаются тем, что WHERE выполняется ### Секция DISTINCT -Если указано DISTINCT, то из всех множеств полностью совпадающих строк результата, будет оставляться только одна строка. -Результат выполнения будет таким же, как если указано GROUP BY по всем указанным полям в SELECT-е и не указаны агрегатные функции. Но имеется несколько отличий от GROUP BY: +Если указано `DISTINCT`, то из всех множеств полностью совпадающих строк результата, будет оставляться только одна строка. +Результат выполнения будет таким же, как если указано `GROUP BY` по всем указанным полям в `SELECT` и не указаны агрегатные функции. Но имеется несколько отличий от `GROUP BY`: -- DISTINCT может применяться совместно с GROUP BY; -- при отсутствии ORDER BY и наличии LIMIT, запрос прекратит выполнение сразу после того, как будет прочитано необходимое количество различных строк - в этом случае использование DISTINCT существенно более оптимально; +- `DISTINCT` может применяться совместно с `GROUP BY`; +- при отсутствии `ORDER BY` и наличии `LIMIT`, запрос прекратит выполнение сразу после того, как будет прочитано необходимое количество различных строк - в этом случае использование DISTINCT существенно более оптимально; - блоки данных будут выдаваться по мере их обработки, не дожидаясь выполнения всего запроса. -DISTINCT не поддерживается, если в SELECT-е присутствует хотя бы один столбец типа массив. +`DISTINCT` не поддерживается, если в `SELECT` присутствует хотя бы один столбец типа массив. + +`DISTINCT` работает с [NULL](syntax.md#null-literal) как если бы `NULL` был конкретным значением, причём `NULL=NULL`. Т.е. в результате `DISTINCT` разные комбинации с `NULL` встретятся только по одному разу. ### Секция LIMIT @@ -1283,9 +1402,11 @@ n и m должны быть неотрицательными целыми чи При отсутствии секции ORDER BY, однозначно сортирующей результат, результат может быть произвольным и может являться недетерминированным. +`DISTINCT` работает с [NULL](syntax.md#null-literal) как если бы `NULL` был конкретным значением, причём `NULL=NULL`. Т.е. в результате `DISTINCT` разные комбинации с `NULL` встретятся только по одному разу. + ### Секция UNION ALL -Произвольное количество запросов может быть объединено с помощью UNION ALL. Пример: +Произвольное количество запросов может быть объединено с помощью `UNION ALL`. Пример: ```sql SELECT CounterID, 1 AS table, toInt64(count()) AS c @@ -1300,13 +1421,13 @@ SELECT CounterID, 2 AS table, sum(Sign) AS c HAVING c > 0 ``` -Поддерживается только UNION ALL. Обычный UNION (UNION DISTINCT) не поддерживается. Если вам нужен UNION DISTINCT, то вы можете написать SELECT DISTINCT из подзапроса, содержащего UNION ALL. +Поддерживается только `UNION ALL`. Обычный `UNION` (`UNION DISTINCT`) не поддерживается. Если вам нужен `UNION DISTINCT`, то вы можете написать `SELECT DISTINCT` из подзапроса, содержащего `UNION ALL`. -Запросы - части UNION ALL могут выполняться параллельно, и их результаты могут возвращаться вперемешку. +Запросы - части `UNION ALL` могут выполняться параллельно, и их результаты могут возвращаться вперемешку. -Структура результатов (количество и типы столбцов) у запросов должна совпадать. Но имена столбцов могут отличаться. В этом случае, имена столбцов для общего результата будут взяты из первого запроса. +Структура результатов (количество и типы столбцов) у запросов должна совпадать. Но имена столбцов могут отличаться. В этом случае, имена столбцов для общего результата будут взяты из первого запроса. При объединении выполняется приведение типов. Например, если в двух объединяемых запросах одно и тоже поле имеет типы не-`Nullable` и `Nullable` от совместимого типа, то в результате `UNION ALL` получим поле типа `Nullable`. -Запросы - части UNION ALL нельзя заключить в скобки. ORDER BY и LIMIT применяются к отдельным запросам, а не к общему результату. Если вам нужно применить какое-либо преобразование к общему результату, то вы можете разместить все запросы с UNION ALL в подзапросе в секции FROM. +Запросы - части `UNION ALL` нельзя заключить в скобки. `ORDER BY` и `LIMIT` применяются к отдельным запросам, а не к общему результату. Если вам нужно применить какое-либо преобразование к общему результату, то вы можете разместить все запросы с `UNION ALL` в подзапросе в секции `FROM`. ### Секция INTO OUTFILE @@ -1344,6 +1465,7 @@ SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ... В качестве правой части оператора может быть множество константных выражений, множество кортежей с константными выражениями (показано в примерах выше), а также имя таблицы или подзапрос SELECT в скобках. + Если в качестве правой части оператора указано имя таблицы (например, `UserID IN users`), то это эквивалентно подзапросу `UserID IN (SELECT * FROM users)`. Это используется при работе с внешними данными, отправляемым вместе с запросом. Например, вместе с запросом может быть отправлено множество идентификаторов посетителей, загруженное во временную таблицу users, по которому следует выполнить фильтрацию. Если качестве правой части оператора, указано имя таблицы, имеющий движок Set (подготовленное множество, постоянно находящееся в оперативке), то множество не будет создаваться заново при каждом запросе. @@ -1389,6 +1511,40 @@ ORDER BY EventDate ASC за каждый день после 17 марта считаем долю хитов, сделанных посетителями, которые заходили на сайт 17 марта. Подзапрос в секции IN на одном сервере всегда выполняется только один раз. Зависимых подзапросов не существует. + +#### Обработка NULL + +При обработке запроса оператор IN будет считать, что результат операции с [NULL](syntax.md#null-literal) всегда равен `0`, независимо от того, находится `NULL` в правой или левой части оператора. Значения `NULL` не входят ни в какое множество, не соответствуют друг другу и не могут сравниваться. + +Рассмотрим для примера таблицу `t_null`: + +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +│ 2 │ 3 │ +└───┴──────┘ +``` + +При выполнении запроса `SELECT x FROM t_null WHERE y IN (NULL,3)` получим следующий результат: + +``` +┌─x─┐ +│ 2 │ +└───┘ +``` + +Видно, что строка, в которой `y = NULL`, выброшена из результатов запроса. Это произошло потому, что ClickHouse не может решить входит ли `NULL` в множество `(NULL,3)`, возвращает результат операции `0`, а `SELECT` выбрасывает эту строку из финальной выдачи. + +``` +SELECT y IN (NULL, 3) +FROM t_null + +┌─in(y, tuple(NULL, 3))─┐ +│ 0 │ +│ 1 │ +└───────────────────────┘ +``` + #### Распределённые подзапросы diff --git a/docs/ru/query_language/syntax.md b/docs/ru/query_language/syntax.md index 9c67dc7fd46..bb51b84be07 100644 --- a/docs/ru/query_language/syntax.md +++ b/docs/ru/query_language/syntax.md @@ -79,6 +79,8 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') При обработке `NULL` есть множество особенностей. Например, если хотя бы один из аргументов операции сравнения — `NULL`, то результатом такой операции тоже будет `NULL`. Этим же свойством обладают операции умножения, сложения и пр. Подробнее читайте в документации на каждую операцию. +В запросах можно проверить `NULL` с помощью операторов [IS NULL](../operators/index.md#operator-is-null) и [IS NOT NULL](../operators/index.md#operator-is-not-null), а также соответствующих функций `isNull` и `isNotNull`. + ## Функции Функции записываются как идентификатор со списком аргументов (возможно, пустым) в скобках. В отличие от стандартного SQL, даже в случае пустого списка аргументов, скобки обязательны. Пример: `now()`. From 09a4f79db691fa89c28db6055df88e305d8208df Mon Sep 17 00:00:00 2001 From: BayoNet Date: Tue, 17 Jul 2018 09:23:18 +0300 Subject: [PATCH 013/425] NULL in aggregate functions. --- docs/ru/agg_functions/index.md | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/ru/agg_functions/index.md b/docs/ru/agg_functions/index.md index 57afd3dfa81..4c540d0954a 100644 --- a/docs/ru/agg_functions/index.md +++ b/docs/ru/agg_functions/index.md @@ -8,3 +8,56 @@ ClickHouse поддерживает также: - [Параметрические агрегатные функции](parametric_functions.md#aggregate_functions_parametric), которые помимо стоблцов принимаю и другие параметры. - [Комбинаторы](combinators.md#aggregate_functions_combinators), которые изменяют поведение агрегатных фунций. + +## Обработка NULL + +При агрегации все `NULL` пропускаются. + +**Примеры** + +Рассмотрим таблицу: + +``` +┌─x─┬────y─┐ +│ 1 │ 2 │ +│ 2 │ ᴺᵁᴸᴸ │ +│ 3 │ 2 │ +│ 3 │ 3 │ +│ 3 │ ᴺᵁᴸᴸ │ +└───┴──────┘ +``` + +Выполним суммирование значений в столбце `y`: + +``` +:) SELECT sum(y) FROM t_null_big + +SELECT sum(y) +FROM t_null_big + +┌─sum(y)─┐ +│ 7 │ +└────────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + +Функция `sum` работает с `NULL` как с `0`. В частности, это означает, что если на вход в функцию подать выборку, где все значения `NULL`, то результат будет `0`, а не `NULL`. + + +Теперь с помощью фукции `groupArray` сформируем массив из стобца `y`: + +``` +:) SELECT groupArray(y) FROM t_null_big + +SELECT groupArray(y) +FROM t_null_big + +┌─groupArray(y)─┐ +│ [2,2,3] │ +└───────────────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + +`groupArray` не включает `NULL` в результирующий массив. From ca7f6b3d5b71fc380a71ece4060c40ca03db7fb0 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Tue, 17 Jul 2018 09:34:43 +0300 Subject: [PATCH 014/425] NULL in dictionaries. --- docs/ru/dicts/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ru/dicts/index.md b/docs/ru/dicts/index.md index f474a241db6..46a6164ec54 100644 --- a/docs/ru/dicts/index.md +++ b/docs/ru/dicts/index.md @@ -4,6 +4,7 @@ ClickHouse поддерживает специальные функции для работы со словарями, которые можно использовать в запросах. Проще и эффективнее использовать словари с помощью функций, чем `JOIN` с таблицами-справочниками. +В словаре нельзя хранить значения [NULL](../query_language/syntax.md#null-literal). ClickHouse поддерживает: From b4eb91b715c8ba0734d82c70d38659808d0604b4 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 05:54:28 +0300 Subject: [PATCH 015/425] Add SPb meetup link to main page --- website/index.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/index.html b/website/index.html index c67a1e96da0..9f9c75308d6 100644 --- a/website/index.html +++ b/website/index.html @@ -90,6 +90,11 @@
+
+
+ ClickHouse Meetup in Saint Petersburg on August 16 +
+

ClickHouse. Just makes you think faster.

From be44a22106afbf16b8ff27830cd420b31179ba49 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 07:36:24 +0300 Subject: [PATCH 016/425] Move Utilities out of top level of docs (the location is probably not yet final) + translate couple articles --- .../utils/clickhouse-copier.md | 0 docs/en/operations/utils/clickhouse-local.md | 74 ++++++++++++++++++ docs/en/{ => operations}/utils/index.md | 0 docs/en/table_engines/file.md | 75 +++++++++++++++++++ docs/en/utils/clickhouse-local.md | 6 -- docs/mkdocs_en.yml | 8 +- docs/mkdocs_ru.yml | 9 +-- docs/redirects.txt | 5 +- .../utils/clickhouse-copier.md | 0 .../utils/clickhouse-local.md | 2 +- docs/ru/{ => operations}/utils/index.md | 0 docs/ru/table_engines/file.md | 2 +- 12 files changed, 163 insertions(+), 18 deletions(-) rename docs/en/{ => operations}/utils/clickhouse-copier.md (100%) create mode 100644 docs/en/operations/utils/clickhouse-local.md rename docs/en/{ => operations}/utils/index.md (100%) delete mode 100644 docs/en/utils/clickhouse-local.md rename docs/ru/{ => operations}/utils/clickhouse-copier.md (100%) rename docs/ru/{ => operations}/utils/clickhouse-local.md (97%) rename docs/ru/{ => operations}/utils/index.md (100%) diff --git a/docs/en/utils/clickhouse-copier.md b/docs/en/operations/utils/clickhouse-copier.md similarity index 100% rename from docs/en/utils/clickhouse-copier.md rename to docs/en/operations/utils/clickhouse-copier.md diff --git a/docs/en/operations/utils/clickhouse-local.md b/docs/en/operations/utils/clickhouse-local.md new file mode 100644 index 00000000000..dadc02f9d3e --- /dev/null +++ b/docs/en/operations/utils/clickhouse-local.md @@ -0,0 +1,74 @@ + + +# clickhouse-local + +The `clickhouse-local` program enables you to perform fast processing on local files, without having to deploy and configure the ClickHouse server. + +Accepts data that represent tables and queries them using [ClickHouse SQL dialect](../../query_language/queries.md#queries). + +`clickhouse-local` uses the same core as ClickHouse server, so it supports most of the features and the same set of formats and table engines. + +By default `clickhouse-local` does not have access to data on the same host, but it supports loading server configuration using `--config-file` argument. + +
+It is not recommended to load production server configuration into `clickhouse-local` because data can be damaged in case of human error. +
+ + +## Usage + +Basic usage: + +``` bash +clickhouse-local --structure "table_structure" --input-format "format_of_incoming_data" -q "query" +``` + +Arguments: + +- `-S`, `--structure` — table structure for input data. +- `-if`, `--input-format` — input format, `TSV` by default. +- `-f`, `--file` — path to data, `stdin` by default. +- `-q` `--query` — queries to execute with `;` as delimeter. +- `-N`, `--table` — table name where to put output data, `table` by default. +- `-of`, `--format`, `--output-format` — output format, `TSV` by default. +- `--stacktrace` — whether to dump debug output in case of exception. +- `--verbose` — more details on query execution. +- `-s` — disables `stderr` logging. +- `--config-file` — path to configuration file in same format as for ClickHouse server, by default the configuration empty. +- `--help` — arguments references for `clickhouse-local`. + +Also there are arguments for each ClickHouse configuration variable which are more commonly used instead of `--config-file`. + + +## Examples + +``` bash +echo -e "1,2\n3,4" | clickhouse-local -S "a Int64, b Int64" -if "CSV" -q "SELECT * FROM table" +Read 2 rows, 32.00 B in 0.000 sec., 5182 rows/sec., 80.97 KiB/sec. +1 2 +3 4 +``` + +Previous example is the same as: + +``` bash +$ echo -e "1,2\n3,4" | clickhouse-local -q "CREATE TABLE table (a Int64, b Int64) ENGINE = File(CSV, stdin); SELECT a, b FROM table; DROP TABLE table" +Read 2 rows, 32.00 B in 0.000 sec., 4987 rows/sec., 77.93 KiB/sec. +1 2 +3 4 +``` + +Now let's output memory user for each Unix user: + +``` bash +$ ps aux | tail -n +2 | awk '{ printf("%s\t%s\n", $1, $4) }' | clickhouse-local -S "user String, mem Float64" -q "SELECT user, round(sum(mem), 2) as memTotal FROM table GROUP BY user ORDER BY memTotal DESC FORMAT Pretty" +Read 186 rows, 4.15 KiB in 0.035 sec., 5302 rows/sec., 118.34 KiB/sec. +┏━━━━━━━━━━┳━━━━━━━━━━┓ +┃ user ┃ memTotal ┃ +┡━━━━━━━━━━╇━━━━━━━━━━┩ +│ bayonet │ 113.5 │ +├──────────┼──────────┤ +│ root │ 8.8 │ +├──────────┼──────────┤ +... +``` diff --git a/docs/en/utils/index.md b/docs/en/operations/utils/index.md similarity index 100% rename from docs/en/utils/index.md rename to docs/en/operations/utils/index.md diff --git a/docs/en/table_engines/file.md b/docs/en/table_engines/file.md index a6d5f9eba43..d596434aa3a 100644 --- a/docs/en/table_engines/file.md +++ b/docs/en/table_engines/file.md @@ -1,4 +1,79 @@ + + # File(InputFormat) The data source is a file that stores data in one of the supported input formats (TabSeparated, Native, etc.). +Usage examples: + +- Data export from ClickHouse to file. +- Convert data from one format to another. +- Updating data in ClickHouse via editing a file on a disk. + +## Использование движка в сервере ClickHouse + +``` +File(Format) +``` + +`Format` should be supported for either `INSERT` and `SELECT`. For the full list of supported formats see [Formats](../interfaces/formats.md#formats). + +ClickHouse does not allow to specify filesystem path for`File`. It will use folder defined by [path](../operations/server_settings/settings.md#server_settings-path) setting in server configuration. + +When creating table using `File(Format)` it creates empty subdirectory in that folder. When data is written to that table, it's put into `data.Format` file in that subdirectory. + +You may manually create this subfolder and file in server filesystem and then [ATTACH](../query_language/queries.md#queries-attach) it to table information with matching name, so you can query data from that file. + +
+Be careful with this funcionality, because ClickHouse does not keep track of external changes to such files. The result of simultaneous writes via ClickHouse and outside of ClickHouse is undefined. +
+ +**Example:** + +**1.** Set up the `file_engine_table` table: + +```sql +CREATE TABLE file_engine_table (name String, value UInt32) ENGINE=File(TabSeparated) +``` + +By default ClickHouse will create folder `/var/lib/clickhouse/data/default/file_engine_table`. + +**2.** Manually create `/var/lib/clickhouse/data/default/file_engine_table/data.TabSeparated` containing: + +```bash +$ cat data.TabSeparated +one 1 +two 2 +``` + +**3.** Query the data: + +```sql +SELECT * FROM file_engine_table +``` + +```text +┌─name─┬─value─┐ +│ one │ 1 │ +│ two │ 2 │ +└──────┴───────┘ +``` + +## Using clickhouse-local + +In [clickhouse-local](../operations/utils/clickhouse-local.md#utils-clickhouse-local) File engine accepts file path in addition to `Format`. Default input/output streams can be specified using numeric or human-readable names like `0` or `stdin`, `1` or `stdout`. + +**Example:** + +```bash +$ echo -e "1,2\n3,4" | clickhouse-local -q "CREATE TABLE table (a Int64, b Int64) ENGINE = File(CSV, stdin); SELECT a, b FROM table; DROP TABLE table" +``` + +## Details of implemntation + +- Reads can be parallel, but not writes +- Not supported: + - `ALTER` + - `SELECT ... SAMPLE` + - Indices + - Replication diff --git a/docs/en/utils/clickhouse-local.md b/docs/en/utils/clickhouse-local.md deleted file mode 100644 index d5fba56271f..00000000000 --- a/docs/en/utils/clickhouse-local.md +++ /dev/null @@ -1,6 +0,0 @@ - - -#clickhouse-local - -The `clickhouse-local` program enables you to perform fast processing on local files that store tables, without having to deploy and configure the ClickHouse server. - diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 2194a9c540c..391be85171f 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -153,10 +153,10 @@ pages: - 'Settings': 'operations/settings/settings.md' - 'Settings profiles': 'operations/settings/settings_profiles.md' -- 'Utilities': - - 'Introduction': 'utils/index.md' - - 'clickhouse-copier': 'utils/clickhouse-copier.md' - - 'clickhouse-local': 'utils/clickhouse-local.md' + - 'Utilities': + - 'Overview': 'operations/utils/index.md' + - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md' + - 'clickhouse-local': 'operations/utils/clickhouse-local.md' - 'ClickHouse Development': # - 'ClickHouse Development': 'development/index.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index de5f255db2b..5e3e3ebe3af 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -153,11 +153,10 @@ pages: - 'Ограничения на сложность запроса': 'operations/settings/query_complexity.md' - 'Настройки': 'operations/settings/settings.md' - 'Профили настроек': 'operations/settings/settings_profiles.md' - -- 'Утилиты': - - 'Введение': 'utils/index.md' - - 'clickhouse-copier': 'utils/clickhouse-copier.md' - - 'clickhouse-local': 'utils/clickhouse-local.md' + - 'Утилиты': + - 'Введение': 'operations/utils/index.md' + - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md' + - 'clickhouse-local': 'operations/utils/clickhouse-local.md' - 'ClickHouse Development': # - 'ClickHouse Development': 'development/index.md' diff --git a/docs/redirects.txt b/docs/redirects.txt index a7d1be92f5e..93024244acc 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -20,7 +20,7 @@ system_tables/system.zookeeper.md operations/system_tables.md formats/capnproto.md formats/interfaces.md formats/csv.md formats/interfaces.md formats/csvwithnames.md formats/interfaces.md -formats/index.md formats/interfaces.md +formats.md formats/interfaces.md formats/json.md formats/interfaces.md formats/jsoncompact.md formats/interfaces.md formats/jsoneachrow.md formats/interfaces.md @@ -41,3 +41,6 @@ formats/values.md formats/interfaces.md formats/vertical.md formats/interfaces.md formats/verticalraw.md formats/interfaces.md formats/xml.md formats/interfaces.md +utils/clickhouse-copier.md operations/utils/clickhouse-copier.md +utils/clickhouse-local.md operations/utils/clickhouse-local.md +utils.md operations/utils.md diff --git a/docs/ru/utils/clickhouse-copier.md b/docs/ru/operations/utils/clickhouse-copier.md similarity index 100% rename from docs/ru/utils/clickhouse-copier.md rename to docs/ru/operations/utils/clickhouse-copier.md diff --git a/docs/ru/utils/clickhouse-local.md b/docs/ru/operations/utils/clickhouse-local.md similarity index 97% rename from docs/ru/utils/clickhouse-local.md rename to docs/ru/operations/utils/clickhouse-local.md index 64aec03ab76..01e4de52c71 100644 --- a/docs/ru/utils/clickhouse-local.md +++ b/docs/ru/operations/utils/clickhouse-local.md @@ -2,7 +2,7 @@ # clickhouse-local -Принимает на вход данные, которые можно представить в табличном виде и выполняет над ними операции, заданные на [языке запросов](../query_language/queries.md#queries) ClickHouse. +Принимает на вход данные, которые можно представить в табличном виде и выполняет над ними операции, заданные на [языке запросов](../../query_language/queries.md#queries) ClickHouse. `clickhouse-local` использует движок сервера ClickHouse, т.е. поддерживает все форматы данных и движки таблиц, с которыми работает ClickHouse, при этом для выполнения операций не требуется запущенный сервер. diff --git a/docs/ru/utils/index.md b/docs/ru/operations/utils/index.md similarity index 100% rename from docs/ru/utils/index.md rename to docs/ru/operations/utils/index.md diff --git a/docs/ru/table_engines/file.md b/docs/ru/table_engines/file.md index 59903a7ae5b..a5af94341db 100644 --- a/docs/ru/table_engines/file.md +++ b/docs/ru/table_engines/file.md @@ -61,7 +61,7 @@ SELECT * FROM file_engine_table ## Использование движка в clickhouse-local -В [clickhouse-local](../utils/clickhouse-local.md#utils-clickhouse-local) движок в качестве параметра принимает не только формат, но и путь к файлу. В том числе можно указать стандартные потоки ввода/вывода цифровым или буквенным обозначением `0` или `stdin`, `1` или `stdout`. +В [clickhouse-local](../operations/utils/clickhouse-local.md#utils-clickhouse-local) движок в качестве параметра принимает не только формат, но и путь к файлу. В том числе можно указать стандартные потоки ввода/вывода цифровым или буквенным обозначением `0` или `stdin`, `1` или `stdout`. **Пример:** From 62db52199ba6a213d99d9941118f892481be38e7 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 07:41:23 +0300 Subject: [PATCH 017/425] Merge MacOS.md into build_osx.md --- MacOS.md | 39 ----------------------------- docs/en/development/build_osx.md | 42 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 40 deletions(-) delete mode 100644 MacOS.md diff --git a/MacOS.md b/MacOS.md deleted file mode 100644 index 93c04d7c2de..00000000000 --- a/MacOS.md +++ /dev/null @@ -1,39 +0,0 @@ -## How to increase maxfiles on macOS - -To increase maxfiles on macOS, create the following file: - -(Note: you'll need to use sudo) - -/Library/LaunchDaemons/limit.maxfiles.plist: -``` - - - - - Label - limit.maxfiles - ProgramArguments - - launchctl - limit - maxfiles - 524288 - 524288 - - RunAtLoad - - ServiceIPC - - - -``` - -Execute the following command: -``` -sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist -``` - -Reboot. - -To check if it's working, you can use `ulimit -n` command. diff --git a/docs/en/development/build_osx.md b/docs/en/development/build_osx.md index d0012276ec1..d29301a4b2b 100644 --- a/docs/en/development/build_osx.md +++ b/docs/en/development/build_osx.md @@ -41,5 +41,45 @@ cd .. ## Caveats -If you intend to run clickhouse-server, make sure to increase the system's maxfiles variable. See [MacOS.md](https://github.com/yandex/ClickHouse/blob/master/MacOS.md) for more details. +If you intend to run clickhouse-server, make sure to increase the system's maxfiles variable. + +
+Note: you'll need to use sudo. +
+ +To do so, create the following file: + +/Library/LaunchDaemons/limit.maxfiles.plist: +``` xml + + + + + Label + limit.maxfiles + ProgramArguments + + launchctl + limit + maxfiles + 524288 + 524288 + + RunAtLoad + + ServiceIPC + + + +``` + +Execute the following command: +``` bash +$ sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist +``` + +Reboot. + +To check if it's working, you can use `ulimit -n` command. From 6f755fe3068788940336dabe4c9d41037aac9ff3 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 07:44:20 +0300 Subject: [PATCH 018/425] Move Data types higher in ToC --- docs/mkdocs_en.yml | 42 +++++++++++++++++++++--------------------- docs/mkdocs_ru.yml | 42 +++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 391be85171f..bcf5499f2a5 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -29,6 +29,27 @@ pages: - 'Visual interfaces from third-party developers': 'interfaces/third-party_gui.md' - 'Input and output formats': 'interfaces/formats.md' +- 'Data types': + - 'Introduction': 'data_types/index.md' + - 'UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64': 'data_types/int_uint.md' + - 'Float32, Float64': 'data_types/float.md' + - 'Boolean values': 'data_types/boolean.md' + - 'String': 'data_types/string.md' + - 'FixedString(N)': 'data_types/fixedstring.md' + - 'Date': 'data_types/date.md' + - 'DateTime': 'data_types/datetime.md' + - 'Enum': 'data_types/enum.md' + - 'Array(T)': 'data_types/array.md' + - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' + - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' + - 'Nested data structures': +# - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' + - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' + - 'Special data types': +# - 'Служебные типы данных': 'data_types/special_data_types/index.md' + - 'Expression': 'data_types/special_data_types/expression.md' + - 'Set': 'data_types/special_data_types/set.md' + - 'Query language': # - 'Query language': 'query_language/index.md' - 'Queries': 'query_language/queries.md' @@ -68,27 +89,6 @@ pages: - 'numbers': 'table_functions/numbers.md' - 'remote': 'table_functions/remote.md' -- 'Data types': - - 'Introduction': 'data_types/index.md' - - 'UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64': 'data_types/int_uint.md' - - 'Float32, Float64': 'data_types/float.md' - - 'Boolean values': 'data_types/boolean.md' - - 'String': 'data_types/string.md' - - 'FixedString(N)': 'data_types/fixedstring.md' - - 'Date': 'data_types/date.md' - - 'DateTime': 'data_types/datetime.md' - - 'Enum': 'data_types/enum.md' - - 'Array(T)': 'data_types/array.md' - - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' - - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' - - 'Nested data structures': -# - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' - - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' - - 'Special data types': -# - 'Служебные типы данных': 'data_types/special_data_types/index.md' - - 'Expression': 'data_types/special_data_types/expression.md' - - 'Set': 'data_types/special_data_types/set.md' - - 'Operators': 'operators/index.md' - 'Functions': diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 5e3e3ebe3af..94692099a1c 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -29,6 +29,27 @@ pages: - 'Визуальные интерфейсы от сторонних разработчиков': 'interfaces/third-party_gui.md' - 'Форматы входных и выходных данных': 'interfaces/formats.md' +- 'Типы данных': + - 'Введение': 'data_types/index.md' + - 'UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64': 'data_types/int_uint.md' + - 'Float32, Float64': 'data_types/float.md' + - 'Булевы значения': 'data_types/boolean.md' + - 'String': 'data_types/string.md' + - 'FixedString(N)': 'data_types/fixedstring.md' + - 'Date': 'data_types/date.md' + - 'DateTime': 'data_types/datetime.md' + - 'Enum': 'data_types/enum.md' + - 'Array(T)': 'data_types/array.md' + - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' + - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' + - 'Вложенные структуры данных': +# - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' + - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' + - 'Служебные типы данных': +# - 'Служебные типы данных': 'data_types/special_data_types/index.md' + - 'Expression': 'data_types/special_data_types/expression.md' + - 'Set': 'data_types/special_data_types/set.md' + - 'Язык запросов': # - 'Язык запросов': 'query_language/index.md' - 'Запросы': 'query_language/queries.md' @@ -68,27 +89,6 @@ pages: - 'numbers': 'table_functions/numbers.md' - 'remote': 'table_functions/remote.md' -- 'Типы данных': - - 'Введение': 'data_types/index.md' - - 'UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64': 'data_types/int_uint.md' - - 'Float32, Float64': 'data_types/float.md' - - 'Булевы значения': 'data_types/boolean.md' - - 'String': 'data_types/string.md' - - 'FixedString(N)': 'data_types/fixedstring.md' - - 'Date': 'data_types/date.md' - - 'DateTime': 'data_types/datetime.md' - - 'Enum': 'data_types/enum.md' - - 'Array(T)': 'data_types/array.md' - - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' - - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' - - 'Вложенные структуры данных': -# - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' - - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' - - 'Служебные типы данных': -# - 'Служебные типы данных': 'data_types/special_data_types/index.md' - - 'Expression': 'data_types/special_data_types/expression.md' - - 'Set': 'data_types/special_data_types/set.md' - - 'Операторы': 'operators/index.md' - 'Функции': From 86031cf7a769f24667bf9ce3badbd71345d2ebef Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 07:55:18 +0300 Subject: [PATCH 019/425] Publish changelog on website alongside documentation --- docs/en/changelog.md | 1 + docs/mkdocs_en.yml | 1 + docs/mkdocs_ru.yml | 1 + docs/ru/changelog.md | 1 + 4 files changed, 4 insertions(+) create mode 120000 docs/en/changelog.md create mode 120000 docs/ru/changelog.md diff --git a/docs/en/changelog.md b/docs/en/changelog.md new file mode 120000 index 00000000000..699cc9e7b7c --- /dev/null +++ b/docs/en/changelog.md @@ -0,0 +1 @@ +../../CHANGELOG.md \ No newline at end of file diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index bcf5499f2a5..976c6950554 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -167,3 +167,4 @@ pages: - 'How to run ClickHouse tests': 'development/tests.md' - 'Roadmap': 'roadmap.md' +- 'Changelog': 'changelog.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 94692099a1c..a0f77f0d5a1 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -167,3 +167,4 @@ pages: - 'How to run ClickHouse tests': 'development/tests.md' - 'Roadmap': 'roadmap.md' +- 'Changelog': 'changelog.md' diff --git a/docs/ru/changelog.md b/docs/ru/changelog.md new file mode 120000 index 00000000000..b84693cec46 --- /dev/null +++ b/docs/ru/changelog.md @@ -0,0 +1 @@ +../../CHANGELOG_RU.md \ No newline at end of file From 9f2130cbb838942e97382fcdd2ec86c82e4527e9 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 07:57:25 +0300 Subject: [PATCH 020/425] Few fixes for en/table_engines/file.md --- docs/en/table_engines/file.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/table_engines/file.md b/docs/en/table_engines/file.md index d596434aa3a..175e6f69b80 100644 --- a/docs/en/table_engines/file.md +++ b/docs/en/table_engines/file.md @@ -10,7 +10,7 @@ Usage examples: - Convert data from one format to another. - Updating data in ClickHouse via editing a file on a disk. -## Использование движка в сервере ClickHouse +## Usage in ClickHouse server ``` File(Format) @@ -59,7 +59,7 @@ SELECT * FROM file_engine_table └──────┴───────┘ ``` -## Using clickhouse-local +## Usage in clickhouse-local In [clickhouse-local](../operations/utils/clickhouse-local.md#utils-clickhouse-local) File engine accepts file path in addition to `Format`. Default input/output streams can be specified using numeric or human-readable names like `0` or `stdin`, `1` or `stdout`. @@ -69,7 +69,7 @@ In [clickhouse-local](../operations/utils/clickhouse-local.md#utils-clickhouse-l $ echo -e "1,2\n3,4" | clickhouse-local -q "CREATE TABLE table (a Int64, b Int64) ENGINE = File(CSV, stdin); SELECT a, b FROM table; DROP TABLE table" ``` -## Details of implemntation +## Details of implementation - Reads can be parallel, but not writes - Not supported: From e327bdd9b881b8ca21453a35ccc08d1e45c66c24 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 08:00:17 +0300 Subject: [PATCH 021/425] Use smaller header sizes in changelogs --- CHANGELOG.draft.md | 12 ++-- CHANGELOG.md | 148 ++++++++++++++++++++++----------------------- CHANGELOG_RU.md | 148 ++++++++++++++++++++++----------------------- 3 files changed, 154 insertions(+), 154 deletions(-) diff --git a/CHANGELOG.draft.md b/CHANGELOG.draft.md index 3dc49842e12..89156db08fc 100644 --- a/CHANGELOG.draft.md +++ b/CHANGELOG.draft.md @@ -1,15 +1,15 @@ -# en: +## en: -## Improvements: +### Improvements: * Added Nullable support for runningDifference function. [#2590](https://github.com/yandex/ClickHouse/issues/2590) -## Bug fiexs: +### Bug fiexs: * Fixed switching to default databses in case of client reconection. [#2580](https://github.com/yandex/ClickHouse/issues/2580) -# ru: +## ru: -## Улучшения: +### Улучшения: * Добавлена поддержка Nullable для функции runningDifference. [#2590](https://github.com/yandex/ClickHouse/issues/2590) -## Исправление ошибок: +### Исправление ошибок: * Исправлено переключение на дефолтную базу данных при переподключении клиента. [#2580](https://github.com/yandex/ClickHouse/issues/2580) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf00a1cab40..6c4c280269d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ -# ClickHouse release 1.1.54388, 2018-06-28 +## ClickHouse release 1.1.54388, 2018-06-28 -## New features: +### New features: * Support for the `ALTER TABLE t DELETE WHERE` query for replicated tables. Added the `system.mutations` table to track progress of this type of queries. * Support for the `ALTER TABLE t [REPLACE|ATTACH] PARTITION` query for MergeTree tables. @@ -18,12 +18,12 @@ * Added the `date_time_input_format` setting. If you switch this setting to `'best_effort'`, DateTime values will be read in a wide range of formats. * Added the `clickhouse-obfuscator` utility for data obfuscation. Usage example: publishing data used in performance tests. -## Experimental features: +### Experimental features: * Added the ability to calculate `and` arguments only where they are needed ([Anastasia Tsarkova](https://github.com/yandex/ClickHouse/pull/2272)). * JIT compilation to native code is now available for some expressions ([pyos](https://github.com/yandex/ClickHouse/pull/2277)). -## Bug fixes: +### Bug fixes: * Duplicates no longer appear for a query with `DISTINCT` and `ORDER BY`. * Queries with `ARRAY JOIN` and `arrayFilter` no longer return an incorrect result. @@ -45,7 +45,7 @@ * Fixed SSRF in the `remote()` table function. * Fixed exit behavior of `clickhouse-client` in multiline mode ([#2510](https://github.com/yandex/ClickHouse/issues/2510)). -## Improvements: +### Improvements: * Background tasks in replicated tables are now performed in a thread pool instead of in separate threads ([Silviu Caragea](https://github.com/yandex/ClickHouse/pull/1722)). * Improved LZ4 compression performance. @@ -58,7 +58,7 @@ * When calculating the number of available CPU cores, limits on cgroups are now taken into account ([Atri Sharma](https://github.com/yandex/ClickHouse/pull/2325)). * Added chown for config directories in the systemd config file ([Mikhail Shiryaev](https://github.com/yandex/ClickHouse/pull/2421)). -## Build changes: +### Build changes: * The gcc8 compiler can be used for builds. * Added the ability to build llvm from a submodule. @@ -69,35 +69,35 @@ * Added the ability to use the libtinfo library instead of libtermcap ([Georgy Kondratiev](https://github.com/yandex/ClickHouse/pull/2519)). * Fixed a header file conflict in Fedora Rawhide ([#2520](https://github.com/yandex/ClickHouse/issues/2520)). -## Backward incompatible changes: +### Backward incompatible changes: * Removed escaping in `Vertical` and `Pretty*` formats and deleted the `VerticalRaw` format. -# ClickHouse release 1.1.54385, 2018-06-01 +## ClickHouse release 1.1.54385, 2018-06-01 -## Bug fixes: +### Bug fixes: * Fixed an error that in some cases caused ZooKeeper operations to block. -# ClickHouse release 1.1.54383, 2018-05-22 +## ClickHouse release 1.1.54383, 2018-05-22 -## Bug fixes: +### Bug fixes: * Fixed a slowdown of replication queue if a table has many replicas. -# ClickHouse release 1.1.54381, 2018-05-14 +## ClickHouse release 1.1.54381, 2018-05-14 -## Bug fixes: +### Bug fixes: * Fixed a nodes leak in ZooKeeper when ClickHouse loses connection to ZooKeeper server. -# ClickHouse release 1.1.54380, 2018-04-21 +## ClickHouse release 1.1.54380, 2018-04-21 -## New features: +### New features: * Added table function `file(path, format, structure)`. An example reading bytes from `/dev/urandom`: `ln -s /dev/urandom /var/lib/clickhouse/user_files/random` `clickhouse-client -q "SELECT * FROM file('random', 'RowBinary', 'd UInt8') LIMIT 10"`. -## Improvements: +### Improvements: * Subqueries could be wrapped by `()` braces (to enhance queries readability). For example, `(SELECT 1) UNION ALL (SELECT 1)`. * Simple `SELECT` queries from table `system.processes` are not counted in `max_concurrent_queries` limit. -## Bug fixes: +### Bug fixes: * Fixed incorrect behaviour of `IN` operator when select from `MATERIALIZED VIEW`. * Fixed incorrect filtering by partition index in expressions like `WHERE partition_key_column IN (...)` * Fixed inability to execute `OPTIMIZE` query on non-leader replica if the table was `REANAME`d. @@ -105,11 +105,11 @@ * Fixed freezing of `KILL QUERY` queries. * Fixed an error in ZooKeeper client library which led to watches loses, freezing of distributed DDL queue and slowing replication queue if non-empty `chroot` prefix is used in ZooKeeper configuration. -## Backward incompatible changes: +### Backward incompatible changes: * Removed support of expressions like `(a, b) IN (SELECT (a, b))` (instead of them you can use their equivalent `(a, b) IN (SELECT a, b)`). In previous releases, these expressions led to undetermined data filtering or caused errors. -# ClickHouse release 1.1.54378, 2018-04-16 -## New features: +## ClickHouse release 1.1.54378, 2018-04-16 +### New features: * Logging level can be changed without restarting the server. * Added the `SHOW CREATE DATABASE` query. @@ -123,7 +123,7 @@ * Multiple comma-separated `topics` can be specified for the `Kafka` engine (Tobias Adamson). * When a query is stopped by `KILL QUERY` or `replace_running_query`, the client receives the `Query was cancelled` exception instead of an incomplete response. -## Improvements: +### Improvements: * `ALTER TABLE ... DROP/DETACH PARTITION` queries are run at the front of the replication queue. * `SELECT ... FINAL` and `OPTIMIZE ... FINAL` can be used even when the table has a single data part. @@ -134,7 +134,7 @@ * More robust crash recovery for asynchronous insertion into `Distributed` tables. * The return type of the `countEqual` function changed from `UInt32` to `UInt64` (谢磊). -## Bug fixes: +### Bug fixes: * Fixed an error with `IN` when the left side of the expression is `Nullable`. * Correct results are now returned when using tuples with `IN` when some of the tuple components are in the table index. @@ -150,31 +150,31 @@ * `SummingMergeTree` now works correctly for summation of nested data structures with a composite key. * Fixed the possibility of a race condition when choosing the leader for `ReplicatedMergeTree` tables. -## Build changes: +### Build changes: * The build supports `ninja` instead of `make` and uses it by default for building releases. * Renamed packages: `clickhouse-server-base` is now `clickhouse-common-static`; `clickhouse-server-common` is now `clickhouse-server`; `clickhouse-common-dbg` is now `clickhouse-common-static-dbg`. To install, use `clickhouse-server clickhouse-client`. Packages with the old names will still load in the repositories for backward compatibility. -## Backward-incompatible changes: +### Backward-incompatible changes: * Removed the special interpretation of an IN expression if an array is specified on the left side. Previously, the expression `arr IN (set)` was interpreted as "at least one `arr` element belongs to the `set`". To get the same behavior in the new version, write `arrayExists(x -> x IN (set), arr)`. * Disabled the incorrect use of the socket option `SO_REUSEPORT`, which was incorrectly enabled by default in the Poco library. Note that on Linux there is no longer any reason to simultaneously specify the addresses `::` and `0.0.0.0` for listen – use just `::`, which allows listening to the connection both over IPv4 and IPv6 (with the default kernel config settings). You can also revert to the behavior from previous versions by specifying `1` in the config. -# ClickHouse release 1.1.54370, 2018-03-16 +## ClickHouse release 1.1.54370, 2018-03-16 -## New features: +### New features: * Added the `system.macros` table and auto updating of macros when the config file is changed. * Added the `SYSTEM RELOAD CONFIG` query. * Added the `maxIntersections(left_col, right_col)` aggregate function, which returns the maximum number of simultaneously intersecting intervals `[left; right]`. The `maxIntersectionsPosition(left, right)` function returns the beginning of the "maximum" interval. ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2012)). -## Improvements: +### Improvements: * When inserting data in a `Replicated` table, fewer requests are made to `ZooKeeper` (and most of the user-level errors have disappeared from the `ZooKeeper` log). * Added the ability to create aliases for sets. Example: `WITH (1, 2, 3) AS set SELECT number IN set FROM system.numbers LIMIT 10`. -## Bug fixes: +### Bug fixes: * Fixed the `Illegal PREWHERE` error when reading from `Merge` tables over `Distributed` tables. * Added fixes that allow you to run `clickhouse-server` in IPv4-only Docker containers. @@ -188,9 +188,9 @@ * Restored the behavior for queries like `SELECT * FROM remote('server2', default.table) WHERE col IN (SELECT col2 FROM default.table)` when the right side argument of the `IN` should use a remote `default.table` instead of a local one. This behavior was broken in version 1.1.54358. * Removed extraneous error-level logging of `Not found column ... in block`. -# ClickHouse release 1.1.54356, 2018-03-06 +## ClickHouse release 1.1.54356, 2018-03-06 -## New features: +### New features: * Aggregation without `GROUP BY` for an empty set (such as `SELECT count(*) FROM table WHERE 0`) now returns a result with one row with null values for aggregate functions, in compliance with the SQL standard. To restore the old behavior (return an empty result), set `empty_result_for_aggregation_by_empty_set` to 1. * Added type conversion for `UNION ALL`. Different alias names are allowed in `SELECT` positions in `UNION ALL`, in compliance with the SQL standard. @@ -225,7 +225,7 @@ * `RENAME TABLE` can be performed for `VIEW`. * Added the `odbc_default_field_size` option, which allows you to extend the maximum size of the value loaded from an ODBC source (by default, it is 1024). -## Improvements: +### Improvements: * Limits and quotas on the result are no longer applied to intermediate data for `INSERT SELECT` queries or for `SELECT` subqueries. * Fewer false triggers of `force_restore_data` when checking the status of `Replicated` tables when the server starts. @@ -241,7 +241,7 @@ * `Enum` values can be used in `min`, `max`, `sum` and some other functions. In these cases, it uses the corresponding numeric values. This feature was previously available but was lost in the release 1.1.54337. * Added `max_expanded_ast_elements` to restrict the size of the AST after recursively expanding aliases. -## Bug fixes: +### Bug fixes: * Fixed cases when unnecessary columns were removed from subqueries in error, or not removed from subqueries containing `UNION ALL`. * Fixed a bug in merges for `ReplacingMergeTree` tables. @@ -267,18 +267,18 @@ * Fixed a crash when passing arrays of different sizes to an `arrayReduce` function when using aggregate functions from multiple arguments. * Prohibited the use of queries with `UNION ALL` in a `MATERIALIZED VIEW`. -## Backward incompatible changes: +### Backward incompatible changes: * Removed the `distributed_ddl_allow_replicated_alter` option. This behavior is enabled by default. * Removed the `UnsortedMergeTree` engine. -# ClickHouse release 1.1.54343, 2018-02-05 +## ClickHouse release 1.1.54343, 2018-02-05 * Added macros support for defining cluster names in distributed DDL queries and constructors of Distributed tables: `CREATE TABLE distr ON CLUSTER '{cluster}' (...) ENGINE = Distributed('{cluster}', 'db', 'table')`. * Now the table index is used for conditions like `expr IN (subquery)`. * Improved processing of duplicates when inserting to Replicated tables, so they no longer slow down execution of the replication queue. -# ClickHouse release 1.1.54342, 2018-01-22 +## ClickHouse release 1.1.54342, 2018-01-22 This release contains bug fixes for the previous release 1.1.54337: * Fixed a regression in 1.1.54337: if the default user has readonly access, then the server refuses to start up with the message `Cannot create database in readonly mode`. @@ -289,9 +289,9 @@ This release contains bug fixes for the previous release 1.1.54337: * Buffer tables now work correctly when MATERIALIZED columns are present in the destination table (by zhang2014). * Fixed a bug in implementation of NULL. -# ClickHouse release 1.1.54337, 2018-01-18 +## ClickHouse release 1.1.54337, 2018-01-18 -## New features: +### New features: * Added support for storage of multidimensional arrays and tuples (`Tuple` data type) in tables. * Added support for table functions in `DESCRIBE` and `INSERT` queries. Added support for subqueries in `DESCRIBE`. Examples: `DESC TABLE remote('host', default.hits)`; `DESC TABLE (SELECT 1)`; `INSERT INTO TABLE FUNCTION remote('host', default.hits)`. Support for `INSERT INTO TABLE` syntax in addition to `INSERT INTO`. @@ -322,7 +322,7 @@ This release contains bug fixes for the previous release 1.1.54337: * Added the `--silent` option for the `clickhouse-local` tool. It suppresses printing query execution info in stderr. * Added support for reading values of type `Date` from text in a format where the month and/or day of the month is specified using a single digit instead of two digits (Amos Bird). -## Performance optimizations: +### Performance optimizations: * Improved performance of `min`, `max`, `any`, `anyLast`, `anyHeavy`, `argMin`, `argMax` aggregate functions for String arguments. * Improved performance of `isInfinite`, `isFinite`, `isNaN`, `roundToExp2` functions. @@ -331,7 +331,7 @@ This release contains bug fixes for the previous release 1.1.54337: * Lowered memory usage for `JOIN` in the case when the left and right parts have columns with identical names that are not contained in `USING`. * Improved performance of `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, and `corr` aggregate functions by reducing computational stability. The old functions are available under the names: `varSampStable`, `varPopStable`, `stddevSampStable`, `stddevPopStable`, `covarSampStable`, `covarPopStable`, `corrStable`. -## Bug fixes: +### Bug fixes: * Fixed data deduplication after running a `DROP PARTITION` query. In the previous version, dropping a partition and INSERTing the same data again was not working because INSERTed blocks were considered duplicates. * Fixed a bug that could lead to incorrect interpretation of the `WHERE` clause for `CREATE MATERIALIZED VIEW` queries with `POPULATE`. @@ -370,7 +370,7 @@ This release contains bug fixes for the previous release 1.1.54337: * Fixed the `SYSTEM DROP DNS CACHE` query: the cache was flushed but addresses of cluster nodes were not updated. * Fixed the behavior of `MATERIALIZED VIEW` after executing `DETACH TABLE` for the table under the view (Marek Vavruša). -## Build improvements: +### Build improvements: * Builds use `pbuilder`. The build process is almost completely independent of the build host environment. * A single build is used for different OS versions. Packages and binaries have been made compatible with a wide range of Linux systems. @@ -384,7 +384,7 @@ This release contains bug fixes for the previous release 1.1.54337: * Removed usage of GNU extensions from the code. Enabled the `-Wextra` option. When building with `clang`, `libc++` is used instead of `libstdc++`. * Extracted `clickhouse_parsers` and `clickhouse_common_io` libraries to speed up builds of various tools. -## Backward incompatible changes: +### Backward incompatible changes: * The format for marks in `Log` type tables that contain `Nullable` columns was changed in a backward incompatible way. If you have these tables, you should convert them to the `TinyLog` type before starting up the new server version. To do this, replace `ENGINE = Log` with `ENGINE = TinyLog` in the corresponding `.sql` file in the `metadata` directory. If your table doesn't have `Nullable` columns or if the type of your table is not `Log`, then you don't need to do anything. * Removed the `experimental_allow_extended_storage_definition_syntax` setting. Now this feature is enabled by default. @@ -395,16 +395,16 @@ This release contains bug fixes for the previous release 1.1.54337: * In previous server versions there was an undocumented feature: if an aggregate function depends on parameters, you can still specify it without parameters in the AggregateFunction data type. Example: `AggregateFunction(quantiles, UInt64)` instead of `AggregateFunction(quantiles(0.5, 0.9), UInt64)`. This feature was lost. Although it was undocumented, we plan to support it again in future releases. * Enum data types cannot be used in min/max aggregate functions. The possibility will be returned back in future release. -## Please note when upgrading: +### Please note when upgrading: * When doing a rolling update on a cluster, at the point when some of the replicas are running the old version of ClickHouse and some are running the new version, replication is temporarily stopped and the message `unknown parameter 'shard'` appears in the log. Replication will continue after all replicas of the cluster are updated. * If you have different ClickHouse versions on the cluster, you can get incorrect results for distributed queries with the aggregate functions `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, and `corr`. You should update all cluster nodes. -# ClickHouse release 1.1.54327, 2017-12-21 +## ClickHouse release 1.1.54327, 2017-12-21 This release contains bug fixes for the previous release 1.1.54318: * Fixed bug with possible race condition in replication that could lead to data loss. This issue affects versions 1.1.54310 and 1.1.54318. If you use one of these versions with Replicated tables, the update is strongly recommended. This issue shows in logs in Warning messages like `Part ... from own log doesn't exist.` The issue is relevant even if you don't see these messages in logs. -# ClickHouse release 1.1.54318, 2017-11-30 +## ClickHouse release 1.1.54318, 2017-11-30 This release contains bug fixes for the previous release 1.1.54310: * Fixed incorrect row deletions during merges in the SummingMergeTree engine @@ -413,9 +413,9 @@ This release contains bug fixes for the previous release 1.1.54310: * Fixed an issue that was causing the replication queue to stop running * Fixed rotation and archiving of server logs -# ClickHouse release 1.1.54310, 2017-11-01 +## ClickHouse release 1.1.54310, 2017-11-01 -## New features: +### New features: * Custom partitioning key for the MergeTree family of table engines. * [Kafka](https://clickhouse.yandex/docs/en/single/index.html#document-table_engines/kafka) table engine. * Added support for loading [CatBoost](https://catboost.yandex/) models and applying them to data stored in ClickHouse. @@ -431,12 +431,12 @@ This release contains bug fixes for the previous release 1.1.54310: * Added support for the Cap'n Proto input format. * You can now customize compression level when using the zstd algorithm. -## Backward incompatible changes: +### Backward incompatible changes: * Creation of temporary tables with an engine other than Memory is forbidden. * Explicit creation of tables with the View or MaterializedView engine is forbidden. * During table creation, a new check verifies that the sampling key expression is included in the primary key. -## Bug fixes: +### Bug fixes: * Fixed hangups when synchronously inserting into a Distributed table. * Fixed nonatomic adding and removing of parts in Replicated tables. * Data inserted into a materialized view is not subjected to unnecessary deduplication. @@ -446,15 +446,15 @@ This release contains bug fixes for the previous release 1.1.54310: * Fixed hangups when the disk volume containing server logs is full. * Fixed an overflow in the `toRelativeWeekNum` function for the first week of the Unix epoch. -## Build improvements: +### Build improvements: * Several third-party libraries (notably Poco) were updated and converted to git submodules. -# ClickHouse release 1.1.54304, 2017-10-19 +## ClickHouse release 1.1.54304, 2017-10-19 -## New features: +### New features: * TLS support in the native protocol (to enable, set `tcp_ssl_port` in `config.xml`) -## Bug fixes: +### Bug fixes: * `ALTER` for replicated tables now tries to start running as soon as possible * Fixed crashing when reading data with the setting `preferred_block_size_bytes=0` * Fixed crashes of `clickhouse-client` when `Page Down` is pressed @@ -467,16 +467,16 @@ This release contains bug fixes for the previous release 1.1.54310: * Users are updated correctly when `users.xml` is invalid * Correct handling when an executable dictionary returns a non-zero response code -# ClickHouse release 1.1.54292, 2017-09-20 +## ClickHouse release 1.1.54292, 2017-09-20 -## New features: +### New features: * Added the `pointInPolygon` function for working with coordinates on a coordinate plane. * Added the `sumMap` aggregate function for calculating the sum of arrays, similar to `SummingMergeTree`. * Added the `trunc` function. Improved performance of the rounding functions (`round`, `floor`, `ceil`, `roundToExp2`) and corrected the logic of how they work. Changed the logic of the `roundToExp2` function for fractions and negative numbers. * The ClickHouse executable file is now less dependent on the libc version. The same ClickHouse executable file can run on a wide variety of Linux systems. Note: There is still a dependency when using compiled queries (with the setting `compile = 1`, which is not used by default). * Reduced the time needed for dynamic compilation of queries. -## Bug fixes: +### Bug fixes: * Fixed an error that sometimes produced `part ... intersects previous part` messages and weakened replica consistency. * Fixed an error that caused the server to lock up if ZooKeeper was unavailable during shutdown. * Removed excessive logging when restoring replicas. @@ -484,9 +484,9 @@ This release contains bug fixes for the previous release 1.1.54310: * Fixed an error in the concat function that occurred if the first column in a block has the Array type. * Progress is now displayed correctly in the system.merges table. -# ClickHouse release 1.1.54289, 2017-09-13 +## ClickHouse release 1.1.54289, 2017-09-13 -## New features: +### New features: * `SYSTEM` queries for server administration: `SYSTEM RELOAD DICTIONARY`, `SYSTEM RELOAD DICTIONARIES`, `SYSTEM DROP DNS CACHE`, `SYSTEM SHUTDOWN`, `SYSTEM KILL`. * Added functions for working with arrays: `concat`, `arraySlice`, `arrayPushBack`, `arrayPushFront`, `arrayPopBack`, `arrayPopFront`. * Added the `root` and `identity` parameters for the ZooKeeper configuration. This allows you to isolate individual users on the same ZooKeeper cluster. @@ -501,7 +501,7 @@ This release contains bug fixes for the previous release 1.1.54310: * Option to set `umask` in the config file. * Improved performance for queries with `DISTINCT`. -## Bug fixes: +### Bug fixes: * Improved the process for deleting old nodes in ZooKeeper. Previously, old nodes sometimes didn't get deleted if there were very frequent inserts, which caused the server to be slow to shut down, among other things. * Fixed randomization when choosing hosts for the connection to ZooKeeper. * Fixed the exclusion of lagging replicas in distributed queries if the replica is localhost. @@ -514,28 +514,28 @@ This release contains bug fixes for the previous release 1.1.54310: * Resolved the appearance of zombie processes when using a dictionary with an `executable` source. * Fixed segfault for the HEAD query. -## Improvements to development workflow and ClickHouse build: +### Improvements to development workflow and ClickHouse build: * You can use `pbuilder` to build ClickHouse. * You can use `libc++` instead of `libstdc++` for builds on Linux. * Added instructions for using static code analysis tools: `Coverity`, `clang-tidy`, and `cppcheck`. -## Please note when upgrading: +### Please note when upgrading: * There is now a higher default value for the MergeTree setting `max_bytes_to_merge_at_max_space_in_pool` (the maximum total size of data parts to merge, in bytes): it has increased from 100 GiB to 150 GiB. This might result in large merges running after the server upgrade, which could cause an increased load on the disk subsystem. If the free space available on the server is less than twice the total amount of the merges that are running, this will cause all other merges to stop running, including merges of small data parts. As a result, INSERT requests will fail with the message "Merges are processing significantly slower than inserts." Use the `SELECT * FROM system.merges` request to monitor the situation. You can also check the `DiskSpaceReservedForMerge` metric in the `system.metrics` table, or in Graphite. You don't need to do anything to fix this, since the issue will resolve itself once the large merges finish. If you find this unacceptable, you can restore the previous value for the `max_bytes_to_merge_at_max_space_in_pool` setting (to do this, go to the `` section in config.xml, set `107374182400` and restart the server). -# ClickHouse release 1.1.54284, 2017-08-29 +## ClickHouse release 1.1.54284, 2017-08-29 * This is bugfix release for previous 1.1.54282 release. It fixes ZooKeeper nodes leak in `parts/` directory. -# ClickHouse release 1.1.54282, 2017-08-23 +## ClickHouse release 1.1.54282, 2017-08-23 This is a bugfix release. The following bugs were fixed: * `DB::Exception: Assertion violation: !_path.empty()` error when inserting into a Distributed table. * Error when parsing inserted data in RowBinary format if the data begins with ';' character. * Errors during runtime compilation of certain aggregate functions (e.g. `groupArray()`). -# ClickHouse release 1.1.54276, 2017-08-16 +## ClickHouse release 1.1.54276, 2017-08-16 -## New features: +### New features: * You can use an optional WITH clause in a SELECT query. Example query: `WITH 1+1 AS a SELECT a, a*a` * INSERT can be performed synchronously in a Distributed table: OK is returned only after all the data is saved on all the shards. This is activated by the setting insert_distributed_sync=1. @@ -546,7 +546,7 @@ This is a bugfix release. The following bugs were fixed: * Added support for non-constant arguments and negative offsets in the function `substring(str, pos, len).` * Added the max_size parameter for the `groupArray(max_size)(column)` aggregate function, and optimized its performance. -## Major changes: +### Major changes: * Improved security: all server files are created with 0640 permissions (can be changed via config parameter). * Improved error messages for queries with invalid syntax. @@ -554,11 +554,11 @@ This is a bugfix release. The following bugs were fixed: * Significantly increased the performance of data merges for the ReplacingMergeTree engine. * Improved performance for asynchronous inserts from a Distributed table by batching multiple source inserts. To enable this functionality, use the setting distributed_directory_monitor_batch_inserts=1. -## Backward incompatible changes: +### Backward incompatible changes: * Changed the binary format of aggregate states of `groupArray(array_column)` functions for arrays. -## Complete list of changes: +### Complete list of changes: * Added the `output_format_json_quote_denormals` setting, which enables outputting nan and inf values in JSON format. * Optimized thread allocation when reading from a Distributed table. @@ -577,7 +577,7 @@ This is a bugfix release. The following bugs were fixed: * It is possible to connect to MySQL through a socket in the file system. * The `system.parts` table has a new column with information about the size of marks, in bytes. -## Bug fixes: +### Bug fixes: * Distributed tables using a Merge table now work correctly for a SELECT query with a condition on the _table field. * Fixed a rare race condition in ReplicatedMergeTree when checking data parts. @@ -601,15 +601,15 @@ This is a bugfix release. The following bugs were fixed: * Fixed the "Cannot mremap" error when using arrays in IN and JOIN clauses with more than 2 billion elements. * Fixed the failover for dictionaries with MySQL as the source. -## Improved workflow for developing and assembling ClickHouse: +### Improved workflow for developing and assembling ClickHouse: * Builds can be assembled in Arcadia. * You can use gcc 7 to compile ClickHouse. * Parallel builds using ccache+distcc are faster now. -# ClickHouse release 1.1.54245, 2017-07-04 +## ClickHouse release 1.1.54245, 2017-07-04 -## New features: +### New features: * Distributed DDL (for example, `CREATE TABLE ON CLUSTER`). * The replicated request `ALTER TABLE CLEAR COLUMN IN PARTITION.` @@ -621,16 +621,16 @@ This is a bugfix release. The following bugs were fixed: * Sessions in the HTTP interface. * The OPTIMIZE query for a Replicated table can can run not only on the leader. -## Backward incompatible changes: +### Backward incompatible changes: * Removed SET GLOBAL. -## Minor changes: +### Minor changes: * If an alert is triggered, the full stack trace is printed into the log. * Relaxed the verification of the number of damaged or extra data parts at startup (there were too many false positives). -## Bug fixes: +### Bug fixes: * Fixed a bad connection "sticking" when inserting into a Distributed table. * GLOBAL IN now works for a query from a Merge table that looks at a Distributed table. diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index 2fe43529a5a..f679856c169 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -1,6 +1,6 @@ -# ClickHouse release 1.1.54388, 2018-06-28 +## ClickHouse release 1.1.54388, 2018-06-28 -## Новые возможности: +### Новые возможности: * Добавлена поддержка запроса `ALTER TABLE t DELETE WHERE` для реплицированных таблиц и таблица `system.mutations`. * Добавлена поддержка запроса `ALTER TABLE t [REPLACE|ATTACH] PARTITION` для *MergeTree-таблиц. * Добавлена поддержка запроса `TRUNCATE TABLE` ([Winter Zhang](https://github.com/yandex/ClickHouse/pull/2260)) @@ -17,11 +17,11 @@ * Добавлена настройка `date_time_input_format`. Если переключить эту настройку в значение `'best_effort'`, значения DateTime будут читаться в широком диапазоне форматов. * Добавлена утилита `clickhouse-obfuscator` для обфускации данных. Пример использования: публикация данных, используемых в тестах производительности. -## Экспериментальные возможности: +### Экспериментальные возможности: * Добавлена возможность вычислять аргументы функции `and` только там, где они нужны ([Анастасия Царькова](https://github.com/yandex/ClickHouse/pull/2272)) * Добавлена возможность JIT-компиляции в нативный код некоторых выражений ([pyos](https://github.com/yandex/ClickHouse/pull/2277)). -## Исправление ошибок: +### Исправление ошибок: * Исправлено появление дублей в запросе с `DISTINCT` и `ORDER BY`. * Запросы с `ARRAY JOIN` и `arrayFilter` раньше возвращали некорректный результат. * Исправлена ошибка при чтении столбца-массива из Nested-структуры ([#2066](https://github.com/yandex/ClickHouse/issues/2066)). @@ -42,7 +42,7 @@ * Исправлена SSRF в табличной функции remote(). * Исправлен выход из `clickhouse-client` в multiline-режиме ([#2510](https://github.com/yandex/ClickHouse/issues/2510)). -## Улучшения: +### Улучшения: * Фоновые задачи в реплицированных таблицах теперь выполняются не в отдельных потоках, а в пуле потоков ([Silviu Caragea](https://github.com/yandex/ClickHouse/pull/1722)) * Улучшена производительность разжатия LZ4. * Ускорен анализ запроса с большим числом JOIN-ов и подзапросов. @@ -54,7 +54,7 @@ * При расчёте количества доступных ядер CPU теперь учитываются ограничения cgroups ([Atri Sharma](https://github.com/yandex/ClickHouse/pull/2325)). * Добавлен chown директорий конфигов в конфигурационном файле systemd ([Михаил Ширяев](https://github.com/yandex/ClickHouse/pull/2421)). -## Изменения сборки: +### Изменения сборки: * Добавлена возможность сборки компилятором gcc8. * Добавлена возможность сборки llvm из submodule. * Используемая версия библиотеки librdkafka обновлена до v0.11.4. @@ -64,33 +64,33 @@ * Добавлена возможность использования библиотеки libtinfo вместо libtermcap ([Георгий Кондратьев](https://github.com/yandex/ClickHouse/pull/2519)). * Исправлен конфликт заголовочных файлов в Fedora Rawhide ([#2520](https://github.com/yandex/ClickHouse/issues/2520)). -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Убран escaping в форматах `Vertical` и `Pretty*`, удалён формат `VerticalRaw`. -# ClickHouse release 1.1.54385, 2018-06-01 -## Исправление ошибок: +## ClickHouse release 1.1.54385, 2018-06-01 +### Исправление ошибок: * Исправлена ошибка, которая в некоторых случаях приводила к блокировке операций с ZooKeeper. -# ClickHouse release 1.1.54383, 2018-05-22 -## Исправление ошибок: +## ClickHouse release 1.1.54383, 2018-05-22 +### Исправление ошибок: * Исправлена деградация скорости выполнения очереди репликации при большом количестве реплик -# ClickHouse release 1.1.54381, 2018-05-14 +## ClickHouse release 1.1.54381, 2018-05-14 -## Исправление ошибок: +### Исправление ошибок: * Исправлена ошибка, приводящая к "утеканию" метаданных в ZooKeeper при потере соединения с сервером ZooKeeper. -# ClickHouse release 1.1.54380, 2018-04-21 +## ClickHouse release 1.1.54380, 2018-04-21 -## Новые возможности: +### Новые возможности: * Добавлена табличная функция `file(path, format, structure)`. Пример, читающий байты из `/dev/urandom`: `ln -s /dev/urandom /var/lib/clickhouse/user_files/random` `clickhouse-client -q "SELECT * FROM file('random', 'RowBinary', 'd UInt8') LIMIT 10"`. -## Улучшения: +### Улучшения: * Добавлена возможность оборачивать подзапросы скобками `()` для повышения читаемости запросов. Например: `(SELECT 1) UNION ALL (SELECT 1)`. * Простые запросы `SELECT` из таблицы `system.processes` не учитываются в ограничении `max_concurrent_queries`. -## Исправление ошибок: +### Исправление ошибок: * Исправлена неправильная работа оператора `IN` в `MATERIALIZED VIEW`. * Исправлена неправильная работа индекса по ключу партиционирования в выражениях типа `partition_key_column IN (...)`. * Исправлена невозможность выполнить `OPTIMIZE` запрос на лидирующей реплике после выполнения `RENAME` таблицы. @@ -98,13 +98,13 @@ * Исправлены зависания запросов `KILL QUERY`. * Исправлена ошибка в клиентской библиотеке ZooKeeper, которая при использовании непустого префикса `chroot` в конфигурации приводила к потере watch'ей, остановке очереди distributed DDL запросов и замедлению репликации. -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Убрана поддержка выражений типа `(a, b) IN (SELECT (a, b))` (можно использовать эквивалентные выражение `(a, b) IN (SELECT a, b)`). Раньше такие запросы могли приводить к недетерминированной фильтрации в `WHERE`. -# ClickHouse release 1.1.54378, 2018-04-16 +## ClickHouse release 1.1.54378, 2018-04-16 -## Новые возможности: +### Новые возможности: * Возможность изменения уровня логгирования без перезагрузки сервера. * Добавлен запрос `SHOW CREATE DATABASE`. @@ -118,7 +118,7 @@ * Возможность указания нескольких `topics` через запятую для движка `Kafka` (Tobias Adamson) * При остановке запроса по причине `KILL QUERY` или `replace_running_query`, клиент получает исключение `Query was cancelled` вместо неполного результата. -## Улучшения: +### Улучшения: * Запросы вида `ALTER TABLE ... DROP/DETACH PARTITION` выполняются впереди очереди репликации. * Возможность использовать `SELECT ... FINAL` и `OPTIMIZE ... FINAL` даже в случае, если данные в таблице представлены одним куском. @@ -129,7 +129,7 @@ * Более надёжное восстановление после сбоев при асинхронной вставке в `Distributed` таблицы. * Возвращаемый тип функции `countEqual` изменён с `UInt32` на `UInt64` (谢磊) -## Исправление ошибок: +### Исправление ошибок: * Исправлена ошибка c `IN` где левая часть выражения `Nullable`. * Исправлен неправильный результат при использовании кортежей с `IN` в случае, если часть компоненнтов кортежа есть в индексе таблицы. @@ -145,31 +145,31 @@ * Исправлена работа `SummingMergeTree` в случае суммирования вложенных структур данных с составным ключом. * Исправлена возможность возникновения race condition при выборе лидера таблиц `ReplicatedMergeTree`. -## Изменения сборки: +### Изменения сборки: * Поддержка `ninja` вместо `make` при сборке. `ninja` используется по-умолчанию при сборке релизов. * Переименованы пакеты `clickhouse-server-base` в `clickhouse-common-static`; `clickhouse-server-common` в `clickhouse-server`; `clickhouse-common-dbg` в `clickhouse-common-static-dbg`. Для установки используйте `clickhouse-server clickhouse-client`. Для совместимости, пакеты со старыми именами продолжают загружаться в репозиторий. -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Удалена специальная интерпретация выражения IN, если слева указан массив. Ранее выражение вида `arr IN (set)` воспринималось как "хотя бы один элемент `arr` принадлежит множеству `set`". Для получения такого же поведения в новой версии, напишите `arrayExists(x -> x IN (set), arr)`. * Отключено ошибочное использование опции сокета `SO_REUSEPORT` (которая по ошибке включена по-умолчанию в библиотеке Poco). Стоит обратить внимание, что на Linux системах теперь не имеет смысла указывать одновременно адреса `::` и `0.0.0.0` для listen - следует использовать лишь адрес `::`, который (с настройками ядра по-умолчанию) позволяет слушать соединения как по IPv4 так и по IPv6. Также вы можете вернуть поведение старых версий, указав в конфиге `1`. -# ClickHouse release 1.1.54370, 2018-03-16 +## ClickHouse release 1.1.54370, 2018-03-16 -## Новые возможности: +### Новые возможности: * Добавлена системная таблица `system.macros` и автоматическое обновление макросов при изменении конфигурационного файла. * Добавлен запрос `SYSTEM RELOAD CONFIG`. * Добавлена агрегатная функция `maxIntersections(left_col, right_col)`, возвращающая максимальное количество одновременно пересекающихся интервалов `[left; right]`. Функция `maxIntersectionsPosition(left, right)` возвращает начало такого "максимального" интервала. ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2012)). -## Улучшения: +### Улучшения: * При вставке данных в `Replicated`-таблицу делается меньше обращений к `ZooKeeper` (также из лога `ZooKeeper` исчезло большинство user-level ошибок). * Добавлена возможность создавать алиасы для множеств. Пример: `WITH (1, 2, 3) AS set SELECT number IN set FROM system.numbers LIMIT 10`. -## Исправление ошибок: +### Исправление ошибок: * Исправлена ошибка `Illegal PREWHERE` при чтении из Merge-таблицы над `Distributed`-таблицами. * Добавлены исправления, позволяющие запускать clickhouse-server в IPv4-only docker-контейнерах. @@ -184,9 +184,9 @@ * Устранено ненужное Error-level логирование `Not found column ... in block`. -# Релиз ClickHouse 1.1.54362, 2018-03-11 +## Релиз ClickHouse 1.1.54362, 2018-03-11 -## Новые возможности: +### Новые возможности: * Агрегация без `GROUP BY` по пустому множеству (как например, `SELECT count(*) FROM table WHERE 0`) теперь возвращает результат из одной строки с нулевыми значениями агрегатных функций, в соответствии со стандартом SQL. Вы можете вернуть старое поведение (возвращать пустой результат), выставив настройку `empty_result_for_aggregation_by_empty_set` в значение 1. * Добавлено приведение типов при `UNION ALL`. Допустимо использование столбцов с разными алиасами в соответствующих позициях `SELECT` в `UNION ALL`, что соответствует стандарту SQL. @@ -224,7 +224,7 @@ * Добавлена настройка `odbc_default_field_size`, позволяющая расширить максимальный размер значения, загружаемого из ODBC источника (по-умолчанию - 1024). * В таблицу `system.processes` и в `SHOW PROCESSLIST` добавлены столбцы `is_cancelled` и `peak_memory_usage`. -## Улучшения: +### Улучшения: * Ограничения на результат и квоты на результат теперь не применяются к промежуточным данным для запросов `INSERT SELECT` и для подзапросов в `SELECT`. * Уменьшено количество ложных срабатываний при проверке состояния `Replicated` таблиц при запуске сервера, приводивших к необходимости выставления флага `force_restore_data`. @@ -240,7 +240,7 @@ * Значения типа `Enum` можно использовать в функциях `min`, `max`, `sum` и некоторых других - в этих случаях используются соответствующие числовые значения. Эта возможность присутствовала ранее, но была потеряна в релизе 1.1.54337. * Добавлено ограничение `max_expanded_ast_elements` действующее на размер AST после рекурсивного раскрытия алиасов. -## Исправление ошибок: +### Исправление ошибок: * Исправлены случаи ошибочного удаления ненужных столбцов из подзапросов, а также отсутствие удаления ненужных столбцов из подзапросов, содержащих `UNION ALL`. * Исправлена ошибка в слияниях для таблиц типа `ReplacingMergeTree`. @@ -268,19 +268,19 @@ * Запрещено использование запросов с `UNION ALL` в `MATERIALIZED VIEW`. * Исправлена ошибка, которая может возникать при инициализации системной таблицы `part_log` при старте сервера (по-умолчанию `part_log` выключен). -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Удалена настройка `distributed_ddl_allow_replicated_alter`. Соответствующее поведение включено по-умолчанию. * Удалена настройка `strict_insert_defaults`. Если вы использовали эту функциональность, напишите на `clickhouse-feedback@yandex-team.com`. * Удалён движок таблиц `UnsortedMergeTree`. -# Релиз ClickHouse 1.1.54343, 2018-02-05 +## Релиз ClickHouse 1.1.54343, 2018-02-05 * Добавлена возможность использовать макросы при задании имени кластера в распределенных DLL запросах и создании Distributed-таблиц: `CREATE TABLE distr ON CLUSTER '{cluster}' (...) ENGINE = Distributed('{cluster}', 'db', 'table')`. * Теперь при вычислении запросов вида `SELECT ... FROM table WHERE expr IN (subquery)` используется индекс таблицы `table`. * Улучшена обработка дубликатов при вставке в Replicated-таблицы, теперь они не приводят к излишнему замедлению выполнения очереди репликации. -# Релиз ClickHouse 1.1.54342, 2018-01-22 +## Релиз ClickHouse 1.1.54342, 2018-01-22 Релиз содержит исправление к предыдущему релизу 1.1.54337: * Исправлена регрессия в версии 1.1.54337: если пользователь по-умолчанию имеет readonly доступ, то сервер отказывался стартовать с сообщением `Cannot create database in readonly mode`. @@ -291,9 +291,9 @@ * Таблицы типа Buffer теперь работают при наличии MATERIALIZED столбцов в таблице назначения (by zhang2014). * Исправлена одна из ошибок в реализации NULL. -# Релиз ClickHouse 1.1.54337, 2018-01-18 +## Релиз ClickHouse 1.1.54337, 2018-01-18 -## Новые возможности: +### Новые возможности: * Добавлена поддержка хранения многомерных массивов и кортежей (тип данных `Tuple`) в таблицах. * Поддержка табличных функций для запросов `DESCRIBE` и `INSERT`. Поддержка подзапроса в запросе `DESCRIBE`. Примеры: `DESC TABLE remote('host', default.hits)`; `DESC TABLE (SELECT 1)`; `INSERT INTO TABLE FUNCTION remote('host', default.hits)`. Возможность писать `INSERT INTO TABLE` вместо `INSERT INTO`. @@ -324,7 +324,7 @@ * Для программы `clickhouse-local` добавлена опция `--silent` для подавления вывода информации о выполнении запроса в stderr. * Добавлена поддержка чтения `Date` в текстовом виде в формате, где месяц и день месяца могут быть указаны одной цифрой вместо двух (Amos Bird). -## Увеличение производительности: +### Увеличение производительности: * Увеличена производительность агрегатных функций `min`, `max`, `any`, `anyLast`, `anyHeavy`, `argMin`, `argMax` от строковых аргументов. * Увеличена производительность функций `isInfinite`, `isFinite`, `isNaN`, `roundToExp2`. @@ -333,7 +333,7 @@ * Уменьшено потребление памяти при `JOIN`, если левая и правая часть содержали столбцы с одинаковым именем, не входящие в `USING`. * Увеличена производительность агрегатных функций `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, `corr` за счёт уменьшения стойкости к вычислительной погрешности. Старые версии функций добавлены под именами `varSampStable`, `varPopStable`, `stddevSampStable`, `stddevPopStable`, `covarSampStable`, `covarPopStable`, `corrStable`. -## Исправления ошибок: +### Исправления ошибок: * Исправлена работа дедупликации блоков после `DROP` или `DETATH PARTITION`. Раньше удаление партиции и вставка тех же самых данных заново не работала, так как вставленные заново блоки считались дубликатами. * Исправлена ошибка, в связи с которой может неправильно обрабатываться `WHERE` для запросов на создание `MATERIALIZED VIEW` с указанием `POPULATE`. @@ -372,7 +372,7 @@ * Исправлена работа запроса `SYSTEM DROP DNS CACHE`: ранее сброс DNS кэша не приводил к повторному резолвингу имён хостов кластера. * Исправлено поведение `MATERIALIZED VIEW` после `DETACH TABLE` таблицы, на которую он смотрит (Marek Vavruša). -## Улучшения сборки: +### Улучшения сборки: * Для сборки используется `pbuilder`. Сборка максимально независима от окружения на сборочной машине. * Для разных версий систем выкладывается один и тот же пакет, который совместим с широким диапазоном Linux систем. @@ -386,7 +386,7 @@ * Удалено использование расширений GNU из кода и включена опция `-Wextra`. При сборке с помощью `clang` по-умолчанию используется `libc++` вместо `libstdc++`. * Выделены библиотеки `clickhouse_parsers` и `clickhouse_common_io` для более быстрой сборки утилит. -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Формат засечек (marks) для таблиц типа `Log`, содержащих `Nullable` столбцы, изменён обратно-несовместимым образом. В случае наличия таких таблиц, вы можете преобразовать их в `TinyLog` до запуска новой версии сервера. Для этого в соответствующем таблице файле `.sql` в директории `metadata`, замените `ENGINE = Log` на `ENGINE = TinyLog`. Если в таблице нет `Nullable` столбцов или тип таблицы не `Log`, то ничего делать не нужно. * Удалена настройка `experimental_allow_extended_storage_definition_syntax`. Соответствующая функциональность включена по-умолчанию. @@ -397,16 +397,16 @@ * В предыдущих версиях существовала недокументированная возможность: в типе данных AggregateFunction можно было не указывать параметры для агрегатной функции, которая зависит от параметров. Пример: `AggregateFunction(quantiles, UInt64)` вместо `AggregateFunction(quantiles(0.5, 0.9), UInt64)`. Эта возможность потеряна. Не смотря на то, что возможность не документирована, мы собираемся вернуть её в ближайших релизах. * Значения типа данных Enum не могут быть переданы в агрегатные функции min/max. Возможность будет возвращена обратно в следующем релизе. -## На что обратить внимание при обновлении: +### На что обратить внимание при обновлении: * При обновлении кластера, на время, когда на одних репликах работает новая версия сервера, а на других - старая, репликация будет приостановлена и в логе появятся сообщения вида `unknown parameter 'shard'`. Репликация продолжится после обновления всех реплик кластера. * Если на серверах кластера работают разные версии ClickHouse, то возможен неправильный результат распределённых запросов, использующих функции `varSamp`, `varPop`, `stddevSamp`, `stddevPop`, `covarSamp`, `covarPop`, `corr`. Необходимо обновить все серверы кластера. -# Релиз ClickHouse 1.1.54327, 2017-12-21 +## Релиз ClickHouse 1.1.54327, 2017-12-21 Релиз содержит исправление к предыдущему релизу 1.1.54318: * Исправлена проблема с возможным race condition при репликации, которая может приводить к потере данных. Проблеме подвержены версии 1.1.54310 и 1.1.54318. Если вы их используете и у вас есть Replicated таблицы, то обновление обязательно. Понять, что эта проблема существует, можно по сообщениям в логе Warning вида `Part ... from own log doesn't exist.` Даже если таких сообщений нет, проблема всё-равно актуальна. -# Релиз ClickHouse 1.1.54318, 2017-11-30 +## Релиз ClickHouse 1.1.54318, 2017-11-30 Релиз содержит изменения к предыдущему релизу 1.1.54310 с исправлением следующих багов: * Исправлено некорректное удаление строк при слияниях в движке SummingMergeTree @@ -415,9 +415,9 @@ * Исправлена проблема, приводящая к остановке выполнения очереди репликации * Исправлено ротирование и архивация логов сервера -# Релиз ClickHouse 1.1.54310, 2017-11-01 +## Релиз ClickHouse 1.1.54310, 2017-11-01 -## Новые возможности: +### Новые возможности: * Произвольный ключ партиционирования для таблиц семейства MergeTree. * Движок таблиц [Kafka](https://clickhouse.yandex/docs/en/single/index.html#document-table_engines/kafka). * Возможность загружать модели [CatBoost](https://catboost.yandex/) и применять их к данным, хранящимся в ClickHouse. @@ -433,12 +433,12 @@ * Поддержка входного формата Cap’n Proto. * Возможность задавать уровень сжатия при использовании алгоритма zstd. -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Запрещено создание временных таблиц с движком, отличным от Memory. * Запрещено явное создание таблиц с движком View и MaterializedView. * При создании таблицы теперь проверяется, что ключ сэмплирования входит в первичный ключ. -## Исправления ошибок: +### Исправления ошибок: * Исправлено зависание при синхронной вставке в Distributed таблицу. * Исправлена неатомарность при добавлении/удалении кусков в реплицированных таблицах. * Данные, вставляемые в материализованное представление, теперь не подвергаются излишней дедупликации. @@ -448,14 +448,14 @@ * Исправлено зависание при недостатке места на диске в разделе с логами. * Исправлено переполнение в функции toRelativeWeekNum для первой недели Unix-эпохи. -## Улучшения сборки: +### Улучшения сборки: * Несколько сторонних библиотек (в частности, Poco) обновлены и переведены на git submodules. -# Релиз ClickHouse 1.1.54304, 2017-10-19 -## Новые возможности: +## Релиз ClickHouse 1.1.54304, 2017-10-19 +### Новые возможности: * Добавлена поддержка TLS в нативном протоколе (включается заданием `tcp_ssl_port` в `config.xml`) -## Исправления ошибок: +### Исправления ошибок: * `ALTER` для реплицированных таблиц теперь пытается начать выполнение как можно быстрее * Исправлены падения при чтении данных с настройкой `preferred_block_size_bytes=0` * Исправлено падение `clickhouse-client` при нажатии `Page Down` @@ -468,16 +468,16 @@ * Корректное обновление пользователей при невалидном `users.xml` * Корректная обработка случаев, когда executable-словарь возвращает ненулевой код ответа -# Релиз ClickHouse 1.1.54292, 2017-09-20 +## Релиз ClickHouse 1.1.54292, 2017-09-20 -## Новые возможности: +### Новые возможности: * Добавлена функция `pointInPolygon` для работы с координатами на плоскости. * Добавлена агрегатная функция `sumMap`, обеспечивающая суммирование массивов аналогично `SummingMergeTree`. * Добавлена функция `trunc`. Увеличена производительность функций округления `round`, `floor`, `ceil`, `roundToExp2`. Исправлена логика работы функций округления. Изменена логика работы функции `roundToExp2` для дробных и отрицательных чисел. * Ослаблена зависимость исполняемого файла ClickHouse от версии libc. Один и тот же исполняемый файл ClickHouse может запускаться и работать на широком множестве Linux систем. Замечание: зависимость всё ещё присутствует при использовании скомпилированных запросов (настройка `compile = 1`, по-умолчанию не используется). * Уменьшено время динамической компиляции запросов. -## Исправления ошибок: +### Исправления ошибок: * Исправлена ошибка, которая могла приводить к сообщениям `part ... intersects previous part` и нарушению консистентности реплик. * Исправлена ошибка, приводящая к блокировке при завершении работы сервера, если в это время ZooKeeper недоступен. * Удалено избыточное логгирование при восстановлении реплик. @@ -485,9 +485,9 @@ * Исправлена ошибка в функции concat, возникающая в случае, если первый столбец блока имеет тип Array. * Исправлено отображение прогресса в таблице system.merges. -# Релиз ClickHouse 1.1.54289, 2017-09-13 +## Релиз ClickHouse 1.1.54289, 2017-09-13 -## Новые возможности: +### Новые возможности: * Запросы `SYSTEM` для административных действий с сервером: `SYSTEM RELOAD DICTIONARY`, `SYSTEM RELOAD DICTIONARIES`, `SYSTEM DROP DNS CACHE`, `SYSTEM SHUTDOWN`, `SYSTEM KILL`. * Добавлены функции для работы с массивами: `concat`, `arraySlice`, `arrayPushBack`, `arrayPushFront`, `arrayPopBack`, `arrayPopFront`. * Добавлены параметры `root` и `identity` для конфигурации ZooKeeper. Это позволяет изолировать разных пользователей одного ZooKeeper кластера. @@ -502,7 +502,7 @@ * Возможность задать `umask` в конфигурационном файле. * Увеличена производительность запросов с `DISTINCT`. -## Исправления ошибок: +### Исправления ошибок: * Более оптимальная процедура удаления старых нод в ZooKeeper. Ранее в случае очень частых вставок, старые ноды могли не успевать удаляться, что приводило, в том числе, к очень долгому завершению сервера. * Исправлена рандомизация при выборе хостов для соединения с ZooKeeper. * Исправлено отключение отстающей реплики при распределённых запросах, если реплика является localhost. @@ -515,28 +515,28 @@ * Исправлено появление zombie процессов при работе со словарём с источником `executable`. * Исправлен segfault при запросе HEAD. -## Улучшения процесса разработки и сборки ClickHouse: +### Улучшения процесса разработки и сборки ClickHouse: * Возможность сборки с помощью `pbuilder`. * Возможность сборки с использованием `libc++` вместо `libstdc++` под Linux. * Добавлены инструкции для использования статических анализаторов кода `Coverity`, `clang-tidy`, `cppcheck`. -## На что обратить внимание при обновлении: +### На что обратить внимание при обновлении: * Увеличено значение по-умолчанию для настройки MergeTree `max_bytes_to_merge_at_max_space_in_pool` (максимальный суммарный размер кусков в байтах для мержа) со 100 GiB до 150 GiB. Это может привести к запуску больших мержей после обновления сервера, что может вызвать повышенную нагрузку на дисковую подсистему. Если же на серверах, где это происходит, количество свободного места менее чем в два раза больше суммарного объёма выполняющихся мержей, то в связи с этим перестанут выполняться какие-либо другие мержи, включая мержи мелких кусков. Это приведёт к тому, что INSERT-ы будут отклоняться с сообщением "Merges are processing significantly slower than inserts". Для наблюдения, используйте запрос `SELECT * FROM system.merges`. Вы также можете смотреть на метрику `DiskSpaceReservedForMerge` в таблице `system.metrics` или в Graphite. Для исправления этой ситуации можно ничего не делать, так как она нормализуется сама после завершения больших мержей. Если же вас это не устраивает, вы можете вернуть настройку `max_bytes_to_merge_at_max_space_in_pool` в старое значение, прописав в config.xml в секции `` `107374182400` и перезапустить сервер. -# Релиз ClickHouse 1.1.54284, 2017-08-29 +## Релиз ClickHouse 1.1.54284, 2017-08-29 * Релиз содержит изменения к предыдущему релизу 1.1.54282, которые исправляют утечку записей о кусках в ZooKeeper -# Релиз ClickHouse 1.1.54282, 2017-08-23 +## Релиз ClickHouse 1.1.54282, 2017-08-23 Релиз содержит исправления к предыдущему релизу 1.1.54276: * Исправлена ошибка `DB::Exception: Assertion violation: !_path.empty()` при вставке в Distributed таблицу. * Исправлен парсинг при вставке в формате RowBinary, если входные данные начинаются с ';'. * Исправлена ошибка при рантайм-компиляции некоторых агрегатных функций (например, `groupArray()`). -# Релиз ClickHouse 1.1.54276, 2017-08-16 +## Релиз ClickHouse 1.1.54276, 2017-08-16 -## Новые возможности: +### Новые возможности: * Добавлена опциональная секция WITH запроса SELECT. Пример запроса: `WITH 1+1 AS a SELECT a, a*a` * Добавлена возможность синхронной вставки в Distributed таблицу: выдается Ok только после того как все данные записались на все шарды. Активируется настройкой insert_distributed_sync=1 * Добавлен тип данных UUID для работы с 16-байтовыми идентификаторами @@ -546,17 +546,17 @@ * Добавлена поддержка неконстантных аргументов и отрицательных смещений в функции `substring(str, pos, len)` * Добавлен параметр max_size для агрегатной функции `groupArray(max_size)(column)`, и оптимизирована её производительность -## Основные изменения: +### Основные изменения: * Улучшение безопасности: все файлы сервера создаются с правами 0640 (можно поменять, через параметр в конфиге). * Улучшены сообщения об ошибках в случае синтаксически неверных запросов * Значительно уменьшен расход оперативной памяти и улучшена производительность слияний больших MergeTree-кусков данных * Значительно увеличена производительность слияний данных для движка ReplacingMergeTree * Улучшена производительность асинхронных вставок из Distributed таблицы за счет объединения нескольких исходных вставок. Функциональность включается настройкой distributed_directory_monitor_batch_inserts=1. -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Изменился бинарный формат агрегатных состояний функции `groupArray(array_column)` для массивов -## Полный список изменений: +### Полный список изменений: * Добавлена настройка `output_format_json_quote_denormals`, включающая вывод nan и inf значений в формате JSON * Более оптимальное выделение потоков при чтении из Distributed таблиц * Разрешено задавать настройки в режиме readonly, если их значение не изменяется @@ -574,7 +574,7 @@ * Возможность подключения к MySQL через сокет на файловой системе * В таблицу system.parts добавлен столбец с информацией о размере marks в байтах -## Исправления багов: +### Исправления багов: * Исправлена некорректная работа Distributed таблиц, использующих Merge таблицы, при SELECT с условием на поле _table * Исправлен редкий race condition в ReplicatedMergeTree при проверке кусков данных * Исправлено возможное зависание процедуры leader election при старте сервера @@ -597,15 +597,15 @@ * Исправлена ошибка "Cannot mremap" при использовании множеств в секциях IN, JOIN, содержащих более 2 млрд. элементов * Исправлен failover для словарей с источником MySQL -## Улучшения процесса разработки и сборки ClickHouse: +### Улучшения процесса разработки и сборки ClickHouse: * Добавлена возмозможность сборки в Arcadia * Добавлена возможность сборки с помощью gcc 7 * Ускорена параллельная сборка с помощью ccache+distcc -# Релиз ClickHouse 1.1.54245, 2017-07-04 +## Релиз ClickHouse 1.1.54245, 2017-07-04 -## Новые возможности: +### Новые возможности: * Распределённые DDL (например, `CREATE TABLE ON CLUSTER`) * Реплицируемый запрос `ALTER TABLE CLEAR COLUMN IN PARTITION` * Движок таблиц Dictionary (доступ к данным словаря в виде таблицы) @@ -616,14 +616,14 @@ * Сессии в HTTP интерфейсе * Запрос OPTIMIZE для Replicated таблицы теперь можно выполнять не только на лидере -## Обратно несовместимые изменения: +### Обратно несовместимые изменения: * Убрана команда SET GLOBAL -## Мелкие изменения: +### Мелкие изменения: * Теперь после получения сигнала в лог печатается полный стектрейс * Ослаблена проверка на количество повреждённых/лишних кусков при старте (было слишком много ложных срабатываний) -## Исправления багов: +### Исправления багов: * Исправлено залипание плохого соединения при вставке в Distributed таблицу * GLOBAL IN теперь работает при запросе из таблицы Merge, смотрящей в Distributed * Теперь правильно определяется количество ядер на виртуалках Google Compute Engine From a7dd87b4636a7600d07949837ae16ecaf748b6ce Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 08:08:39 +0300 Subject: [PATCH 022/425] Group up table engines inside ToC --- docs/mkdocs_en.yml | 52 +++++++++++++++++++++++++--------------------- docs/mkdocs_ru.yml | 52 +++++++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 976c6950554..d7931cf6d4b 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -57,30 +57,34 @@ pages: - 'Table engines': - 'Introduction': 'table_engines/index.md' - - 'TinyLog': 'table_engines/tinylog.md' - - 'Log': 'table_engines/log.md' - - 'Memory': 'table_engines/memory.md' - - 'MergeTree': 'table_engines/mergetree.md' - - 'Custom partitioning key': 'table_engines/custom_partitioning_key.md' - - 'ReplacingMergeTree': 'table_engines/replacingmergetree.md' - - 'SummingMergeTree': 'table_engines/summingmergetree.md' - - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' - - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' - - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' - - 'Data replication': 'table_engines/replication.md' - - 'Distributed': 'table_engines/distributed.md' - - 'Dictionary': 'table_engines/dictionary.md' - - 'Merge': 'table_engines/merge.md' - - 'Buffer': 'table_engines/buffer.md' - - 'File': 'table_engines/file.md' - - 'Null': 'table_engines/null.md' - - 'Set': 'table_engines/set.md' - - 'Join': 'table_engines/join.md' - - 'View': 'table_engines/view.md' - - 'MaterializedView': 'table_engines/materializedview.md' - - 'Kafka': 'table_engines/kafka.md' - - 'MySQL': 'table_engines/mysql.md' - - 'External data for query processing': 'table_engines/external_data.md' + - 'MergeTree family': + - 'MergeTree': 'table_engines/mergetree.md' + - 'Data replication': 'table_engines/replication.md' + - 'Custom partitioning key': 'table_engines/custom_partitioning_key.md' + - 'ReplacingMergeTree': 'table_engines/replacingmergetree.md' + - 'SummingMergeTree': 'table_engines/summingmergetree.md' + - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' + - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' + - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' + - 'For small data': + - 'TinyLog': 'table_engines/tinylog.md' + - 'Log': 'table_engines/log.md' + - 'Memory': 'table_engines/memory.md' + - 'Buffer': 'table_engines/buffer.md' + - 'External data': 'table_engines/external_data.md' + - 'Special': + - 'Distributed': 'table_engines/distributed.md' + - 'Dictionary': 'table_engines/dictionary.md' + - 'Merge': 'table_engines/merge.md' + - 'File': 'table_engines/file.md' + - 'Null': 'table_engines/null.md' + - 'Set': 'table_engines/set.md' + - 'Join': 'table_engines/join.md' + - 'View': 'table_engines/view.md' + - 'MaterializedView': 'table_engines/materializedview.md' + - 'Integrations': + - 'Kafka': 'table_engines/kafka.md' + - 'MySQL': 'table_engines/mysql.md' - 'Table functions': - 'Introduction': 'table_functions/index.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index a0f77f0d5a1..f406522edaa 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -57,30 +57,34 @@ pages: - 'Движки таблиц': - 'Введение': 'table_engines/index.md' - - 'TinyLog': 'table_engines/tinylog.md' - - 'Log': 'table_engines/log.md' - - 'Memory': 'table_engines/memory.md' - - 'MergeTree': 'table_engines/mergetree.md' - - 'Произвольный ключ партиционирования': 'table_engines/custom_partitioning_key.md' - - 'ReplacingMergeTree': 'table_engines/replacingmergetree.md' - - 'SummingMergeTree': 'table_engines/summingmergetree.md' - - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' - - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' - - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' - - 'Репликация данных': 'table_engines/replication.md' - - 'Distributed': 'table_engines/distributed.md' - - 'Dictionary': 'table_engines/dictionary.md' - - 'Merge': 'table_engines/merge.md' - - 'Buffer': 'table_engines/buffer.md' - - 'File': 'table_engines/file.md' - - 'Null': 'table_engines/null.md' - - 'Set': 'table_engines/set.md' - - 'Join': 'table_engines/join.md' - - 'View': 'table_engines/view.md' - - 'MaterializedView': 'table_engines/materializedview.md' - - 'Kafka': 'table_engines/kafka.md' - - 'MySQL': 'table_engines/mysql.md' - - 'Внешние данные для обработки запроса': 'table_engines/external_data.md' + - 'Семейство MergeTree': + - 'MergeTree': 'table_engines/mergetree.md' + - 'Репликация данных': 'table_engines/replication.md' + - 'Произвольный ключ партиционирования': 'table_engines/custom_partitioning_key.md' + - 'ReplacingMergeTree': 'table_engines/replacingmergetree.md' + - 'SummingMergeTree': 'table_engines/summingmergetree.md' + - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' + - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' + - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' + - 'Для небольших объемов данных': + - 'TinyLog': 'table_engines/tinylog.md' + - 'Log': 'table_engines/log.md' + - 'Memory': 'table_engines/memory.md' + - 'Buffer': 'table_engines/buffer.md' + - 'Внешние данные': 'table_engines/external_data.md' + - 'Особые': + - 'Distributed': 'table_engines/distributed.md' + - 'Dictionary': 'table_engines/dictionary.md' + - 'Merge': 'table_engines/merge.md' + - 'File': 'table_engines/file.md' + - 'Null': 'table_engines/null.md' + - 'Set': 'table_engines/set.md' + - 'Join': 'table_engines/join.md' + - 'View': 'table_engines/view.md' + - 'MaterializedView': 'table_engines/materializedview.md' + - 'Интеграции': + - 'Kafka': 'table_engines/kafka.md' + - 'MySQL': 'table_engines/mysql.md' - 'Табличные функции': - 'Введение': 'table_functions/index.md' From fd747ddafab05eb1e5360710416a0f0287614211 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 08:27:08 +0300 Subject: [PATCH 023/425] Move table engines out of top level too --- docs/en/dicts/external_dicts_dict_sources.md | 2 +- docs/en/introduction/distinctive_features.md | 2 +- docs/en/operations/access_rights.md | 2 +- .../en/operations/server_settings/settings.md | 22 +++---- docs/en/operations/settings/settings.md | 10 +-- docs/en/operations/system_tables.md | 2 +- .../table_engines/aggregatingmergetree.md | 0 .../{ => operations}/table_engines/buffer.md | 0 .../table_engines/collapsingmergetree.md | 0 .../table_engines/custom_partitioning_key.md | 0 .../table_engines/dictionary.md | 2 +- .../table_engines/distributed.md | 0 .../table_engines/external_data.md | 0 .../en/{ => operations}/table_engines/file.md | 8 +-- .../table_engines/graphitemergetree.md | 2 +- .../{ => operations}/table_engines/index.md | 0 .../en/{ => operations}/table_engines/join.md | 0 .../{ => operations}/table_engines/kafka.md | 2 +- docs/en/{ => operations}/table_engines/log.md | 0 .../table_engines/materializedview.md | 4 ++ .../{ => operations}/table_engines/memory.md | 0 .../{ => operations}/table_engines/merge.md | 0 .../table_engines/mergetree.md | 2 +- .../{ => operations}/table_engines/mysql.md | 0 .../en/{ => operations}/table_engines/null.md | 0 .../table_engines/replacingmergetree.md | 0 .../table_engines/replication.md | 6 +- docs/en/{ => operations}/table_engines/set.md | 0 .../table_engines/summingmergetree.md | 0 .../{ => operations}/table_engines/tinylog.md | 0 .../en/{ => operations}/table_engines/view.md | 0 docs/en/table_engines/materializedview.md | 4 -- docs/mkdocs_en.yml | 61 +++++++++---------- docs/mkdocs_ru.yml | 61 +++++++++---------- docs/redirects.txt | 26 ++++++++ docs/ru/dicts/external_dicts_dict_sources.md | 2 +- docs/ru/introduction/distinctive_features.md | 2 +- docs/ru/operations/access_rights.md | 2 +- .../ru/operations/server_settings/settings.md | 22 +++---- docs/ru/operations/settings/settings.md | 10 +-- docs/ru/operations/system_tables.md | 2 +- .../table_engines/aggregatingmergetree.md | 0 .../{ => operations}/table_engines/buffer.md | 0 .../table_engines/collapsingmergetree.md | 0 .../table_engines/custom_partitioning_key.md | 0 .../table_engines/dictionary.md | 2 +- .../table_engines/distributed.md | 0 .../table_engines/external_data.md | 0 .../ru/{ => operations}/table_engines/file.md | 8 +-- .../table_engines/graphitemergetree.md | 2 +- .../{ => operations}/table_engines/index.md | 0 .../ru/{ => operations}/table_engines/join.md | 0 .../{ => operations}/table_engines/kafka.md | 4 +- docs/ru/{ => operations}/table_engines/log.md | 0 .../table_engines/materializedview.md | 3 + .../{ => operations}/table_engines/memory.md | 0 .../{ => operations}/table_engines/merge.md | 0 .../table_engines/mergetree.md | 2 +- .../{ => operations}/table_engines/mysql.md | 0 .../ru/{ => operations}/table_engines/null.md | 0 .../table_engines/replacingmergetree.md | 0 .../table_engines/replication.md | 6 +- docs/ru/{ => operations}/table_engines/set.md | 0 .../table_engines/summingmergetree.md | 0 .../{ => operations}/table_engines/tinylog.md | 0 .../ru/{ => operations}/table_engines/view.md | 0 docs/ru/table_engines/materializedview.md | 3 - 67 files changed, 156 insertions(+), 132 deletions(-) rename docs/en/{ => operations}/table_engines/aggregatingmergetree.md (100%) rename docs/en/{ => operations}/table_engines/buffer.md (100%) rename docs/en/{ => operations}/table_engines/collapsingmergetree.md (100%) rename docs/en/{ => operations}/table_engines/custom_partitioning_key.md (100%) rename docs/en/{ => operations}/table_engines/dictionary.md (95%) rename docs/en/{ => operations}/table_engines/distributed.md (100%) rename docs/en/{ => operations}/table_engines/external_data.md (100%) rename docs/en/{ => operations}/table_engines/file.md (75%) rename docs/en/{ => operations}/table_engines/graphitemergetree.md (93%) rename docs/en/{ => operations}/table_engines/index.md (100%) rename docs/en/{ => operations}/table_engines/join.md (100%) rename docs/en/{ => operations}/table_engines/kafka.md (93%) rename docs/en/{ => operations}/table_engines/log.md (100%) create mode 100644 docs/en/operations/table_engines/materializedview.md rename docs/en/{ => operations}/table_engines/memory.md (100%) rename docs/en/{ => operations}/table_engines/merge.md (100%) rename docs/en/{ => operations}/table_engines/mergetree.md (96%) rename docs/en/{ => operations}/table_engines/mysql.md (100%) rename docs/en/{ => operations}/table_engines/null.md (100%) rename docs/en/{ => operations}/table_engines/replacingmergetree.md (100%) rename docs/en/{ => operations}/table_engines/replication.md (96%) rename docs/en/{ => operations}/table_engines/set.md (100%) rename docs/en/{ => operations}/table_engines/summingmergetree.md (100%) rename docs/en/{ => operations}/table_engines/tinylog.md (100%) rename docs/en/{ => operations}/table_engines/view.md (100%) delete mode 100644 docs/en/table_engines/materializedview.md rename docs/ru/{ => operations}/table_engines/aggregatingmergetree.md (100%) rename docs/ru/{ => operations}/table_engines/buffer.md (100%) rename docs/ru/{ => operations}/table_engines/collapsingmergetree.md (100%) rename docs/ru/{ => operations}/table_engines/custom_partitioning_key.md (100%) rename docs/ru/{ => operations}/table_engines/dictionary.md (98%) rename docs/ru/{ => operations}/table_engines/distributed.md (100%) rename docs/ru/{ => operations}/table_engines/external_data.md (100%) rename docs/ru/{ => operations}/table_engines/file.md (79%) rename docs/ru/{ => operations}/table_engines/graphitemergetree.md (95%) rename docs/ru/{ => operations}/table_engines/index.md (100%) rename docs/ru/{ => operations}/table_engines/join.md (100%) rename docs/ru/{ => operations}/table_engines/kafka.md (94%) rename docs/ru/{ => operations}/table_engines/log.md (100%) create mode 100644 docs/ru/operations/table_engines/materializedview.md rename docs/ru/{ => operations}/table_engines/memory.md (100%) rename docs/ru/{ => operations}/table_engines/merge.md (100%) rename docs/ru/{ => operations}/table_engines/mergetree.md (98%) rename docs/ru/{ => operations}/table_engines/mysql.md (100%) rename docs/ru/{ => operations}/table_engines/null.md (100%) rename docs/ru/{ => operations}/table_engines/replacingmergetree.md (100%) rename docs/ru/{ => operations}/table_engines/replication.md (98%) rename docs/ru/{ => operations}/table_engines/set.md (100%) rename docs/ru/{ => operations}/table_engines/summingmergetree.md (100%) rename docs/ru/{ => operations}/table_engines/tinylog.md (100%) rename docs/ru/{ => operations}/table_engines/view.md (100%) delete mode 100644 docs/ru/table_engines/materializedview.md diff --git a/docs/en/dicts/external_dicts_dict_sources.md b/docs/en/dicts/external_dicts_dict_sources.md index 7779187d583..914729767ce 100644 --- a/docs/en/dicts/external_dicts_dict_sources.md +++ b/docs/en/dicts/external_dicts_dict_sources.md @@ -361,7 +361,7 @@ Example of settings: Setting fields: -- `host` – The ClickHouse host. If it is a local host, the query is processed without any network activity. To improve fault tolerance, you can create a [Distributed](../table_engines/distributed.md#table_engines-distributed) table and enter it in subsequent configurations. +- `host` – The ClickHouse host. If it is a local host, the query is processed without any network activity. To improve fault tolerance, you can create a [Distributed](../operations/table_engines/distributed.md#table_engines-distributed) table and enter it in subsequent configurations. - `port` – The port on the ClickHouse server. - `user` – Name of the ClickHouse user. - `password` – Password of the ClickHouse user. diff --git a/docs/en/introduction/distinctive_features.md b/docs/en/introduction/distinctive_features.md index 59853b8e202..f626f13c274 100644 --- a/docs/en/introduction/distinctive_features.md +++ b/docs/en/introduction/distinctive_features.md @@ -58,5 +58,5 @@ This lets us use the system as the back-end for a web interface. Low latency mea ## Data replication and support for data integrity on replicas Uses asynchronous multimaster replication. After being written to any available replica, data is distributed to all the remaining replicas. The system maintains identical data on different replicas. Data is restored automatically after a failure, or using a "button" for complex cases. -For more information, see the section [Data replication](../table_engines/replication.md#table_engines-replication). +For more information, see the section [Data replication](../operations/table_engines/replication.md#table_engines-replication). diff --git a/docs/en/operations/access_rights.md b/docs/en/operations/access_rights.md index 837fd870fcf..5e2534cdf56 100644 --- a/docs/en/operations/access_rights.md +++ b/docs/en/operations/access_rights.md @@ -61,7 +61,7 @@ Users are recorded in the `users` section. Here is a fragment of the `users.xml` You can see a declaration from two users: `default` and `web`. We added the `web` user separately. -The `default` user is chosen in cases when the username is not passed. The `default` user is also used for distributed query processing, if the configuration of the server or cluster doesn't specify the `user` and `password` (see the section on the [Distributed](../table_engines/distributed.md#table_engines-distributed) engine). +The `default` user is chosen in cases when the username is not passed. The `default` user is also used for distributed query processing, if the configuration of the server or cluster doesn't specify the `user` and `password` (see the section on the [Distributed](../operations/table_engines/distributed.md#table_engines-distributed) engine). The user that is used for exchanging information between servers combined in a cluster must not have substantial restrictions or quotas – otherwise, distributed queries will fail. diff --git a/docs/en/operations/server_settings/settings.md b/docs/en/operations/server_settings/settings.md index ed0bbe5b893..4a56bd057fe 100644 --- a/docs/en/operations/server_settings/settings.md +++ b/docs/en/operations/server_settings/settings.md @@ -179,7 +179,7 @@ You can configure multiple `` clauses. For instance, you can use this Settings for thinning data for Graphite. -For more information, see [GraphiteMergeTree](../../table_engines/graphitemergetree.md#table_engines-graphitemergetree). +For more information, see [GraphiteMergeTree](../../operations/table_engines/graphitemergetree.md#table_engines-graphitemergetree). **Example** @@ -358,7 +358,7 @@ Parameter substitutions for replicated tables. Can be omitted if replicated tables are not used. -For more information, see the section "[Creating replicated tables](../../table_engines/replication.md#table_engines-replication-creation_of_rep_tables)". +For more information, see the section "[Creating replicated tables](../../operations/table_engines/replication.md#table_engines-replication-creation_of_rep_tables)". **Example** @@ -370,7 +370,7 @@ For more information, see the section "[Creating replicated tables](../../table_ ## mark_cache_size -Approximate size (in bytes) of the cache of "marks" used by [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree) engines. +Approximate size (in bytes) of the cache of "marks" used by [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree) engines. The cache is shared for the server and memory is allocated as needed. The cache size must be at least 5368709120. @@ -426,7 +426,7 @@ We recommend using this option in Mac OS X, since the ` getrlimit()` function re Restriction on deleting tables. -If the size of a [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree) type table exceeds `max_table_size_to_drop` (in bytes), you can't delete it using a DROP query. +If the size of a [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree) type table exceeds `max_table_size_to_drop` (in bytes), you can't delete it using a DROP query. If you still need to delete the table without restarting the ClickHouse server, create the ` /flags/force_drop_table` file and run the DROP query. @@ -444,7 +444,7 @@ The value 0 means that you can delete all tables without any restrictions. ## merge_tree -Fine tuning for tables in the [ MergeTree](../../table_engines/mergetree.md#table_engines-mergetree) family. +Fine tuning for tables in the [ MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree) family. For more information, see the MergeTreeSettings.h header file. @@ -521,7 +521,7 @@ Keys for server/client settings: ## part_log -Logging events that are associated with [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree) data. For instance, adding or merging data. You can use the log to simulate merge algorithms and compare their characteristics. You can visualize the merge process. +Logging events that are associated with [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree) data. For instance, adding or merging data. You can use the log to simulate merge algorithms and compare their characteristics. You can visualize the merge process. Queries are logged in the ClickHouse table, not in a separate file. @@ -541,7 +541,7 @@ Use the following parameters to configure logging: - database – Name of the database. - table – Name of the table. -- partition_by – Sets a [custom partitioning key](../../table_engines/custom_partitioning_key.md#custom-partitioning-key). +- partition_by – Sets a [custom partitioning key](../../operations/table_engines/custom_partitioning_key.md#custom-partitioning-key). - flush_interval_milliseconds – Interval for flushing data from memory to the disk. **Example** @@ -585,7 +585,7 @@ Use the following parameters to configure logging: - database – Name of the database. - table – Name of the table. -- partition_by – Sets a [custom partitioning key](../../table_engines/custom_partitioning_key.md#custom-partitioning-key). +- partition_by – Sets a [custom partitioning key](../../operations/table_engines/custom_partitioning_key.md#custom-partitioning-key). - flush_interval_milliseconds – Interval for flushing data from memory to the disk. If the table doesn't exist, ClickHouse will create it. If the structure of the query log changed when the ClickHouse server was updated, the table with the old structure is renamed, and a new table is created automatically. @@ -607,7 +607,7 @@ If the table doesn't exist, ClickHouse will create it. If the structure of the q Configuration of clusters used by the Distributed table engine. -For more information, see the section "[Table engines/Distributed](../../table_engines/distributed.md#table_engines-distributed)". +For more information, see the section "[Table engines/Distributed](../../operations/table_engines/distributed.md#table_engines-distributed)". **Example** @@ -667,7 +667,7 @@ The end slash is mandatory. ## uncompressed_cache_size -Cache size (in bytes) for uncompressed data used by table engines from the [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree) family. +Cache size (in bytes) for uncompressed data used by table engines from the [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree) family. There is one shared cache for the server. Memory is allocated on demand. The cache is used if the option [use_uncompressed_cache](../settings/settings.md#settings-use_uncompressed_cache) is enabled. @@ -716,7 +716,7 @@ ClickHouse uses ZooKeeper for storing replica metadata when using replicated tab This parameter can be omitted if replicated tables are not used. -For more information, see the section "[Replication](../../table_engines/replication.md#table_engines-replication)". +For more information, see the section "[Replication](../../operations/table_engines/replication.md#table_engines-replication)". **Example** diff --git a/docs/en/operations/settings/settings.md b/docs/en/operations/settings/settings.md index 79d84f2f9e8..fa23583692f 100644 --- a/docs/en/operations/settings/settings.md +++ b/docs/en/operations/settings/settings.md @@ -20,7 +20,7 @@ The possible values ​​are: ## fallback_to_stale_replicas_for_distributed_queries -Forces a query to an out-of-date replica if updated data is not available. See "[Replication](../../table_engines/replication.md#table_engines-replication)". +Forces a query to an out-of-date replica if updated data is not available. See "[Replication](../../operations/table_engines/replication.md#table_engines-replication)". ClickHouse selects the most relevant from the outdated replicas of the table. @@ -36,7 +36,7 @@ Disables query execution if the index can't be used by date. Works with tables in the MergeTree family. -If `force_index_by_date=1`, ClickHouse checks whether the query has a date key condition that can be used for restricting data ranges. If there is no suitable condition, it throws an exception. However, it does not check whether the condition actually reduces the amount of data to read. For example, the condition `Date != ' 2000-01-01 '` is acceptable even when it matches all the data in the table (i.e., running the query requires a full scan). For more information about ranges of data in MergeTree tables, see "[MergeTree](../../table_engines/mergetree.md#table_engines-mergetree)". +If `force_index_by_date=1`, ClickHouse checks whether the query has a date key condition that can be used for restricting data ranges. If there is no suitable condition, it throws an exception. However, it does not check whether the condition actually reduces the amount of data to read. For example, the condition `Date != ' 2000-01-01 '` is acceptable even when it matches all the data in the table (i.e., running the query requires a full scan). For more information about ranges of data in MergeTree tables, see "[MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree)". @@ -46,7 +46,7 @@ Disables query execution if indexing by the primary key is not possible. Works with tables in the MergeTree family. -If `force_primary_key=1`, ClickHouse checks to see if the query has a primary key condition that can be used for restricting data ranges. If there is no suitable condition, it throws an exception. However, it does not check whether the condition actually reduces the amount of data to read. For more information about data ranges in MergeTree tables, see "[MergeTree](../../table_engines/mergetree.md#table_engines-mergetree)". +If `force_primary_key=1`, ClickHouse checks to see if the query has a primary key condition that can be used for restricting data ranges. If there is no suitable condition, it throws an exception. However, it does not check whether the condition actually reduces the amount of data to read. For more information about data ranges in MergeTree tables, see "[MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree)". @@ -125,7 +125,7 @@ This is slightly more than `max_block_size`. The reason for this is because cert ## max_replica_delay_for_distributed_queries -Disables lagging replicas for distributed queries. See "[Replication](../../table_engines/replication.md#table_engines-replication)". +Disables lagging replicas for distributed queries. See "[Replication](../../operations/table_engines/replication.md#table_engines-replication)". Sets the time in seconds. If a replica lags more than the set value, this replica is not used. @@ -158,7 +158,7 @@ Don't confuse blocks for compression (a chunk of memory consisting of bytes) and ## min_compress_block_size -For [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree)" tables. In order to reduce latency when processing queries, a block is compressed when writing the next mark if its size is at least 'min_compress_block_size'. By default, 65,536. +For [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree)" tables. In order to reduce latency when processing queries, a block is compressed when writing the next mark if its size is at least 'min_compress_block_size'. By default, 65,536. The actual size of the block, if the uncompressed data is less than 'max_compress_block_size', is no less than this value and no less than the volume of data for one mark. diff --git a/docs/en/operations/system_tables.md b/docs/en/operations/system_tables.md index b0a8aa55236..0f0fe6f05a0 100644 --- a/docs/en/operations/system_tables.md +++ b/docs/en/operations/system_tables.md @@ -127,7 +127,7 @@ This is similar to the DUAL table found in other DBMSs. ## system.parts -Contains information about parts of a table in the [MergeTree](../table_engines/mergetree.md#table_engines-mergetree) family. +Contains information about parts of a table in the [MergeTree](../operations/table_engines/mergetree.md#table_engines-mergetree) family. Each row describes one part of the data. diff --git a/docs/en/table_engines/aggregatingmergetree.md b/docs/en/operations/table_engines/aggregatingmergetree.md similarity index 100% rename from docs/en/table_engines/aggregatingmergetree.md rename to docs/en/operations/table_engines/aggregatingmergetree.md diff --git a/docs/en/table_engines/buffer.md b/docs/en/operations/table_engines/buffer.md similarity index 100% rename from docs/en/table_engines/buffer.md rename to docs/en/operations/table_engines/buffer.md diff --git a/docs/en/table_engines/collapsingmergetree.md b/docs/en/operations/table_engines/collapsingmergetree.md similarity index 100% rename from docs/en/table_engines/collapsingmergetree.md rename to docs/en/operations/table_engines/collapsingmergetree.md diff --git a/docs/en/table_engines/custom_partitioning_key.md b/docs/en/operations/table_engines/custom_partitioning_key.md similarity index 100% rename from docs/en/table_engines/custom_partitioning_key.md rename to docs/en/operations/table_engines/custom_partitioning_key.md diff --git a/docs/en/table_engines/dictionary.md b/docs/en/operations/table_engines/dictionary.md similarity index 95% rename from docs/en/table_engines/dictionary.md rename to docs/en/operations/table_engines/dictionary.md index db24e39e07a..f300bcd3a99 100644 --- a/docs/en/table_engines/dictionary.md +++ b/docs/en/operations/table_engines/dictionary.md @@ -61,7 +61,7 @@ WHERE name = 'products' └──────────┴──────┴────────┴─────────────────┴─────────────────┴─────────────────┴───────────────┴─────────────────┘ ``` -You can use the [dictGet*](../functions/ext_dict_functions.md#ext_dict_functions) function to get the dictionary data in this format. +You can use the [dictGet*](../../functions/ext_dict_functions.md#ext_dict_functions) function to get the dictionary data in this format. This view isn't helpful when you need to get raw data, or when performing a `JOIN` operation. For these cases, you can use the `Dictionary` engine, which displays the dictionary data in a table. diff --git a/docs/en/table_engines/distributed.md b/docs/en/operations/table_engines/distributed.md similarity index 100% rename from docs/en/table_engines/distributed.md rename to docs/en/operations/table_engines/distributed.md diff --git a/docs/en/table_engines/external_data.md b/docs/en/operations/table_engines/external_data.md similarity index 100% rename from docs/en/table_engines/external_data.md rename to docs/en/operations/table_engines/external_data.md diff --git a/docs/en/table_engines/file.md b/docs/en/operations/table_engines/file.md similarity index 75% rename from docs/en/table_engines/file.md rename to docs/en/operations/table_engines/file.md index 175e6f69b80..63c575997d2 100644 --- a/docs/en/table_engines/file.md +++ b/docs/en/operations/table_engines/file.md @@ -16,13 +16,13 @@ Usage examples: File(Format) ``` -`Format` should be supported for either `INSERT` and `SELECT`. For the full list of supported formats see [Formats](../interfaces/formats.md#formats). +`Format` should be supported for either `INSERT` and `SELECT`. For the full list of supported formats see [Formats](../../interfaces/formats.md#formats). -ClickHouse does not allow to specify filesystem path for`File`. It will use folder defined by [path](../operations/server_settings/settings.md#server_settings-path) setting in server configuration. +ClickHouse does not allow to specify filesystem path for`File`. It will use folder defined by [path](../server_settings/settings.md#server_settings-path) setting in server configuration. When creating table using `File(Format)` it creates empty subdirectory in that folder. When data is written to that table, it's put into `data.Format` file in that subdirectory. -You may manually create this subfolder and file in server filesystem and then [ATTACH](../query_language/queries.md#queries-attach) it to table information with matching name, so you can query data from that file. +You may manually create this subfolder and file in server filesystem and then [ATTACH](../../query_language/queries.md#queries-attach) it to table information with matching name, so you can query data from that file.
Be careful with this funcionality, because ClickHouse does not keep track of external changes to such files. The result of simultaneous writes via ClickHouse and outside of ClickHouse is undefined. @@ -61,7 +61,7 @@ SELECT * FROM file_engine_table ## Usage in clickhouse-local -In [clickhouse-local](../operations/utils/clickhouse-local.md#utils-clickhouse-local) File engine accepts file path in addition to `Format`. Default input/output streams can be specified using numeric or human-readable names like `0` or `stdin`, `1` or `stdout`. +In [clickhouse-local](../utils/clickhouse-local.md#utils-clickhouse-local) File engine accepts file path in addition to `Format`. Default input/output streams can be specified using numeric or human-readable names like `0` or `stdin`, `1` or `stdout`. **Example:** diff --git a/docs/en/table_engines/graphitemergetree.md b/docs/en/operations/table_engines/graphitemergetree.md similarity index 93% rename from docs/en/table_engines/graphitemergetree.md rename to docs/en/operations/table_engines/graphitemergetree.md index d53d871ba6e..b9c5a3d563c 100644 --- a/docs/en/table_engines/graphitemergetree.md +++ b/docs/en/operations/table_engines/graphitemergetree.md @@ -14,7 +14,7 @@ Graphite stores full data in ClickHouse, and data can be retrieved in the follow Using the `GraphiteMergeTree` engine. -The engine inherits properties from MergeTree. The settings for thinning data are defined by the [graphite_rollup](../operations/server_settings/settings.md#server_settings-graphite_rollup) parameter in the server configuration. +The engine inherits properties from MergeTree. The settings for thinning data are defined by the [graphite_rollup](../server_settings/settings.md#server_settings-graphite_rollup) parameter in the server configuration. ## Using the engine diff --git a/docs/en/table_engines/index.md b/docs/en/operations/table_engines/index.md similarity index 100% rename from docs/en/table_engines/index.md rename to docs/en/operations/table_engines/index.md diff --git a/docs/en/table_engines/join.md b/docs/en/operations/table_engines/join.md similarity index 100% rename from docs/en/table_engines/join.md rename to docs/en/operations/table_engines/join.md diff --git a/docs/en/table_engines/kafka.md b/docs/en/operations/table_engines/kafka.md similarity index 93% rename from docs/en/table_engines/kafka.md rename to docs/en/operations/table_engines/kafka.md index 9c766e40fb6..31616e77d25 100644 --- a/docs/en/table_engines/kafka.md +++ b/docs/en/operations/table_engines/kafka.md @@ -67,7 +67,7 @@ Example: SELECT level, sum(total) FROM daily GROUP BY level; ``` -To improve performance, received messages are grouped into blocks the size of [max_insert_block_size](../operations/settings/settings.md#settings-settings-max_insert_block_size). If the block wasn't formed within [stream_flush_interval_ms](../operations/settings/settings.md#settings-settings_stream_flush_interval_ms) milliseconds, the data will be flushed to the table regardless of the completeness of the block. +To improve performance, received messages are grouped into blocks the size of [max_insert_block_size](../settings/settings.md#settings-settings-max_insert_block_size). If the block wasn't formed within [stream_flush_interval_ms](../settings/settings.md#settings-settings_stream_flush_interval_ms) milliseconds, the data will be flushed to the table regardless of the completeness of the block. To stop receiving topic data or to change the conversion logic, detach the materialized view: diff --git a/docs/en/table_engines/log.md b/docs/en/operations/table_engines/log.md similarity index 100% rename from docs/en/table_engines/log.md rename to docs/en/operations/table_engines/log.md diff --git a/docs/en/operations/table_engines/materializedview.md b/docs/en/operations/table_engines/materializedview.md new file mode 100644 index 00000000000..63e282295ec --- /dev/null +++ b/docs/en/operations/table_engines/materializedview.md @@ -0,0 +1,4 @@ +# MaterializedView + +Used for implementing materialized views (for more information, see the [CREATE TABLE](../../query_language/queries.md#query_language-queries-create_table)) query. For storing data, it uses a different engine that was specified when creating the view. When reading from a table, it just uses this engine. + diff --git a/docs/en/table_engines/memory.md b/docs/en/operations/table_engines/memory.md similarity index 100% rename from docs/en/table_engines/memory.md rename to docs/en/operations/table_engines/memory.md diff --git a/docs/en/table_engines/merge.md b/docs/en/operations/table_engines/merge.md similarity index 100% rename from docs/en/table_engines/merge.md rename to docs/en/operations/table_engines/merge.md diff --git a/docs/en/table_engines/mergetree.md b/docs/en/operations/table_engines/mergetree.md similarity index 96% rename from docs/en/table_engines/mergetree.md rename to docs/en/operations/table_engines/mergetree.md index 7ee58165c80..d89b2dfdfa3 100644 --- a/docs/en/table_engines/mergetree.md +++ b/docs/en/operations/table_engines/mergetree.md @@ -56,7 +56,7 @@ In this example, the index can't be used. SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%' ``` -To check whether ClickHouse can use the index when executing the query, use the settings [force_index_by_date](../operations/settings/settings.md#settings-settings-force_index_by_date)and[force_primary_key](../operations/settings/settings.md#settings-settings-force_primary_key). +To check whether ClickHouse can use the index when executing the query, use the settings [force_index_by_date](../settings/settings.md#settings-settings-force_index_by_date)and[force_primary_key](../settings/settings.md#settings-settings-force_primary_key). The index by date only allows reading those parts that contain dates from the desired range. However, a data part may contain data for many dates (up to an entire month), while within a single part the data is ordered by the primary key, which might not contain the date as the first column. Because of this, using a query with only a date condition that does not specify the primary key prefix will cause more data to be read than for a single date. diff --git a/docs/en/table_engines/mysql.md b/docs/en/operations/table_engines/mysql.md similarity index 100% rename from docs/en/table_engines/mysql.md rename to docs/en/operations/table_engines/mysql.md diff --git a/docs/en/table_engines/null.md b/docs/en/operations/table_engines/null.md similarity index 100% rename from docs/en/table_engines/null.md rename to docs/en/operations/table_engines/null.md diff --git a/docs/en/table_engines/replacingmergetree.md b/docs/en/operations/table_engines/replacingmergetree.md similarity index 100% rename from docs/en/table_engines/replacingmergetree.md rename to docs/en/operations/table_engines/replacingmergetree.md diff --git a/docs/en/table_engines/replication.md b/docs/en/operations/table_engines/replication.md similarity index 96% rename from docs/en/table_engines/replication.md rename to docs/en/operations/table_engines/replication.md index cdc9ce0d1e0..5ced888b43d 100644 --- a/docs/en/table_engines/replication.md +++ b/docs/en/operations/table_engines/replication.md @@ -15,7 +15,7 @@ Replication works at the level of an individual table, not the entire server. A Replication does not depend on sharding. Each shard has its own independent replication. -Compressed data is replicated for `INSERT` and `ALTER` queries (see the description of the [ALTER](../query_language/queries.md#query_language_queries_alter) query). +Compressed data is replicated for `INSERT` and `ALTER` queries (see the description of the [ALTER](../../query_language/queries.md#query_language_queries_alter) query). `CREATE`, `DROP`, `ATTACH`, `DETACH` and `RENAME` queries are executed on a single server and are not replicated: @@ -48,7 +48,7 @@ You can specify any existing ZooKeeper cluster and the system will use a directo If ZooKeeper isn't set in the config file, you can't create replicated tables, and any existing replicated tables will be read-only. -ZooKeeper is not used in `SELECT` queries because replication does not affect the performance of `SELECT` and queries run just as fast as they do for non-replicated tables. When querying distributed replicated tables, ClickHouse behavior is controlled by the settings [max_replica_delay_for_distributed_queries](../operations/settings/settings.md#settings_settings_max_replica_delay_for_distributed_queries) and [fallback_to_stale_replicas_for_distributed_queries](../operations/settings/settings.md#settings-settings-fallback_to_stale_replicas_for_distributed_queries). +ZooKeeper is not used in `SELECT` queries because replication does not affect the performance of `SELECT` and queries run just as fast as they do for non-replicated tables. When querying distributed replicated tables, ClickHouse behavior is controlled by the settings [max_replica_delay_for_distributed_queries](../settings/settings.md#settings_settings_max_replica_delay_for_distributed_queries) and [fallback_to_stale_replicas_for_distributed_queries](../settings/settings.md#settings-settings-fallback_to_stale_replicas_for_distributed_queries). For each `INSERT` query, approximately ten entries are added to ZooKeeper through several transactions. (To be more precise, this is for each inserted block of data; an INSERT query contains one block or one block per `max_insert_block_size = 1048576` rows.) This leads to slightly longer latencies for `INSERT` compared to non-replicated tables. But if you follow the recommendations to insert data in batches of no more than one `INSERT` per second, it doesn't create any problems. The entire ClickHouse cluster used for coordinating one ZooKeeper cluster has a total of several hundred `INSERTs` per second. The throughput on data inserts (the number of rows per second) is just as high as for non-replicated data. @@ -60,7 +60,7 @@ By default, an INSERT query waits for confirmation of writing the data from only Each block of data is written atomically. The INSERT query is divided into blocks up to `max_insert_block_size = 1048576` rows. In other words, if the `INSERT` query has less than 1048576 rows, it is made atomically. -Data blocks are deduplicated. For multiple writes of the same data block (data blocks of the same size containing the same rows in the same order), the block is only written once. The reason for this is in case of network failures when the client application doesn't know if the data was written to the DB, so the `INSERT` query can simply be repeated. It doesn't matter which replica INSERTs were sent to with identical data. `INSERTs` are idempotent. Deduplication parameters are controlled by [merge_tree](../operations/server_settings/settings.md#server_settings-merge_tree) server settings. +Data blocks are deduplicated. For multiple writes of the same data block (data blocks of the same size containing the same rows in the same order), the block is only written once. The reason for this is in case of network failures when the client application doesn't know if the data was written to the DB, so the `INSERT` query can simply be repeated. It doesn't matter which replica INSERTs were sent to with identical data. `INSERTs` are idempotent. Deduplication parameters are controlled by [merge_tree](../server_settings/settings.md#server_settings-merge_tree) server settings. During replication, only the source data to insert is transferred over the network. Further data transformation (merging) is coordinated and performed on all the replicas in the same way. This minimizes network usage, which means that replication works well when replicas reside in different datacenters. (Note that duplicating data in different datacenters is the main goal of replication.) diff --git a/docs/en/table_engines/set.md b/docs/en/operations/table_engines/set.md similarity index 100% rename from docs/en/table_engines/set.md rename to docs/en/operations/table_engines/set.md diff --git a/docs/en/table_engines/summingmergetree.md b/docs/en/operations/table_engines/summingmergetree.md similarity index 100% rename from docs/en/table_engines/summingmergetree.md rename to docs/en/operations/table_engines/summingmergetree.md diff --git a/docs/en/table_engines/tinylog.md b/docs/en/operations/table_engines/tinylog.md similarity index 100% rename from docs/en/table_engines/tinylog.md rename to docs/en/operations/table_engines/tinylog.md diff --git a/docs/en/table_engines/view.md b/docs/en/operations/table_engines/view.md similarity index 100% rename from docs/en/table_engines/view.md rename to docs/en/operations/table_engines/view.md diff --git a/docs/en/table_engines/materializedview.md b/docs/en/table_engines/materializedview.md deleted file mode 100644 index 5e2741c6aa1..00000000000 --- a/docs/en/table_engines/materializedview.md +++ /dev/null @@ -1,4 +0,0 @@ -# MaterializedView - -Used for implementing materialized views (for more information, see the [CREATE TABLE](../query_language/queries.md#query_language-queries-create_table)) query. For storing data, it uses a different engine that was specified when creating the view. When reading from a table, it just uses this engine. - diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index d7931cf6d4b..a206bddc1b1 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -55,37 +55,6 @@ pages: - 'Queries': 'query_language/queries.md' - 'Syntax': 'query_language/syntax.md' -- 'Table engines': - - 'Introduction': 'table_engines/index.md' - - 'MergeTree family': - - 'MergeTree': 'table_engines/mergetree.md' - - 'Data replication': 'table_engines/replication.md' - - 'Custom partitioning key': 'table_engines/custom_partitioning_key.md' - - 'ReplacingMergeTree': 'table_engines/replacingmergetree.md' - - 'SummingMergeTree': 'table_engines/summingmergetree.md' - - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' - - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' - - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' - - 'For small data': - - 'TinyLog': 'table_engines/tinylog.md' - - 'Log': 'table_engines/log.md' - - 'Memory': 'table_engines/memory.md' - - 'Buffer': 'table_engines/buffer.md' - - 'External data': 'table_engines/external_data.md' - - 'Special': - - 'Distributed': 'table_engines/distributed.md' - - 'Dictionary': 'table_engines/dictionary.md' - - 'Merge': 'table_engines/merge.md' - - 'File': 'table_engines/file.md' - - 'Null': 'table_engines/null.md' - - 'Set': 'table_engines/set.md' - - 'Join': 'table_engines/join.md' - - 'View': 'table_engines/view.md' - - 'MaterializedView': 'table_engines/materializedview.md' - - 'Integrations': - - 'Kafka': 'table_engines/kafka.md' - - 'MySQL': 'table_engines/mysql.md' - - 'Table functions': - 'Introduction': 'table_functions/index.md' - 'file': 'table_functions/file.md' @@ -143,6 +112,36 @@ pages: - 'Operations': - 'Operations': 'operations/index.md' + - 'Table engines': + - 'Introduction': 'operations/table_engines/index.md' + - 'MergeTree family': + - 'MergeTree': 'operations/table_engines/mergetree.md' + - 'Data replication': 'operations/table_engines/replication.md' + - 'Custom partitioning key': 'operations/table_engines/custom_partitioning_key.md' + - 'ReplacingMergeTree': 'operations/table_engines/replacingmergetree.md' + - 'SummingMergeTree': 'operations/table_engines/summingmergetree.md' + - 'AggregatingMergeTree': 'operations/table_engines/aggregatingmergetree.md' + - 'CollapsingMergeTree': 'operations/table_engines/collapsingmergetree.md' + - 'GraphiteMergeTree': 'operations/table_engines/graphitemergetree.md' + - 'For small data': + - 'TinyLog': 'operations/table_engines/tinylog.md' + - 'Log': 'operations/table_engines/log.md' + - 'Memory': 'operations/table_engines/memory.md' + - 'Buffer': 'operations/table_engines/buffer.md' + - 'External data': 'operations/table_engines/external_data.md' + - 'Special': + - 'Distributed': 'operations/table_engines/distributed.md' + - 'Dictionary': 'operations/table_engines/dictionary.md' + - 'Merge': 'operations/table_engines/merge.md' + - 'File': 'operations/table_engines/file.md' + - 'Null': 'operations/table_engines/null.md' + - 'Set': 'operations/table_engines/set.md' + - 'Join': 'operations/table_engines/join.md' + - 'View': 'operations/table_engines/view.md' + - 'MaterializedView': 'operations/table_engines/materializedview.md' + - 'Integrations': + - 'Kafka': 'operations/table_engines/kafka.md' + - 'MySQL': 'operations/table_engines/mysql.md' - 'Access rights': 'operations/access_rights.md' - 'Configuration files': 'operations/configuration_files.md' - 'Quotas': 'operations/quotas.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index f406522edaa..3ba1ee6fb16 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -55,37 +55,6 @@ pages: - 'Запросы': 'query_language/queries.md' - 'Синтаксис': 'query_language/syntax.md' -- 'Движки таблиц': - - 'Введение': 'table_engines/index.md' - - 'Семейство MergeTree': - - 'MergeTree': 'table_engines/mergetree.md' - - 'Репликация данных': 'table_engines/replication.md' - - 'Произвольный ключ партиционирования': 'table_engines/custom_partitioning_key.md' - - 'ReplacingMergeTree': 'table_engines/replacingmergetree.md' - - 'SummingMergeTree': 'table_engines/summingmergetree.md' - - 'AggregatingMergeTree': 'table_engines/aggregatingmergetree.md' - - 'CollapsingMergeTree': 'table_engines/collapsingmergetree.md' - - 'GraphiteMergeTree': 'table_engines/graphitemergetree.md' - - 'Для небольших объемов данных': - - 'TinyLog': 'table_engines/tinylog.md' - - 'Log': 'table_engines/log.md' - - 'Memory': 'table_engines/memory.md' - - 'Buffer': 'table_engines/buffer.md' - - 'Внешние данные': 'table_engines/external_data.md' - - 'Особые': - - 'Distributed': 'table_engines/distributed.md' - - 'Dictionary': 'table_engines/dictionary.md' - - 'Merge': 'table_engines/merge.md' - - 'File': 'table_engines/file.md' - - 'Null': 'table_engines/null.md' - - 'Set': 'table_engines/set.md' - - 'Join': 'table_engines/join.md' - - 'View': 'table_engines/view.md' - - 'MaterializedView': 'table_engines/materializedview.md' - - 'Интеграции': - - 'Kafka': 'table_engines/kafka.md' - - 'MySQL': 'table_engines/mysql.md' - - 'Табличные функции': - 'Введение': 'table_functions/index.md' - 'file': 'table_functions/file.md' @@ -144,6 +113,36 @@ pages: - 'Эксплуатация': # - 'Эксплуатация': 'operations/index.md' + - 'Движки таблиц': + - 'Введение': 'operations/table_engines/index.md' + - 'Семейство MergeTree': + - 'MergeTree': 'operations/table_engines/mergetree.md' + - 'Репликация данных': 'operations/table_engines/replication.md' + - 'Произвольный ключ партиционирования': 'operations/table_engines/custom_partitioning_key.md' + - 'ReplacingMergeTree': 'operations/table_engines/replacingmergetree.md' + - 'SummingMergeTree': 'operations/table_engines/summingmergetree.md' + - 'AggregatingMergeTree': 'operations/table_engines/aggregatingmergetree.md' + - 'CollapsingMergeTree': 'operations/table_engines/collapsingmergetree.md' + - 'GraphiteMergeTree': 'operations/table_engines/graphitemergetree.md' + - 'Для небольших объемов данных': + - 'TinyLog': 'operations/table_engines/tinylog.md' + - 'Log': 'operations/table_engines/log.md' + - 'Memory': 'operations/table_engines/memory.md' + - 'Buffer': 'operations/table_engines/buffer.md' + - 'Внешние данные': 'operations/table_engines/external_data.md' + - 'Особые': + - 'Distributed': 'operations/table_engines/distributed.md' + - 'Dictionary': 'operations/table_engines/dictionary.md' + - 'Merge': 'operations/table_engines/merge.md' + - 'File': 'operations/table_engines/file.md' + - 'Null': 'operations/table_engines/null.md' + - 'Set': 'operations/table_engines/set.md' + - 'Join': 'operations/table_engines/join.md' + - 'View': 'operations/table_engines/view.md' + - 'MaterializedView': 'operations/table_engines/materializedview.md' + - 'Интеграции': + - 'Kafka': 'operations/table_engines/kafka.md' + - 'MySQL': 'operations/table_engines/mysql.md' - 'Права доступа': 'operations/access_rights.md' - 'Конфигурационные файлы': 'operations/configuration_files.md' - 'Квоты': 'operations/quotas.md' diff --git a/docs/redirects.txt b/docs/redirects.txt index 93024244acc..73803e31a9f 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -44,3 +44,29 @@ formats/xml.md formats/interfaces.md utils/clickhouse-copier.md operations/utils/clickhouse-copier.md utils/clickhouse-local.md operations/utils/clickhouse-local.md utils.md operations/utils.md +table_engines.md operations/table_engines.md +table_engines/aggregatingmergetree.md operations/table_engines/aggregatingmergetree.md +table_engines/buffer.md operations/table_engines/buffer.md +table_engines/collapsingmergetree.md operations/table_engines/collapsingmergetree.md +table_engines/custom_partitioning_key.md operations/table_engines/custom_partitioning_key.md +table_engines/dictionary.md operations/table_engines/dictionary.md +table_engines/distributed.md operations/table_engines/distributed.md +table_engines/external_data.md operations/table_engines/external_data.md +table_engines/file.md operations/table_engines/file.md +table_engines/graphitemergetree.md operations/table_engines/graphitemergetree.md +table_engines/index.md operations/table_engines/index.md +table_engines/join.md operations/table_engines/join.md +table_engines/kafka.md operations/table_engines/kafka.md +table_engines/log.md operations/table_engines/log.md +table_engines/materializedview.md operations/table_engines/materializedview.md +table_engines/memory.md operations/table_engines/memory.md +table_engines/merge.md operations/table_engines/merge.md +table_engines/mergetree.md operations/table_engines/mergetree.md +table_engines/mysql.md operations/table_engines/mysql.md +table_engines/null.md operations/table_engines/null.md +table_engines/replacingmergetree.md operations/table_engines/replacingmergetree.md +table_engines/replication.md operations/table_engines/replication.md +table_engines/set.md operations/table_engines/set.md +table_engines/summingmergetree.md operations/table_engines/summingmergetree.md +table_engines/tinylog.md operations/table_engines/tinylog.md +table_engines/view.md operations/table_engines/view.md diff --git a/docs/ru/dicts/external_dicts_dict_sources.md b/docs/ru/dicts/external_dicts_dict_sources.md index 083d14d4159..4811cb03f23 100644 --- a/docs/ru/dicts/external_dicts_dict_sources.md +++ b/docs/ru/dicts/external_dicts_dict_sources.md @@ -355,7 +355,7 @@ MySQL можно подключить на локальном хосте чер Поля настройки: -- `host` - хост ClickHouse. Если host локальный, то запрос выполняется без сетевого взаимодействия. Чтобы повысить отказоустойчивость решения, можно создать таблицу типа [Distributed](../table_engines/distributed.md#table_engines-distributed) и прописать её в дальнейших настройках. +- `host` - хост ClickHouse. Если host локальный, то запрос выполняется без сетевого взаимодействия. Чтобы повысить отказоустойчивость решения, можно создать таблицу типа [Distributed](../operations/table_engines/distributed.md#table_engines-distributed) и прописать её в дальнейших настройках. - `port` - порт сервера ClickHouse. - `user` - имя пользователя ClickHouse. - `password` - пароль пользователя ClickHouse. diff --git a/docs/ru/introduction/distinctive_features.md b/docs/ru/introduction/distinctive_features.md index 63ba71d4367..031a5c7f6bb 100644 --- a/docs/ru/introduction/distinctive_features.md +++ b/docs/ru/introduction/distinctive_features.md @@ -58,4 +58,4 @@ ClickHouse поддерживает таблицы с первичным клю ## Репликация данных, поддержка целостности данных на репликах Используется асинхронная multimaster репликация. После записи на любую доступную реплику, данные распространяются на все остальные реплики. Система поддерживает полную идентичность данных на разных репликах. Восстановление после сбоя осуществляется автоматически, а в сложных случаях - "по кнопке". -Подробнее смотрите раздел [Репликация данных](../table_engines/replication.md#table_engines-replication). +Подробнее смотрите раздел [Репликация данных](../operations/table_engines/replication.md#table_engines-replication). diff --git a/docs/ru/operations/access_rights.md b/docs/ru/operations/access_rights.md index 2e5fac14200..027b2fb9e8a 100644 --- a/docs/ru/operations/access_rights.md +++ b/docs/ru/operations/access_rights.md @@ -61,7 +61,7 @@ Здесь видно объявление двух пользователей - `default` и `web`. Пользователя `web` мы добавили самостоятельно. -Пользователь `default` выбирается в случаях, когда имя пользователя не передаётся. Также пользователь `default` может использоваться при распределённой обработке запроса - если в конфигурации кластера для сервера не указаны `user` и `password`. (см. раздел о движке [Distributed](../table_engines/distributed.md#table_engines-distributed)). +Пользователь `default` выбирается в случаях, когда имя пользователя не передаётся. Также пользователь `default` может использоваться при распределённой обработке запроса - если в конфигурации кластера для сервера не указаны `user` и `password`. (см. раздел о движке [Distributed](../operations/table_engines/distributed.md#table_engines-distributed)). Пользователь, который используется для обмена информацией между серверами, объединенными в кластер, не должен иметь существенных ограничений или квот - иначе распределённые запросы сломаются. diff --git a/docs/ru/operations/server_settings/settings.md b/docs/ru/operations/server_settings/settings.md index 2992b8d4c67..53d2beb3539 100644 --- a/docs/ru/operations/server_settings/settings.md +++ b/docs/ru/operations/server_settings/settings.md @@ -180,7 +180,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat Настройка прореживания данных для Graphite. -Подробнее читайте в разделе [GraphiteMergeTree](../../table_engines/graphitemergetree.md#table_engines-graphitemergetree). +Подробнее читайте в разделе [GraphiteMergeTree](../../operations/table_engines/graphitemergetree.md#table_engines-graphitemergetree). **Пример** @@ -360,7 +360,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat Можно не указывать, если реплицируемых таблицы не используются. -Подробнее смотрите в разделе "[Создание реплицируемых таблиц](../../table_engines/replication.md#table_engines-replication-creation_of_rep_tables)". +Подробнее смотрите в разделе "[Создание реплицируемых таблиц](../../operations/table_engines/replication.md#table_engines-replication-creation_of_rep_tables)". **Пример** @@ -372,7 +372,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat ## mark_cache_size -Приблизительный размер (в байтах) кеша "засечек", используемых движками таблиц семейства [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree). +Приблизительный размер (в байтах) кеша "засечек", используемых движками таблиц семейства [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree). Кеш общий для сервера, память выделяется по мере необходимости. Кеш не может быть меньше, чем 5368709120. @@ -428,7 +428,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat Ограничение на удаление таблиц. -Если размер таблицы семейства [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree) превышает `max_table_size_to_drop` (в байтах), то ее нельзя удалить запросом DROP. +Если размер таблицы семейства [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree) превышает `max_table_size_to_drop` (в байтах), то ее нельзя удалить запросом DROP. Если таблицу все же необходимо удалить, не перезапуская при этом сервер ClickHouse, то необходимо создать файл `/flags/force_drop_table` и выполнить запрос DROP. @@ -446,7 +446,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat ## merge_tree -Тонкая настройка таблиц семейства [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree). +Тонкая настройка таблиц семейства [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree). Подробнее смотрите в заголовочном файле MergeTreeSettings.h. @@ -523,7 +523,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat ## part_log -Логгирование событий, связанных с данными типа [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree). Например, события добавления или мержа данных. Лог можно использовать для симуляции алгоритмов слияния, чтобы сравнивать их характеристики. Также, можно визуализировать процесс слияния. +Логгирование событий, связанных с данными типа [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree). Например, события добавления или мержа данных. Лог можно использовать для симуляции алгоритмов слияния, чтобы сравнивать их характеристики. Также, можно визуализировать процесс слияния. Запросы логгируются не в отдельный файл, а в таблицу ClickHouse. @@ -543,7 +543,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat - database - Имя базы данных. - table - Имя таблицы. -- partition_by - Устанавливает [произвольный ключ партиционирования](../../table_engines/custom_partitioning_key.md#custom-partitioning-key). +- partition_by - Устанавливает [произвольный ключ партиционирования](../../operations/table_engines/custom_partitioning_key.md#custom-partitioning-key). - flush_interval_milliseconds - Период сброса данных из оперативной памяти на диск. @@ -588,7 +588,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat - database - Имя базы данных. - table - Имя таблицы. -- partition_by - Устанавливает [произвольный ключ партиционирования](../../table_engines/custom_partitioning_key.md#custom-partitioning-key). +- partition_by - Устанавливает [произвольный ключ партиционирования](../../operations/table_engines/custom_partitioning_key.md#custom-partitioning-key). - flush_interval_milliseconds - Период сброса данных из оперативной памяти на диск. Если таблица не существует, то ClickHouse создаст её. Если структура журнала запросов изменилась при обновлении сервера ClickHouse, то таблица со старой структурой переименовывается, а новая таблица создается автоматически. @@ -610,7 +610,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat Конфигурация кластеров, которые использует движок таблиц Distributed. -Пример настройки смотрите в разделе "[Движки таблиц/Distributed](../../table_engines/distributed.md#table_engines-distributed)". +Пример настройки смотрите в разделе "[Движки таблиц/Distributed](../../operations/table_engines/distributed.md#table_engines-distributed)". **Пример** @@ -671,7 +671,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat ## uncompressed_cache_size -Размер кеша (в байтах) для несжатых данных, используемых движками таблиц семейства [MergeTree](../../table_engines/mergetree.md#table_engines-mergetree). +Размер кеша (в байтах) для несжатых данных, используемых движками таблиц семейства [MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree). Кеш единый для сервера. Память выделяется по-требованию. Кеш используется в том случае, если включена опция [use_uncompressed_cache](../settings/settings.md#settings-use_uncompressed_cache). @@ -720,7 +720,7 @@ ClickHouse использует ZooKeeper для хранения метадан Параметр можно не указывать, если реплицированные таблицы не используются. -Подробно читайте в разделе "[Репликация](../../table_engines/replication.md#table_engines-replication)". +Подробно читайте в разделе "[Репликация](../../operations/table_engines/replication.md#table_engines-replication)". **Пример** diff --git a/docs/ru/operations/settings/settings.md b/docs/ru/operations/settings/settings.md index 9cd6639d941..e2956380cd4 100644 --- a/docs/ru/operations/settings/settings.md +++ b/docs/ru/operations/settings/settings.md @@ -26,7 +26,7 @@ ClickHouse применяет настройку в тех случаях, ко ## fallback_to_stale_replicas_for_distributed_queries -Форсирует запрос в устаревшую реплику в случае, если актуальные данные недоступны. Смотрите "[Репликация](../../table_engines/replication.md#table_engines-replication)". +Форсирует запрос в устаревшую реплику в случае, если актуальные данные недоступны. Смотрите "[Репликация](../../operations/table_engines/replication.md#table_engines-replication)". Из устаревших реплик таблицы ClickHouse выбирает наиболее актуальную. @@ -42,7 +42,7 @@ ClickHouse применяет настройку в тех случаях, ко Работает с таблицами семейства MergeTree. -При `force_index_by_date=1` ClickHouse проверяет, есть ли в запросе условие на ключ даты, которое может использоваться для отсечения диапазонов данных. Если подходящего условия нет - кидается исключение. При этом не проверяется, действительно ли условие уменьшает объём данных для чтения. Например, условие `Date != '2000-01-01'` подходит даже в том случае, когда соответствует всем данным в таблице (т.е. для выполнения запроса требуется full scan). Подробнее про диапазоны данных в таблицах MergeTree читайте в разделе "[MergeTree](../../table_engines/mergetree.md#table_engines-mergetree)". +При `force_index_by_date=1` ClickHouse проверяет, есть ли в запросе условие на ключ даты, которое может использоваться для отсечения диапазонов данных. Если подходящего условия нет - кидается исключение. При этом не проверяется, действительно ли условие уменьшает объём данных для чтения. Например, условие `Date != '2000-01-01'` подходит даже в том случае, когда соответствует всем данным в таблице (т.е. для выполнения запроса требуется full scan). Подробнее про диапазоны данных в таблицах MergeTree читайте в разделе "[MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree)". @@ -52,7 +52,7 @@ ClickHouse применяет настройку в тех случаях, ко Работает с таблицами семейства MergeTree. -При `force_primary_key=1` ClickHouse проверяет, есть ли в запросе условие на первичный ключ, которое может использоваться для отсечения диапазонов данных. Если подходящего условия нет - кидается исключение. При этом не проверяется, действительно ли условие уменьшает объём данных для чтения. Подробнее про диапазоны данных в таблицах MergeTree читайте в разделе "[MergeTree](../../table_engines/mergetree.md#table_engines-mergetree)". +При `force_primary_key=1` ClickHouse проверяет, есть ли в запросе условие на первичный ключ, которое может использоваться для отсечения диапазонов данных. Если подходящего условия нет - кидается исключение. При этом не проверяется, действительно ли условие уменьшает объём данных для чтения. Подробнее про диапазоны данных в таблицах MergeTree читайте в разделе "[MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree)". @@ -131,7 +131,7 @@ ClickHouse применяет настройку в тех случаях, ко ## max_replica_delay_for_distributed_queries -Отключает отстающие реплики при распределенных запросах. Смотрите "[Репликация](../../table_engines/replication.md#table_engines-replication)". +Отключает отстающие реплики при распределенных запросах. Смотрите "[Репликация](../../operations/table_engines/replication.md#table_engines-replication)". Устанавливает время в секундах. Если оставание реплики больше установленного значения, то реплика не используется. @@ -163,7 +163,7 @@ ClickHouse применяет настройку в тех случаях, ко ## min_compress_block_size -Для таблиц типа "[MergeTree](../../table_engines/mergetree.md#table_engines-mergetree)". В целях уменьшения задержек при обработке запросов, блок сжимается при записи следующей засечки, если его размер не меньше min_compress_block_size. По умолчанию - 65 536. +Для таблиц типа "[MergeTree](../../operations/table_engines/mergetree.md#table_engines-mergetree)". В целях уменьшения задержек при обработке запросов, блок сжимается при записи следующей засечки, если его размер не меньше min_compress_block_size. По умолчанию - 65 536. Реальный размер блока, если несжатых данных меньше max_compress_block_size, будет не меньше этого значения и не меньше объёма данных на одну засечку. diff --git a/docs/ru/operations/system_tables.md b/docs/ru/operations/system_tables.md index 277e89d644f..32086933d4a 100644 --- a/docs/ru/operations/system_tables.md +++ b/docs/ru/operations/system_tables.md @@ -120,7 +120,7 @@ default_expression String - выражение для значения по ум То есть, это - аналог таблицы DUAL, которую можно найти в других СУБД. # system.parts -Содержит информацию о кусках таблиц семейства [MergeTree](../table_engines/mergetree.md#table_engines-mergetree). +Содержит информацию о кусках таблиц семейства [MergeTree](../operations/table_engines/mergetree.md#table_engines-mergetree). Каждая строка описывает один кусок данных. diff --git a/docs/ru/table_engines/aggregatingmergetree.md b/docs/ru/operations/table_engines/aggregatingmergetree.md similarity index 100% rename from docs/ru/table_engines/aggregatingmergetree.md rename to docs/ru/operations/table_engines/aggregatingmergetree.md diff --git a/docs/ru/table_engines/buffer.md b/docs/ru/operations/table_engines/buffer.md similarity index 100% rename from docs/ru/table_engines/buffer.md rename to docs/ru/operations/table_engines/buffer.md diff --git a/docs/ru/table_engines/collapsingmergetree.md b/docs/ru/operations/table_engines/collapsingmergetree.md similarity index 100% rename from docs/ru/table_engines/collapsingmergetree.md rename to docs/ru/operations/table_engines/collapsingmergetree.md diff --git a/docs/ru/table_engines/custom_partitioning_key.md b/docs/ru/operations/table_engines/custom_partitioning_key.md similarity index 100% rename from docs/ru/table_engines/custom_partitioning_key.md rename to docs/ru/operations/table_engines/custom_partitioning_key.md diff --git a/docs/ru/table_engines/dictionary.md b/docs/ru/operations/table_engines/dictionary.md similarity index 98% rename from docs/ru/table_engines/dictionary.md rename to docs/ru/operations/table_engines/dictionary.md index 6ea26ff6e79..10e7696949f 100644 --- a/docs/ru/table_engines/dictionary.md +++ b/docs/ru/operations/table_engines/dictionary.md @@ -60,7 +60,7 @@ WHERE name = 'products' └──────────┴──────┴────────┴─────────────────┴─────────────────┴─────────────────┴───────────────┴─────────────────┘ ``` -В таком виде данные из словаря можно получить при помощи функций [dictGet*](../functions/ext_dict_functions.md#ext_dict_functions). +В таком виде данные из словаря можно получить при помощи функций [dictGet*](../../functions/ext_dict_functions.md#ext_dict_functions). Такое представление неудобно, когда нам необходимо получить данные в чистом виде, а также при выполнении операции `JOIN`. Для этих случаев можно использовать движок `Dictionary`, который отобразит данные словаря в таблицу. diff --git a/docs/ru/table_engines/distributed.md b/docs/ru/operations/table_engines/distributed.md similarity index 100% rename from docs/ru/table_engines/distributed.md rename to docs/ru/operations/table_engines/distributed.md diff --git a/docs/ru/table_engines/external_data.md b/docs/ru/operations/table_engines/external_data.md similarity index 100% rename from docs/ru/table_engines/external_data.md rename to docs/ru/operations/table_engines/external_data.md diff --git a/docs/ru/table_engines/file.md b/docs/ru/operations/table_engines/file.md similarity index 79% rename from docs/ru/table_engines/file.md rename to docs/ru/operations/table_engines/file.md index a5af94341db..93b2c0c3f45 100644 --- a/docs/ru/table_engines/file.md +++ b/docs/ru/operations/table_engines/file.md @@ -16,13 +16,13 @@ File(Format) ``` -`Format` должен быть таким, который ClickHouse может использовать и в запросах `INSERT` и в запросах `SELECT`. Полный список поддерживаемых форматов смотрите в разделе [Форматы](../interfaces/formats.md#formats). +`Format` должен быть таким, который ClickHouse может использовать и в запросах `INSERT` и в запросах `SELECT`. Полный список поддерживаемых форматов смотрите в разделе [Форматы](../../interfaces/formats.md#formats). -Сервер ClickHouse не позволяет указать путь к файлу, с которым будет работать `File`. Используется путь к хранилищу, определенный параметром [path](../operations/server_settings/settings.md#server_settings-path) в конфигурации сервера. +Сервер ClickHouse не позволяет указать путь к файлу, с которым будет работать `File`. Используется путь к хранилищу, определенный параметром [path](../server_settings/settings.md#server_settings-path) в конфигурации сервера. При создании таблицы с помощью `File(Format)` сервер ClickHouse создает в хранилище каталог с именем таблицы, а после добавления в таблицу данных помещает туда файл `data.Format`. -Можно вручную создать в хранилище каталог таблицы, поместить туда файл, затем на сервере ClickHouse добавить ([ATTACH](../query_language/queries.md#queries-attach)) информацию о таблице, соответствующей имени каталога и прочитать из файла данные. +Можно вручную создать в хранилище каталог таблицы, поместить туда файл, затем на сервере ClickHouse добавить ([ATTACH](../../query_language/queries.md#queries-attach)) информацию о таблице, соответствующей имени каталога и прочитать из файла данные.
Будьте аккуратны с этой функциональностью, поскольку сервер ClickHouse не отслеживает внешние изменения данных. Если в файл будет производиться запись одновременно со стороны сервера ClickHouse и с внешней стороны, то результат непредсказуем. @@ -61,7 +61,7 @@ SELECT * FROM file_engine_table ## Использование движка в clickhouse-local -В [clickhouse-local](../operations/utils/clickhouse-local.md#utils-clickhouse-local) движок в качестве параметра принимает не только формат, но и путь к файлу. В том числе можно указать стандартные потоки ввода/вывода цифровым или буквенным обозначением `0` или `stdin`, `1` или `stdout`. +В [clickhouse-local](../utils/clickhouse-local.md#utils-clickhouse-local) движок в качестве параметра принимает не только формат, но и путь к файлу. В том числе можно указать стандартные потоки ввода/вывода цифровым или буквенным обозначением `0` или `stdin`, `1` или `stdout`. **Пример:** diff --git a/docs/ru/table_engines/graphitemergetree.md b/docs/ru/operations/table_engines/graphitemergetree.md similarity index 95% rename from docs/ru/table_engines/graphitemergetree.md rename to docs/ru/operations/table_engines/graphitemergetree.md index f3dad938c34..3617fe40829 100644 --- a/docs/ru/table_engines/graphitemergetree.md +++ b/docs/ru/operations/table_engines/graphitemergetree.md @@ -14,7 +14,7 @@ Graphite хранит в ClickHouse полные данные, а получат Используется движок `GraphiteMergeTree`. -Движок наследует свойства MergeTree. Настройки прореживания данных задаются параметром [graphite_rollup](../operations/server_settings/settings.md#server_settings-graphite_rollup) в конфигурации сервера . +Движок наследует свойства MergeTree. Настройки прореживания данных задаются параметром [graphite_rollup](../server_settings/settings.md#server_settings-graphite_rollup) в конфигурации сервера . ## Использование движка diff --git a/docs/ru/table_engines/index.md b/docs/ru/operations/table_engines/index.md similarity index 100% rename from docs/ru/table_engines/index.md rename to docs/ru/operations/table_engines/index.md diff --git a/docs/ru/table_engines/join.md b/docs/ru/operations/table_engines/join.md similarity index 100% rename from docs/ru/table_engines/join.md rename to docs/ru/operations/table_engines/join.md diff --git a/docs/ru/table_engines/kafka.md b/docs/ru/operations/table_engines/kafka.md similarity index 94% rename from docs/ru/table_engines/kafka.md rename to docs/ru/operations/table_engines/kafka.md index 8225192e337..f368fae3860 100644 --- a/docs/ru/table_engines/kafka.md +++ b/docs/ru/operations/table_engines/kafka.md @@ -67,7 +67,7 @@ Kafka(broker_list, topic_list, group_name, format[, schema, num_consumers]) SELECT level, sum(total) FROM daily GROUP BY level; ``` -Для улучшения производительности полученные сообщения группируются в блоки размера [max_insert_block_size](../operations/settings/settings.md#settings-settings-max_insert_block_size). Если блок не удалось сформировать за [stream_flush_interval_ms](../operations/settings/settings.md#settings-settings_stream_flush_interval_ms) миллисекунд, то данные будут сброшены в таблицу независимо от полноты блока. +Для улучшения производительности полученные сообщения группируются в блоки размера [max_insert_block_size](../settings/settings.md#settings-settings-max_insert_block_size). Если блок не удалось сформировать за [stream_flush_interval_ms](../settings/settings.md#settings-settings_stream_flush_interval_ms) миллисекунд, то данные будут сброшены в таблицу независимо от полноты блока. Чтобы остановить получение данных топика или изменить логику преобразования, отсоедините материализованное представление: @@ -97,4 +97,4 @@ Kafka(broker_list, topic_list, group_name, format[, schema, num_consumers]) ``` -В документе [librdkafka configuration reference](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md) можно увидеть список возможных опций конфигурации. Используйте подчёркивания (`_`) вместо точек в конфигурации ClickHouse, например, `check.crcs=true` будет соответствовать `true`. \ No newline at end of file +В документе [librdkafka configuration reference](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md) можно увидеть список возможных опций конфигурации. Используйте подчёркивания (`_`) вместо точек в конфигурации ClickHouse, например, `check.crcs=true` будет соответствовать `true`. diff --git a/docs/ru/table_engines/log.md b/docs/ru/operations/table_engines/log.md similarity index 100% rename from docs/ru/table_engines/log.md rename to docs/ru/operations/table_engines/log.md diff --git a/docs/ru/operations/table_engines/materializedview.md b/docs/ru/operations/table_engines/materializedview.md new file mode 100644 index 00000000000..997d17928c2 --- /dev/null +++ b/docs/ru/operations/table_engines/materializedview.md @@ -0,0 +1,3 @@ +# MaterializedView + +Используется для реализации материализованных представлений (подробнее см. запрос [CREATE TABLE](../../query_language/queries.md#query_language-queries-create_table)). Для хранения данных, использует другой движок, который был указан при создании представления. При чтении из таблицы, просто использует этот движок. diff --git a/docs/ru/table_engines/memory.md b/docs/ru/operations/table_engines/memory.md similarity index 100% rename from docs/ru/table_engines/memory.md rename to docs/ru/operations/table_engines/memory.md diff --git a/docs/ru/table_engines/merge.md b/docs/ru/operations/table_engines/merge.md similarity index 100% rename from docs/ru/table_engines/merge.md rename to docs/ru/operations/table_engines/merge.md diff --git a/docs/ru/table_engines/mergetree.md b/docs/ru/operations/table_engines/mergetree.md similarity index 98% rename from docs/ru/table_engines/mergetree.md rename to docs/ru/operations/table_engines/mergetree.md index b11e00f83d1..62ea3dc2e2f 100644 --- a/docs/ru/table_engines/mergetree.md +++ b/docs/ru/operations/table_engines/mergetree.md @@ -56,7 +56,7 @@ SELECT count() FROM table WHERE ((EventDate >= toDate('2014-01-01') AND EventDat SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%' ``` -Чтобы проверить, сможет ли ClickHouse использовать индекс при выполнении запроса, используйте настройки [force_index_by_date](../operations/settings/settings.md#settings-settings-force_index_by_date) и [force_primary_key](../operations/settings/settings.md#settings-settings-force_primary_key). +Чтобы проверить, сможет ли ClickHouse использовать индекс при выполнении запроса, используйте настройки [force_index_by_date](../settings/settings.md#settings-settings-force_index_by_date) и [force_primary_key](../settings/settings.md#settings-settings-force_primary_key). Индекс по дате обеспечивает чтение только кусков, содержащих даты из нужного диапазона. При этом кусок данных может содержать данные за многие даты (до целого месяца), а в пределах одного куска данные лежат упорядоченными по первичному ключу, который может не содержать дату в качестве первого столбца. В связи с этим, при использовании запроса с указанием условия только на дату, но не на префикс первичного ключа, будет читаться данных больше, чем за одну дату. diff --git a/docs/ru/table_engines/mysql.md b/docs/ru/operations/table_engines/mysql.md similarity index 100% rename from docs/ru/table_engines/mysql.md rename to docs/ru/operations/table_engines/mysql.md diff --git a/docs/ru/table_engines/null.md b/docs/ru/operations/table_engines/null.md similarity index 100% rename from docs/ru/table_engines/null.md rename to docs/ru/operations/table_engines/null.md diff --git a/docs/ru/table_engines/replacingmergetree.md b/docs/ru/operations/table_engines/replacingmergetree.md similarity index 100% rename from docs/ru/table_engines/replacingmergetree.md rename to docs/ru/operations/table_engines/replacingmergetree.md diff --git a/docs/ru/table_engines/replication.md b/docs/ru/operations/table_engines/replication.md similarity index 98% rename from docs/ru/table_engines/replication.md rename to docs/ru/operations/table_engines/replication.md index 22eab99739f..9c9cb69ff1a 100644 --- a/docs/ru/table_engines/replication.md +++ b/docs/ru/operations/table_engines/replication.md @@ -15,7 +15,7 @@ Репликация не зависит от шардирования. На каждом шарде репликация работает независимо. -Реплицируются сжатые данные запросов `INSERT`, `ALTER` (см. подробности в описании запроса [ALTER](../query_language/queries.md#query_language_queries_alter)). +Реплицируются сжатые данные запросов `INSERT`, `ALTER` (см. подробности в описании запроса [ALTER](../../query_language/queries.md#query_language_queries_alter)). Запросы `CREATE`, `DROP`, `ATTACH`, `DETACH`, `RENAME` выполняются на одном сервере и не реплицируются: @@ -48,7 +48,7 @@ Если в конфигурационном файле не настроен ZooKeeper, то вы не сможете создать реплицируемые таблицы, а уже имеющиеся реплицируемые таблицы будут доступны в режиме только на чтение. -При запросах `SELECT`, ZooKeeper не используется, т.е. репликация не влияет на производительность `SELECT` и запросы работают так же быстро, как и для нереплицируемых таблиц. При запросах к распределенным реплицированным таблицам поведение ClickHouse регулируется настройками [max_replica_delay_for_distributed_queries](../operations/settings/settings.md#settings_settings_max_replica_delay_for_distributed_queries) и [fallback_to_stale_replicas_for_distributed_queries](../operations/settings/settings.md#settings-settings-fallback_to_stale_replicas_for_distributed_queries). +При запросах `SELECT`, ZooKeeper не используется, т.е. репликация не влияет на производительность `SELECT` и запросы работают так же быстро, как и для нереплицируемых таблиц. При запросах к распределенным реплицированным таблицам поведение ClickHouse регулируется настройками [max_replica_delay_for_distributed_queries](../settings/settings.md#settings_settings_max_replica_delay_for_distributed_queries) и [fallback_to_stale_replicas_for_distributed_queries](../settings/settings.md#settings-settings-fallback_to_stale_replicas_for_distributed_queries). При каждом запросе `INSERT` (точнее, на каждый вставляемый блок данных; запрос INSERT содержит один блок, или по блоку на каждые `max_insert_block_size = 1048576` строк), делается около десятка записей в ZooKeeper в рамках нескольких транзакций. Это приводит к некоторому увеличению задержек при `INSERT`, по сравнению с нереплицируемыми таблицами. Но если придерживаться обычных рекомендаций - вставлять данные пачками не более одного `INSERT` в секунду, то это не составляет проблем. На всём кластере ClickHouse, использующим для координации один кластер ZooKeeper, может быть в совокупности несколько сотен `INSERT` в секунду. Пропускная способность при вставке данных (количество строчек в секунду) такая же высокая, как для нереплицируемых таблиц. @@ -60,7 +60,7 @@ Каждый блок данных записывается атомарно. Запрос INSERT разбивается на блоки данных размером до `max_insert_block_size = 1048576` строк. То есть, если в запросе `INSERT` менее 1048576 строк, то он делается атомарно. -Блоки данных дедуплицируются. При многократной записи одного и того же блока данных (блоков данных одинакового размера, содержащих одни и те же строчки в одном и том же порядке), блок будет записан только один раз. Это сделано для того, чтобы в случае сбоя в сети, когда клиентское приложение не может понять, были ли данные записаны в БД, можно было просто повторить запрос `INSERT`. При этом не имеет значения, на какую реплику будут отправлены INSERT-ы с одинаковыми данными. То есть, обеспечивается идемпотентность `INSERT`. Параметры дедупликации регулируются настройками сервера [merge_tree](../operations/server_settings/settings.md#server_settings-merge_tree). +Блоки данных дедуплицируются. При многократной записи одного и того же блока данных (блоков данных одинакового размера, содержащих одни и те же строчки в одном и том же порядке), блок будет записан только один раз. Это сделано для того, чтобы в случае сбоя в сети, когда клиентское приложение не может понять, были ли данные записаны в БД, можно было просто повторить запрос `INSERT`. При этом не имеет значения, на какую реплику будут отправлены INSERT-ы с одинаковыми данными. То есть, обеспечивается идемпотентность `INSERT`. Параметры дедупликации регулируются настройками сервера [merge_tree](../server_settings/settings.md#server_settings-merge_tree). При репликации, по сети передаются только исходные вставляемые данные. Дальнейшие преобразования данных (слияния) координируются и делаются на всех репликах одинаковым образом. За счёт этого минимизируется использование сети, и благодаря этому, репликация хорошо работает при расположении реплик в разных датацентрах. (Стоит заметить, что дублирование данных в разных датацентрах, по сути, является основной задачей репликации). diff --git a/docs/ru/table_engines/set.md b/docs/ru/operations/table_engines/set.md similarity index 100% rename from docs/ru/table_engines/set.md rename to docs/ru/operations/table_engines/set.md diff --git a/docs/ru/table_engines/summingmergetree.md b/docs/ru/operations/table_engines/summingmergetree.md similarity index 100% rename from docs/ru/table_engines/summingmergetree.md rename to docs/ru/operations/table_engines/summingmergetree.md diff --git a/docs/ru/table_engines/tinylog.md b/docs/ru/operations/table_engines/tinylog.md similarity index 100% rename from docs/ru/table_engines/tinylog.md rename to docs/ru/operations/table_engines/tinylog.md diff --git a/docs/ru/table_engines/view.md b/docs/ru/operations/table_engines/view.md similarity index 100% rename from docs/ru/table_engines/view.md rename to docs/ru/operations/table_engines/view.md diff --git a/docs/ru/table_engines/materializedview.md b/docs/ru/table_engines/materializedview.md deleted file mode 100644 index 4452855c802..00000000000 --- a/docs/ru/table_engines/materializedview.md +++ /dev/null @@ -1,3 +0,0 @@ -# MaterializedView - -Используется для реализации материализованных представлений (подробнее см. запрос [CREATE TABLE](../query_language/queries.md#query_language-queries-create_table)). Для хранения данных, использует другой движок, который был указан при создании представления. При чтении из таблицы, просто использует этот движок. From bfa380593249e1929e384f301c4181c29ed3de00 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 08:31:32 +0300 Subject: [PATCH 024/425] Specificy in ToC that query language is SQL based. Thats a bit excessive, but catches eye. --- docs/mkdocs_en.yml | 2 +- docs/mkdocs_ru.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index a206bddc1b1..f8c1f8fccee 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -50,7 +50,7 @@ pages: - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' -- 'Query language': +- 'SQL query language': # - 'Query language': 'query_language/index.md' - 'Queries': 'query_language/queries.md' - 'Syntax': 'query_language/syntax.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 3ba1ee6fb16..6f234d9e266 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -50,7 +50,7 @@ pages: - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' -- 'Язык запросов': +- 'SQL язык запросов': # - 'Язык запросов': 'query_language/index.md' - 'Запросы': 'query_language/queries.md' - 'Синтаксис': 'query_language/syntax.md' From 3031cc27888a578d10c4a422f97a1584d6132f8b Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 08:54:29 +0300 Subject: [PATCH 025/425] Move stuff that is part of query language into respective folder --- .../en/operations/server_settings/settings.md | 4 +- docs/en/operations/settings/settings.md | 2 +- .../en/operations/table_engines/dictionary.md | 2 +- .../agg_functions/combinators.md | 0 .../agg_functions/index.md | 0 .../agg_functions/parametric_functions.md | 0 .../agg_functions/reference.md | 4 +- .../dicts/external_dicts.md | 4 +- .../dicts/external_dicts_dict.md | 0 .../dicts/external_dicts_dict_layout.md | 0 .../dicts/external_dicts_dict_lifetime.md | 0 .../dicts/external_dicts_dict_sources.md | 10 +- .../dicts/external_dicts_dict_structure.md | 0 docs/en/{ => query_language}/dicts/index.md | 0 .../dicts/internal_dicts.md | 0 .../functions/arithmetic_functions.md | 0 .../functions/array_functions.md | 4 +- .../functions/array_join.md | 0 .../functions/bit_functions.md | 0 .../functions/comparison_functions.md | 0 .../functions/conditional_functions.md | 0 .../functions/date_time_functions.md | 0 .../functions/encoding_functions.md | 0 .../functions/ext_dict_functions.md | 0 .../functions/hash_functions.md | 0 .../functions/higher_order_functions.md | 0 .../functions/in_functions.md | 0 .../{ => query_language}/functions/index.md | 0 .../functions/ip_address_functions.md | 0 .../functions/json_functions.md | 0 .../functions/logical_functions.md | 0 .../functions/math_functions.md | 0 .../functions/other_functions.md | 0 .../functions/random_functions.md | 0 .../functions/rounding_functions.md | 0 .../functions/splitting_merging_functions.md | 0 .../functions/string_functions.md | 0 .../functions/string_replace_functions.md | 0 .../functions/string_search_functions.md | 0 .../functions/type_conversion_functions.md | 0 .../functions/url_functions.md | 0 .../functions/ym_dict_functions.md | 0 .../index.md => query_language/operators.md} | 0 .../table_functions/file.md | 4 +- .../table_functions/index.md | 0 .../table_functions/merge.md | 0 .../table_functions/numbers.md | 0 .../table_functions/remote.md | 2 +- docs/mkdocs_en.yml | 109 +++++++++-------- docs/mkdocs_ru.yml | 110 +++++++++--------- .../ru/operations/server_settings/settings.md | 4 +- docs/ru/operations/settings/settings.md | 2 +- .../ru/operations/table_engines/dictionary.md | 2 +- .../agg_functions/combinators.md | 0 .../agg_functions/index.md | 0 .../agg_functions/parametric_functions.md | 0 .../agg_functions/reference.md | 4 +- .../dicts/external_dicts.md | 4 +- .../dicts/external_dicts_dict.md | 0 .../dicts/external_dicts_dict_layout.md | 0 .../dicts/external_dicts_dict_lifetime.md | 0 .../dicts/external_dicts_dict_sources.md | 10 +- .../dicts/external_dicts_dict_structure.md | 0 docs/ru/{ => query_language}/dicts/index.md | 0 .../dicts/internal_dicts.md | 0 .../functions/arithmetic_functions.md | 0 .../functions/array_functions.md | 4 +- .../functions/array_join.md | 0 .../functions/bit_functions.md | 0 .../functions/comparison_functions.md | 0 .../functions/conditional_functions.md | 0 .../functions/date_time_functions.md | 0 .../functions/encoding_functions.md | 0 .../functions/ext_dict_functions.md | 0 docs/ru/{ => query_language}/functions/geo.md | 0 .../functions/hash_functions.md | 0 .../functions/higher_order_functions.md | 0 .../functions/in_functions.md | 0 .../{ => query_language}/functions/index.md | 0 .../functions/ip_address_functions.md | 0 .../functions/json_functions.md | 0 .../functions/logical_functions.md | 0 .../functions/math_functions.md | 0 .../functions/other_functions.md | 0 .../functions/random_functions.md | 0 .../functions/rounding_functions.md | 0 .../functions/splitting_merging_functions.md | 0 .../functions/string_functions.md | 0 .../functions/string_replace_functions.md | 0 .../functions/string_search_functions.md | 0 .../functions/type_conversion_functions.md | 0 .../functions/url_functions.md | 0 .../functions/ym_dict_functions.md | 0 .../index.md => query_language/operators.md} | 0 .../table_functions/file.md | 4 +- .../table_functions/index.md | 0 .../table_functions/merge.md | 0 .../table_functions/numbers.md | 0 .../table_functions/remote.md | 2 +- 99 files changed, 143 insertions(+), 148 deletions(-) rename docs/en/{ => query_language}/agg_functions/combinators.md (100%) rename docs/en/{ => query_language}/agg_functions/index.md (100%) rename docs/en/{ => query_language}/agg_functions/parametric_functions.md (100%) rename docs/en/{ => query_language}/agg_functions/reference.md (97%) rename docs/en/{ => query_language}/dicts/external_dicts.md (88%) rename docs/en/{ => query_language}/dicts/external_dicts_dict.md (100%) rename docs/en/{ => query_language}/dicts/external_dicts_dict_layout.md (100%) rename docs/en/{ => query_language}/dicts/external_dicts_dict_lifetime.md (100%) rename docs/en/{ => query_language}/dicts/external_dicts_dict_sources.md (95%) rename docs/en/{ => query_language}/dicts/external_dicts_dict_structure.md (100%) rename docs/en/{ => query_language}/dicts/index.md (100%) rename docs/en/{ => query_language}/dicts/internal_dicts.md (100%) rename docs/en/{ => query_language}/functions/arithmetic_functions.md (100%) rename docs/en/{ => query_language}/functions/array_functions.md (98%) rename docs/en/{ => query_language}/functions/array_join.md (100%) rename docs/en/{ => query_language}/functions/bit_functions.md (100%) rename docs/en/{ => query_language}/functions/comparison_functions.md (100%) rename docs/en/{ => query_language}/functions/conditional_functions.md (100%) rename docs/en/{ => query_language}/functions/date_time_functions.md (100%) rename docs/en/{ => query_language}/functions/encoding_functions.md (100%) rename docs/en/{ => query_language}/functions/ext_dict_functions.md (100%) rename docs/en/{ => query_language}/functions/hash_functions.md (100%) rename docs/en/{ => query_language}/functions/higher_order_functions.md (100%) rename docs/en/{ => query_language}/functions/in_functions.md (100%) rename docs/en/{ => query_language}/functions/index.md (100%) rename docs/en/{ => query_language}/functions/ip_address_functions.md (100%) rename docs/en/{ => query_language}/functions/json_functions.md (100%) rename docs/en/{ => query_language}/functions/logical_functions.md (100%) rename docs/en/{ => query_language}/functions/math_functions.md (100%) rename docs/en/{ => query_language}/functions/other_functions.md (100%) rename docs/en/{ => query_language}/functions/random_functions.md (100%) rename docs/en/{ => query_language}/functions/rounding_functions.md (100%) rename docs/en/{ => query_language}/functions/splitting_merging_functions.md (100%) rename docs/en/{ => query_language}/functions/string_functions.md (100%) rename docs/en/{ => query_language}/functions/string_replace_functions.md (100%) rename docs/en/{ => query_language}/functions/string_search_functions.md (100%) rename docs/en/{ => query_language}/functions/type_conversion_functions.md (100%) rename docs/en/{ => query_language}/functions/url_functions.md (100%) rename docs/en/{ => query_language}/functions/ym_dict_functions.md (100%) rename docs/en/{operators/index.md => query_language/operators.md} (100%) rename docs/en/{ => query_language}/table_functions/file.md (73%) rename docs/en/{ => query_language}/table_functions/index.md (100%) rename docs/en/{ => query_language}/table_functions/merge.md (100%) rename docs/en/{ => query_language}/table_functions/numbers.md (100%) rename docs/en/{ => query_language}/table_functions/remote.md (95%) rename docs/ru/{ => query_language}/agg_functions/combinators.md (100%) rename docs/ru/{ => query_language}/agg_functions/index.md (100%) rename docs/ru/{ => query_language}/agg_functions/parametric_functions.md (100%) rename docs/ru/{ => query_language}/agg_functions/reference.md (98%) rename docs/ru/{ => query_language}/dicts/external_dicts.md (93%) rename docs/ru/{ => query_language}/dicts/external_dicts_dict.md (100%) rename docs/ru/{ => query_language}/dicts/external_dicts_dict_layout.md (100%) rename docs/ru/{ => query_language}/dicts/external_dicts_dict_lifetime.md (100%) rename docs/ru/{ => query_language}/dicts/external_dicts_dict_sources.md (96%) rename docs/ru/{ => query_language}/dicts/external_dicts_dict_structure.md (100%) rename docs/ru/{ => query_language}/dicts/index.md (100%) rename docs/ru/{ => query_language}/dicts/internal_dicts.md (100%) rename docs/ru/{ => query_language}/functions/arithmetic_functions.md (100%) rename docs/ru/{ => query_language}/functions/array_functions.md (98%) rename docs/ru/{ => query_language}/functions/array_join.md (100%) rename docs/ru/{ => query_language}/functions/bit_functions.md (100%) rename docs/ru/{ => query_language}/functions/comparison_functions.md (100%) rename docs/ru/{ => query_language}/functions/conditional_functions.md (100%) rename docs/ru/{ => query_language}/functions/date_time_functions.md (100%) rename docs/ru/{ => query_language}/functions/encoding_functions.md (100%) rename docs/ru/{ => query_language}/functions/ext_dict_functions.md (100%) rename docs/ru/{ => query_language}/functions/geo.md (100%) rename docs/ru/{ => query_language}/functions/hash_functions.md (100%) rename docs/ru/{ => query_language}/functions/higher_order_functions.md (100%) rename docs/ru/{ => query_language}/functions/in_functions.md (100%) rename docs/ru/{ => query_language}/functions/index.md (100%) rename docs/ru/{ => query_language}/functions/ip_address_functions.md (100%) rename docs/ru/{ => query_language}/functions/json_functions.md (100%) rename docs/ru/{ => query_language}/functions/logical_functions.md (100%) rename docs/ru/{ => query_language}/functions/math_functions.md (100%) rename docs/ru/{ => query_language}/functions/other_functions.md (100%) rename docs/ru/{ => query_language}/functions/random_functions.md (100%) rename docs/ru/{ => query_language}/functions/rounding_functions.md (100%) rename docs/ru/{ => query_language}/functions/splitting_merging_functions.md (100%) rename docs/ru/{ => query_language}/functions/string_functions.md (100%) rename docs/ru/{ => query_language}/functions/string_replace_functions.md (100%) rename docs/ru/{ => query_language}/functions/string_search_functions.md (100%) rename docs/ru/{ => query_language}/functions/type_conversion_functions.md (100%) rename docs/ru/{ => query_language}/functions/url_functions.md (100%) rename docs/ru/{ => query_language}/functions/ym_dict_functions.md (100%) rename docs/ru/{operators/index.md => query_language/operators.md} (100%) rename docs/ru/{ => query_language}/table_functions/file.md (82%) rename docs/ru/{ => query_language}/table_functions/index.md (100%) rename docs/ru/{ => query_language}/table_functions/merge.md (100%) rename docs/ru/{ => query_language}/table_functions/numbers.md (100%) rename docs/ru/{ => query_language}/table_functions/remote.md (97%) diff --git a/docs/en/operations/server_settings/settings.md b/docs/en/operations/server_settings/settings.md index 4a56bd057fe..63933362472 100644 --- a/docs/en/operations/server_settings/settings.md +++ b/docs/en/operations/server_settings/settings.md @@ -100,7 +100,7 @@ Path: - Specify the absolute path or the path relative to the server config file. - The path can contain wildcards \* and ?. -See also "[External dictionaries](../../dicts/external_dicts.md#dicts-external_dicts)". +See also "[External dictionaries](../../query_language/dicts/external_dicts.md#dicts-external_dicts)". **Example** @@ -681,7 +681,7 @@ The uncompressed cache is advantageous for very short queries in individual case ## user_files_path -A catalog with user files. Used in a [file()](../../table_functions/file.md#table_functions-file) table function. +A catalog with user files. Used in a [file()](../../query_language/table_functions/file.md#table_functions-file) table function. **Example** diff --git a/docs/en/operations/settings/settings.md b/docs/en/operations/settings/settings.md index fa23583692f..39529fee8c1 100644 --- a/docs/en/operations/settings/settings.md +++ b/docs/en/operations/settings/settings.md @@ -12,7 +12,7 @@ Restrictions: - Only applied for IN and JOIN subqueries. - Used only if a distributed table is used in the FROM clause. -- Not used for a table-valued [ remote](../../table_functions/remote.md#table_functions-remote) function. +- Not used for a table-valued [ remote](../../query_language/table_functions/remote.md#table_functions-remote) function. The possible values ​​are: diff --git a/docs/en/operations/table_engines/dictionary.md b/docs/en/operations/table_engines/dictionary.md index f300bcd3a99..7029abf41ec 100644 --- a/docs/en/operations/table_engines/dictionary.md +++ b/docs/en/operations/table_engines/dictionary.md @@ -61,7 +61,7 @@ WHERE name = 'products' └──────────┴──────┴────────┴─────────────────┴─────────────────┴─────────────────┴───────────────┴─────────────────┘ ``` -You can use the [dictGet*](../../functions/ext_dict_functions.md#ext_dict_functions) function to get the dictionary data in this format. +You can use the [dictGet*](../../query_language/functions/ext_dict_functions.md#ext_dict_functions) function to get the dictionary data in this format. This view isn't helpful when you need to get raw data, or when performing a `JOIN` operation. For these cases, you can use the `Dictionary` engine, which displays the dictionary data in a table. diff --git a/docs/en/agg_functions/combinators.md b/docs/en/query_language/agg_functions/combinators.md similarity index 100% rename from docs/en/agg_functions/combinators.md rename to docs/en/query_language/agg_functions/combinators.md diff --git a/docs/en/agg_functions/index.md b/docs/en/query_language/agg_functions/index.md similarity index 100% rename from docs/en/agg_functions/index.md rename to docs/en/query_language/agg_functions/index.md diff --git a/docs/en/agg_functions/parametric_functions.md b/docs/en/query_language/agg_functions/parametric_functions.md similarity index 100% rename from docs/en/agg_functions/parametric_functions.md rename to docs/en/query_language/agg_functions/parametric_functions.md diff --git a/docs/en/agg_functions/reference.md b/docs/en/query_language/agg_functions/reference.md similarity index 97% rename from docs/en/agg_functions/reference.md rename to docs/en/query_language/agg_functions/reference.md index 2b046d997cc..8cdbd36c2d9 100644 --- a/docs/en/agg_functions/reference.md +++ b/docs/en/query_language/agg_functions/reference.md @@ -32,7 +32,7 @@ anyHeavy(column) **Example** -Take the [OnTime](../getting_started/example_datasets/ontime.md#example_datasets-ontime) data set and select any frequently occurring value in the `AirlineID` column. +Take the [OnTime](../../getting_started/example_datasets/ontime.md#example_datasets-ontime) data set and select any frequently occurring value in the `AirlineID` column. ```sql SELECT anyHeavy(AirlineID) AS res @@ -306,7 +306,7 @@ We recommend using the `N < 10 ` value; performance is reduced with large `N` va **Example** -Take the [OnTime](../getting_started/example_datasets/ontime.md#example_datasets-ontime) data set and select the three most frequently occurring values in the `AirlineID` column. +Take the [OnTime](../../getting_started/example_datasets/ontime.md#example_datasets-ontime) data set and select the three most frequently occurring values in the `AirlineID` column. ```sql SELECT topK(3)(AirlineID) AS res diff --git a/docs/en/dicts/external_dicts.md b/docs/en/query_language/dicts/external_dicts.md similarity index 88% rename from docs/en/dicts/external_dicts.md rename to docs/en/query_language/dicts/external_dicts.md index 673966dc711..af8c280a4e6 100644 --- a/docs/en/dicts/external_dicts.md +++ b/docs/en/query_language/dicts/external_dicts.md @@ -9,9 +9,9 @@ ClickHouse: > - Fully or partially stores dictionaries in RAM. - Periodically updates dictionaries and dynamically loads missing values. In other words, dictionaries can be loaded dynamically. -The configuration of external dictionaries is located in one or more files. The path to the configuration is specified in the [dictionaries_config](../operations/server_settings/settings.md#server_settings-dictionaries_config) parameter. +The configuration of external dictionaries is located in one or more files. The path to the configuration is specified in the [dictionaries_config](../../operations/server_settings/settings.md#server_settings-dictionaries_config) parameter. -Dictionaries can be loaded at server startup or at first use, depending on the [dictionaries_lazy_load](../operations/server_settings/settings.md#server_settings-dictionaries_lazy_load) setting. +Dictionaries can be loaded at server startup or at first use, depending on the [dictionaries_lazy_load](../../operations/server_settings/settings.md#server_settings-dictionaries_lazy_load) setting. The dictionary config file has the following format: diff --git a/docs/en/dicts/external_dicts_dict.md b/docs/en/query_language/dicts/external_dicts_dict.md similarity index 100% rename from docs/en/dicts/external_dicts_dict.md rename to docs/en/query_language/dicts/external_dicts_dict.md diff --git a/docs/en/dicts/external_dicts_dict_layout.md b/docs/en/query_language/dicts/external_dicts_dict_layout.md similarity index 100% rename from docs/en/dicts/external_dicts_dict_layout.md rename to docs/en/query_language/dicts/external_dicts_dict_layout.md diff --git a/docs/en/dicts/external_dicts_dict_lifetime.md b/docs/en/query_language/dicts/external_dicts_dict_lifetime.md similarity index 100% rename from docs/en/dicts/external_dicts_dict_lifetime.md rename to docs/en/query_language/dicts/external_dicts_dict_lifetime.md diff --git a/docs/en/dicts/external_dicts_dict_sources.md b/docs/en/query_language/dicts/external_dicts_dict_sources.md similarity index 95% rename from docs/en/dicts/external_dicts_dict_sources.md rename to docs/en/query_language/dicts/external_dicts_dict_sources.md index 914729767ce..9a4cf5f0dc0 100644 --- a/docs/en/dicts/external_dicts_dict_sources.md +++ b/docs/en/query_language/dicts/external_dicts_dict_sources.md @@ -52,7 +52,7 @@ Example of settings: Setting fields: - `path` – The absolute path to the file. -- `format` – The file format. All the formats described in "[Formats](../interfaces/formats.md#formats)" are supported. +- `format` – The file format. All the formats described in "[Formats](../../interfaces/formats.md#formats)" are supported. @@ -74,7 +74,7 @@ Example of settings: Setting fields: - `command` – The absolute path to the executable file, or the file name (if the program directory is written to `PATH`). -- `format` – The file format. All the formats described in "[Formats](../interfaces/formats.md#formats)" are supported. +- `format` – The file format. All the formats described in "[Formats](../../interfaces/formats.md#formats)" are supported. @@ -93,12 +93,12 @@ Example of settings: ``` -In order for ClickHouse to access an HTTPS resource, you must [configure openSSL](../operations/server_settings/settings.md#server_settings-openSSL) in the server configuration. +In order for ClickHouse to access an HTTPS resource, you must [configure openSSL](../../operations/server_settings/settings.md#server_settings-openSSL) in the server configuration. Setting fields: - `url` – The source URL. -- `format` – The file format. All the formats described in "[Formats](../interfaces/formats.md#formats)" are supported. +- `format` – The file format. All the formats described in "[Formats](../../interfaces/formats.md#formats)" are supported. @@ -361,7 +361,7 @@ Example of settings: Setting fields: -- `host` – The ClickHouse host. If it is a local host, the query is processed without any network activity. To improve fault tolerance, you can create a [Distributed](../operations/table_engines/distributed.md#table_engines-distributed) table and enter it in subsequent configurations. +- `host` – The ClickHouse host. If it is a local host, the query is processed without any network activity. To improve fault tolerance, you can create a [Distributed](../../operations/table_engines/distributed.md#table_engines-distributed) table and enter it in subsequent configurations. - `port` – The port on the ClickHouse server. - `user` – Name of the ClickHouse user. - `password` – Password of the ClickHouse user. diff --git a/docs/en/dicts/external_dicts_dict_structure.md b/docs/en/query_language/dicts/external_dicts_dict_structure.md similarity index 100% rename from docs/en/dicts/external_dicts_dict_structure.md rename to docs/en/query_language/dicts/external_dicts_dict_structure.md diff --git a/docs/en/dicts/index.md b/docs/en/query_language/dicts/index.md similarity index 100% rename from docs/en/dicts/index.md rename to docs/en/query_language/dicts/index.md diff --git a/docs/en/dicts/internal_dicts.md b/docs/en/query_language/dicts/internal_dicts.md similarity index 100% rename from docs/en/dicts/internal_dicts.md rename to docs/en/query_language/dicts/internal_dicts.md diff --git a/docs/en/functions/arithmetic_functions.md b/docs/en/query_language/functions/arithmetic_functions.md similarity index 100% rename from docs/en/functions/arithmetic_functions.md rename to docs/en/query_language/functions/arithmetic_functions.md diff --git a/docs/en/functions/array_functions.md b/docs/en/query_language/functions/array_functions.md similarity index 98% rename from docs/en/functions/array_functions.md rename to docs/en/query_language/functions/array_functions.md index 20a1eac2919..3c9b02041ea 100644 --- a/docs/en/functions/array_functions.md +++ b/docs/en/query_language/functions/array_functions.md @@ -242,7 +242,7 @@ arrayPushBack(array, single_value) **Arguments** - `array` – Array. -- `single_value` – A single value. Only numbers can be added to an array with numbers, and only strings can be added to an array of strings. When adding numbers, ClickHouse automatically sets the `single_value` type for the data type of the array. For more information about ClickHouse data types, read the section "[Data types](../data_types/index.md#data_types)". +- `single_value` – A single value. Only numbers can be added to an array with numbers, and only strings can be added to an array of strings. When adding numbers, ClickHouse automatically sets the `single_value` type for the data type of the array. For more information about ClickHouse data types, read the section "[Data types](../../data_types/index.md#data_types)". **Example** @@ -267,7 +267,7 @@ arrayPushFront(array, single_value) **Arguments** - `array` – Array. -- `single_value` – A single value. Only numbers can be added to an array with numbers, and only strings can be added to an array of strings. When adding numbers, ClickHouse automatically sets the `single_value` type for the data type of the array. For more information about ClickHouse data types, read the section "[Data types](../data_types/index.md#data_types)". +- `single_value` – A single value. Only numbers can be added to an array with numbers, and only strings can be added to an array of strings. When adding numbers, ClickHouse automatically sets the `single_value` type for the data type of the array. For more information about ClickHouse data types, read the section "[Data types](../../data_types/index.md#data_types)". **Example** diff --git a/docs/en/functions/array_join.md b/docs/en/query_language/functions/array_join.md similarity index 100% rename from docs/en/functions/array_join.md rename to docs/en/query_language/functions/array_join.md diff --git a/docs/en/functions/bit_functions.md b/docs/en/query_language/functions/bit_functions.md similarity index 100% rename from docs/en/functions/bit_functions.md rename to docs/en/query_language/functions/bit_functions.md diff --git a/docs/en/functions/comparison_functions.md b/docs/en/query_language/functions/comparison_functions.md similarity index 100% rename from docs/en/functions/comparison_functions.md rename to docs/en/query_language/functions/comparison_functions.md diff --git a/docs/en/functions/conditional_functions.md b/docs/en/query_language/functions/conditional_functions.md similarity index 100% rename from docs/en/functions/conditional_functions.md rename to docs/en/query_language/functions/conditional_functions.md diff --git a/docs/en/functions/date_time_functions.md b/docs/en/query_language/functions/date_time_functions.md similarity index 100% rename from docs/en/functions/date_time_functions.md rename to docs/en/query_language/functions/date_time_functions.md diff --git a/docs/en/functions/encoding_functions.md b/docs/en/query_language/functions/encoding_functions.md similarity index 100% rename from docs/en/functions/encoding_functions.md rename to docs/en/query_language/functions/encoding_functions.md diff --git a/docs/en/functions/ext_dict_functions.md b/docs/en/query_language/functions/ext_dict_functions.md similarity index 100% rename from docs/en/functions/ext_dict_functions.md rename to docs/en/query_language/functions/ext_dict_functions.md diff --git a/docs/en/functions/hash_functions.md b/docs/en/query_language/functions/hash_functions.md similarity index 100% rename from docs/en/functions/hash_functions.md rename to docs/en/query_language/functions/hash_functions.md diff --git a/docs/en/functions/higher_order_functions.md b/docs/en/query_language/functions/higher_order_functions.md similarity index 100% rename from docs/en/functions/higher_order_functions.md rename to docs/en/query_language/functions/higher_order_functions.md diff --git a/docs/en/functions/in_functions.md b/docs/en/query_language/functions/in_functions.md similarity index 100% rename from docs/en/functions/in_functions.md rename to docs/en/query_language/functions/in_functions.md diff --git a/docs/en/functions/index.md b/docs/en/query_language/functions/index.md similarity index 100% rename from docs/en/functions/index.md rename to docs/en/query_language/functions/index.md diff --git a/docs/en/functions/ip_address_functions.md b/docs/en/query_language/functions/ip_address_functions.md similarity index 100% rename from docs/en/functions/ip_address_functions.md rename to docs/en/query_language/functions/ip_address_functions.md diff --git a/docs/en/functions/json_functions.md b/docs/en/query_language/functions/json_functions.md similarity index 100% rename from docs/en/functions/json_functions.md rename to docs/en/query_language/functions/json_functions.md diff --git a/docs/en/functions/logical_functions.md b/docs/en/query_language/functions/logical_functions.md similarity index 100% rename from docs/en/functions/logical_functions.md rename to docs/en/query_language/functions/logical_functions.md diff --git a/docs/en/functions/math_functions.md b/docs/en/query_language/functions/math_functions.md similarity index 100% rename from docs/en/functions/math_functions.md rename to docs/en/query_language/functions/math_functions.md diff --git a/docs/en/functions/other_functions.md b/docs/en/query_language/functions/other_functions.md similarity index 100% rename from docs/en/functions/other_functions.md rename to docs/en/query_language/functions/other_functions.md diff --git a/docs/en/functions/random_functions.md b/docs/en/query_language/functions/random_functions.md similarity index 100% rename from docs/en/functions/random_functions.md rename to docs/en/query_language/functions/random_functions.md diff --git a/docs/en/functions/rounding_functions.md b/docs/en/query_language/functions/rounding_functions.md similarity index 100% rename from docs/en/functions/rounding_functions.md rename to docs/en/query_language/functions/rounding_functions.md diff --git a/docs/en/functions/splitting_merging_functions.md b/docs/en/query_language/functions/splitting_merging_functions.md similarity index 100% rename from docs/en/functions/splitting_merging_functions.md rename to docs/en/query_language/functions/splitting_merging_functions.md diff --git a/docs/en/functions/string_functions.md b/docs/en/query_language/functions/string_functions.md similarity index 100% rename from docs/en/functions/string_functions.md rename to docs/en/query_language/functions/string_functions.md diff --git a/docs/en/functions/string_replace_functions.md b/docs/en/query_language/functions/string_replace_functions.md similarity index 100% rename from docs/en/functions/string_replace_functions.md rename to docs/en/query_language/functions/string_replace_functions.md diff --git a/docs/en/functions/string_search_functions.md b/docs/en/query_language/functions/string_search_functions.md similarity index 100% rename from docs/en/functions/string_search_functions.md rename to docs/en/query_language/functions/string_search_functions.md diff --git a/docs/en/functions/type_conversion_functions.md b/docs/en/query_language/functions/type_conversion_functions.md similarity index 100% rename from docs/en/functions/type_conversion_functions.md rename to docs/en/query_language/functions/type_conversion_functions.md diff --git a/docs/en/functions/url_functions.md b/docs/en/query_language/functions/url_functions.md similarity index 100% rename from docs/en/functions/url_functions.md rename to docs/en/query_language/functions/url_functions.md diff --git a/docs/en/functions/ym_dict_functions.md b/docs/en/query_language/functions/ym_dict_functions.md similarity index 100% rename from docs/en/functions/ym_dict_functions.md rename to docs/en/query_language/functions/ym_dict_functions.md diff --git a/docs/en/operators/index.md b/docs/en/query_language/operators.md similarity index 100% rename from docs/en/operators/index.md rename to docs/en/query_language/operators.md diff --git a/docs/en/table_functions/file.md b/docs/en/query_language/table_functions/file.md similarity index 73% rename from docs/en/table_functions/file.md rename to docs/en/query_language/table_functions/file.md index 1ec3634c6b5..67eb5742988 100644 --- a/docs/en/table_functions/file.md +++ b/docs/en/query_language/table_functions/file.md @@ -4,9 +4,9 @@ `file(path, format, structure)` - returns a table created from a path file with a format type, with columns specified in structure. -path - a relative path to a file from [user_files_path](../operations/server_settings/settings.md#user_files_path). +path - a relative path to a file from [user_files_path](../../operations/server_settings/settings.md#user_files_path). -format - file [format](../interfaces/formats.md#formats). +format - file [format](../../interfaces/formats.md#formats). structure - table structure in 'UserID UInt64, URL String' format. Determines column names and types. diff --git a/docs/en/table_functions/index.md b/docs/en/query_language/table_functions/index.md similarity index 100% rename from docs/en/table_functions/index.md rename to docs/en/query_language/table_functions/index.md diff --git a/docs/en/table_functions/merge.md b/docs/en/query_language/table_functions/merge.md similarity index 100% rename from docs/en/table_functions/merge.md rename to docs/en/query_language/table_functions/merge.md diff --git a/docs/en/table_functions/numbers.md b/docs/en/query_language/table_functions/numbers.md similarity index 100% rename from docs/en/table_functions/numbers.md rename to docs/en/query_language/table_functions/numbers.md diff --git a/docs/en/table_functions/remote.md b/docs/en/query_language/table_functions/remote.md similarity index 95% rename from docs/en/table_functions/remote.md rename to docs/en/query_language/table_functions/remote.md index e26e245207b..8ceaa0cd659 100644 --- a/docs/en/table_functions/remote.md +++ b/docs/en/query_language/table_functions/remote.md @@ -52,7 +52,7 @@ example01-{01..02}-1 If you have multiple pairs of curly brackets, it generates the direct product of the corresponding sets. -Addresses and parts of addresses in curly brackets can be separated by the pipe symbol (|). In this case, the corresponding sets of addresses are interpreted as replicas, and the query will be sent to the first healthy replica. However, the replicas are iterated in the order currently set in the [load_balancing](../operations/settings/settings.md#settings-load_balancing) setting. +Addresses and parts of addresses in curly brackets can be separated by the pipe symbol (|). In this case, the corresponding sets of addresses are interpreted as replicas, and the query will be sent to the first healthy replica. However, the replicas are iterated in the order currently set in the [load_balancing](../../operations/settings/settings.md#settings-load_balancing) setting. Example: diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index f8c1f8fccee..21f9957932a 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -54,62 +54,59 @@ pages: # - 'Query language': 'query_language/index.md' - 'Queries': 'query_language/queries.md' - 'Syntax': 'query_language/syntax.md' - -- 'Table functions': - - 'Introduction': 'table_functions/index.md' - - 'file': 'table_functions/file.md' - - 'merge': 'table_functions/merge.md' - - 'numbers': 'table_functions/numbers.md' - - 'remote': 'table_functions/remote.md' - -- 'Operators': 'operators/index.md' - -- 'Functions': - - 'Introduction': 'functions/index.md' - - 'Arithmetic functions': 'functions/arithmetic_functions.md' - - 'Comparison functions': 'functions/comparison_functions.md' - - 'Logical functions': 'functions/logical_functions.md' - - 'Type conversion functions': 'functions/type_conversion_functions.md' - - 'Functions for working with dates and times': 'functions/date_time_functions.md' - - 'Functions for working with strings': 'functions/string_functions.md' - - 'Functions for searching strings': 'functions/string_search_functions.md' - - 'Functions for searching and replacing in strings': 'functions/string_replace_functions.md' - - 'Conditional functions': 'functions/conditional_functions.md' - - 'Mathematical functions': 'functions/math_functions.md' - - 'Rounding functions': 'functions/rounding_functions.md' - - 'Functions for working with arrays': 'functions/array_functions.md' - - 'Functions for splitting and merging strings and arrays': 'functions/splitting_merging_functions.md' - - 'Bit functions': 'functions/bit_functions.md' - - 'Hash functions': 'functions/hash_functions.md' - - 'Functions for generating pseudo-random numbers': 'functions/random_functions.md' - - 'Encoding functions': 'functions/encoding_functions.md' - - 'Functions for working with URLs': 'functions/url_functions.md' - - 'Functions for working with IP addresses': 'functions/ip_address_functions.md' - - 'Functions for working with JSON.': 'functions/json_functions.md' - - 'Higher-order functions': 'functions/higher_order_functions.md' - - 'Other functions': 'functions/other_functions.md' - - 'Functions for working with external dictionaries': 'functions/ext_dict_functions.md' - - 'Functions for working with Yandex.Metrica dictionaries': 'functions/ym_dict_functions.md' - - 'Functions for implementing the IN operator': 'functions/in_functions.md' - - 'arrayJoin function': 'functions/array_join.md' - -- 'Aggregate functions': - - 'Introduction': 'agg_functions/index.md' - - 'Function reference': 'agg_functions/reference.md' - - 'Aggregate function combinators': 'agg_functions/combinators.md' - - 'Parametric aggregate functions': 'agg_functions/parametric_functions.md' - -- 'Dictionaries': - - 'Introduction': 'dicts/index.md' - - 'External dictionaries': - - 'General desription': 'dicts/external_dicts.md' - - 'Configuring an external dictionary': 'dicts/external_dicts_dict.md' - - 'Storing dictionaries in memory': 'dicts/external_dicts_dict_layout.md' - - 'Dictionary updates': 'dicts/external_dicts_dict_lifetime.md' - - 'Sources of external dictionaries': 'dicts/external_dicts_dict_sources.md' - - 'Dictionary key and fields': 'dicts/external_dicts_dict_structure.md' - - 'Internal dictionaries': 'dicts/internal_dicts.md' - + - 'Operators': 'query_language/operators.md' + - 'Table functions': + - 'Introduction': 'query_language/table_functions/index.md' + - 'file': 'query_language/table_functions/file.md' + - 'merge': 'query_language/table_functions/merge.md' + - 'numbers': 'query_language/table_functions/numbers.md' + - 'remote': 'query_language/table_functions/remote.md' + - 'Functions': + - 'Introduction': 'query_language/functions/index.md' + - 'Arithmetic functions': 'query_language/functions/arithmetic_functions.md' + - 'Comparison functions': 'query_language/functions/comparison_functions.md' + - 'Logical functions': 'query_language/functions/logical_functions.md' + - 'Type conversion functions': 'query_language/functions/type_conversion_functions.md' + - 'Functions for working with dates and times': 'query_language/functions/date_time_functions.md' + - 'Functions for working with strings': 'query_language/functions/string_functions.md' + - 'Functions for searching strings': 'query_language/functions/string_search_functions.md' + - 'Functions for searching and replacing in strings': 'query_language/functions/string_replace_functions.md' + - 'Conditional functions': 'query_language/functions/conditional_functions.md' + - 'Mathematical functions': 'query_language/functions/math_functions.md' + - 'Rounding functions': 'query_language/functions/rounding_functions.md' + - 'Functions for working with arrays': 'query_language/functions/array_functions.md' + - 'Functions for splitting and merging strings and arrays': 'query_language/functions/splitting_merging_functions.md' + - 'Bit functions': 'query_language/functions/bit_functions.md' + - 'Hash functions': 'query_language/functions/hash_functions.md' + - 'Functions for generating pseudo-random numbers': 'query_language/functions/random_functions.md' + - 'Encoding functions': 'query_language/functions/encoding_functions.md' + - 'Functions for working with URLs': 'query_language/functions/url_functions.md' + - 'Functions for working with IP addresses': 'query_language/functions/ip_address_functions.md' + - 'Functions for working with JSON.': 'query_language/functions/json_functions.md' + - 'Higher-order functions': 'query_language/functions/higher_order_functions.md' + - 'Other functions': 'query_language/functions/other_functions.md' + - 'Functions for working with external dictionaries': 'query_language/functions/ext_dict_functions.md' + - 'Functions for working with Yandex.Metrica dictionaries': 'query_language/functions/ym_dict_functions.md' + - 'Functions for implementing the IN operator': 'query_language/functions/in_functions.md' + - 'arrayJoin function': 'query_language/functions/array_join.md' + + - 'Aggregate functions': + - 'Introduction': 'query_language/agg_functions/index.md' + - 'Function reference': 'query_language/agg_functions/reference.md' + - 'Aggregate function combinators': 'query_language/agg_functions/combinators.md' + - 'Parametric aggregate functions': 'query_language/agg_functions/parametric_functions.md' + + - 'Dictionaries': + - 'Introduction': 'query_language/dicts/index.md' + - 'External dictionaries': + - 'General desription': 'query_language/dicts/external_dicts.md' + - 'Configuring an external dictionary': 'query_language/dicts/external_dicts_dict.md' + - 'Storing dictionaries in memory': 'query_language/dicts/external_dicts_dict_layout.md' + - 'Dictionary updates': 'query_language/dicts/external_dicts_dict_lifetime.md' + - 'Sources of external dictionaries': 'query_language/dicts/external_dicts_dict_sources.md' + - 'Dictionary key and fields': 'query_language/dicts/external_dicts_dict_structure.md' + - 'Internal dictionaries': 'query_language/dicts/internal_dicts.md' + - 'Operations': - 'Operations': 'operations/index.md' - 'Table engines': diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 6f234d9e266..277f1e2992e 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -54,62 +54,60 @@ pages: # - 'Язык запросов': 'query_language/index.md' - 'Запросы': 'query_language/queries.md' - 'Синтаксис': 'query_language/syntax.md' - -- 'Табличные функции': - - 'Введение': 'table_functions/index.md' - - 'file': 'table_functions/file.md' - - 'merge': 'table_functions/merge.md' - - 'numbers': 'table_functions/numbers.md' - - 'remote': 'table_functions/remote.md' - -- 'Операторы': 'operators/index.md' - -- 'Функции': - - 'Введение': 'functions/index.md' - - 'Арифметические функции': 'functions/arithmetic_functions.md' - - 'Функции сравнения': 'functions/comparison_functions.md' - - 'Логические функции': 'functions/logical_functions.md' - - 'Функции преобразования типов': 'functions/type_conversion_functions.md' - - 'Функции для работы с датами и временем': 'functions/date_time_functions.md' - - 'Функции для работы со строками': 'functions/string_functions.md' - - 'Функции поиска в строках': 'functions/string_search_functions.md' - - 'Функции поиска и замены в строках': 'functions/string_replace_functions.md' - - 'Условные функции': 'functions/conditional_functions.md' - - 'Математические функции': 'functions/math_functions.md' - - 'Функции округления': 'functions/rounding_functions.md' - - 'Функции по работе с массивами': 'functions/array_functions.md' - - 'Функции разбиения и слияния строк и массивов': 'functions/splitting_merging_functions.md' - - 'Битовые функции': 'functions/bit_functions.md' - - 'Функции хэширования': 'functions/hash_functions.md' - - 'Функции генерации псевдослучайных чисел': 'functions/random_functions.md' - - 'Функции кодирования': 'functions/encoding_functions.md' - - 'Функции для работы с URL': 'functions/url_functions.md' - - 'Функции для работы с IP-адресами': 'functions/ip_address_functions.md' - - 'Функции для работы с JSON.': 'functions/json_functions.md' - - 'Функции высшего порядка': 'functions/higher_order_functions.md' - - 'Прочие функции': 'functions/other_functions.md' - - 'Функции для работы с внешними словарями': 'functions/ext_dict_functions.md' - - 'Функции для работы со словарями Яндекс.Метрики': 'functions/ym_dict_functions.md' - - 'Функции для реализации оператора IN.': 'functions/in_functions.md' - - 'Функция arrayJoin': 'functions/array_join.md' - - 'Функции для работы с географическими координатами': 'functions/geo.md' - -- 'Агрегатные функции': - - 'Введение': 'agg_functions/index.md' - - 'Справочник функций': 'agg_functions/reference.md' - - 'Комбинаторы агрегатных функций': 'agg_functions/combinators.md' - - 'Параметрические агрегатные функции': 'agg_functions/parametric_functions.md' - -- 'Словари': - - 'Введение': 'dicts/index.md' - - 'Внешние словари': - - 'Общее описание': 'dicts/external_dicts.md' - - 'Настройка внешнего словаря': 'dicts/external_dicts_dict.md' - - 'Хранение словарей в памяти': 'dicts/external_dicts_dict_layout.md' - - 'Обновление словарей': 'dicts/external_dicts_dict_lifetime.md' - - 'Источники внешних словарей': 'dicts/external_dicts_dict_sources.md' - - 'Ключ и поля словаря': 'dicts/external_dicts_dict_structure.md' - - 'Встроенные словари': 'dicts/internal_dicts.md' + - 'Операторы': 'query_language/operators.md' + - 'Функции': + - 'Введение': 'query_language/functions/index.md' + - 'Арифметические функции': 'query_language/functions/arithmetic_functions.md' + - 'Функции сравнения': 'query_language/functions/comparison_functions.md' + - 'Логические функции': 'query_language/functions/logical_functions.md' + - 'Функции преобразования типов': 'query_language/functions/type_conversion_functions.md' + - 'Функции для работы с датами и временем': 'query_language/functions/date_time_functions.md' + - 'Функции для работы со строками': 'query_language/functions/string_functions.md' + - 'Функции поиска в строках': 'query_language/functions/string_search_functions.md' + - 'Функции поиска и замены в строках': 'query_language/functions/string_replace_functions.md' + - 'Условные функции': 'query_language/functions/conditional_functions.md' + - 'Математические функции': 'query_language/functions/math_functions.md' + - 'Функции округления': 'query_language/functions/rounding_functions.md' + - 'Функции по работе с массивами': 'query_language/functions/array_functions.md' + - 'Функции разбиения и слияния строк и массивов': 'query_language/functions/splitting_merging_functions.md' + - 'Битовые функции': 'query_language/functions/bit_functions.md' + - 'Функции хэширования': 'query_language/functions/hash_functions.md' + - 'Функции генерации псевдослучайных чисел': 'query_language/functions/random_functions.md' + - 'Функции кодирования': 'query_language/functions/encoding_functions.md' + - 'Функции для работы с URL': 'query_language/functions/url_functions.md' + - 'Функции для работы с IP-адресами': 'query_language/functions/ip_address_functions.md' + - 'Функции для работы с JSON.': 'query_language/functions/json_functions.md' + - 'Функции высшего порядка': 'query_language/functions/higher_order_functions.md' + - 'Прочие функции': 'query_language/functions/other_functions.md' + - 'Функции для работы с внешними словарями': 'query_language/functions/ext_dict_functions.md' + - 'Функции для работы со словарями Яндекс.Метрики': 'query_language/functions/ym_dict_functions.md' + - 'Функции для реализации оператора IN.': 'query_language/functions/in_functions.md' + - 'Функция arrayJoin': 'query_language/functions/array_join.md' + - 'Функции для работы с географическими координатами': 'query_language/functions/geo.md' + + - 'Агрегатные функции': + - 'Введение': 'query_language/agg_functions/index.md' + - 'Справочник функций': 'query_language/agg_functions/reference.md' + - 'Комбинаторы агрегатных функций': 'query_language/agg_functions/combinators.md' + - 'Параметрические агрегатные функции': 'query_language/agg_functions/parametric_functions.md' + + - 'Словари': + - 'Введение': 'query_language/dicts/index.md' + - 'Внешние словари': + - 'Общее описание': 'query_language/dicts/external_dicts.md' + - 'Настройка внешнего словаря': 'query_language/dicts/external_dicts_dict.md' + - 'Хранение словарей в памяти': 'query_language/dicts/external_dicts_dict_layout.md' + - 'Обновление словарей': 'query_language/dicts/external_dicts_dict_lifetime.md' + - 'Источники внешних словарей': 'query_language/dicts/external_dicts_dict_sources.md' + - 'Ключ и поля словаря': 'query_language/dicts/external_dicts_dict_structure.md' + - 'Встроенные словари': 'query_language/dicts/internal_dicts.md' + + - 'Табличные функции': + - 'Введение': 'query_language/table_functions/index.md' + - 'file': 'query_language/table_functions/file.md' + - 'merge': 'query_language/table_functions/merge.md' + - 'numbers': 'query_language/table_functions/numbers.md' + - 'remote': 'query_language/table_functions/remote.md' - 'Эксплуатация': # - 'Эксплуатация': 'operations/index.md' diff --git a/docs/ru/operations/server_settings/settings.md b/docs/ru/operations/server_settings/settings.md index 53d2beb3539..6734f42178b 100644 --- a/docs/ru/operations/server_settings/settings.md +++ b/docs/ru/operations/server_settings/settings.md @@ -100,7 +100,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat - Указывается абсолютным или относительно конфигурационного файла сервера. - Может содержать wildcard-ы \* и ?. -Смотрите также "[Внешние словари](../../dicts/external_dicts.md#dicts-external_dicts)". +Смотрите также "[Внешние словари](../../query_language/dicts/external_dicts.md#dicts-external_dicts)". **Пример** @@ -685,7 +685,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat ## user_files_path -Каталог с пользовательскими файлами. Используется в табличной функции [file()](../../table_functions/file.md#table_functions-file). +Каталог с пользовательскими файлами. Используется в табличной функции [file()](../../query_language/table_functions/file.md#table_functions-file). **Пример** diff --git a/docs/ru/operations/settings/settings.md b/docs/ru/operations/settings/settings.md index e2956380cd4..89a43b6bb6e 100644 --- a/docs/ru/operations/settings/settings.md +++ b/docs/ru/operations/settings/settings.md @@ -13,7 +13,7 @@ ClickHouse применяет настройку в тех случаях, ко - Только подзапросы для IN, JOIN. - Только если в секции FROM используется распределённая таблица, содержащая более одного шарда. - Если подзапрос касается распределенной таблицы, содержащей более одного шарда, -- Не используется в случае табличной функции [remote](../../table_functions/remote.md#table_functions-remote). +- Не используется в случае табличной функции [remote](../../query_language/table_functions/remote.md#table_functions-remote). Возможные значения: diff --git a/docs/ru/operations/table_engines/dictionary.md b/docs/ru/operations/table_engines/dictionary.md index 10e7696949f..bf37867a6a7 100644 --- a/docs/ru/operations/table_engines/dictionary.md +++ b/docs/ru/operations/table_engines/dictionary.md @@ -60,7 +60,7 @@ WHERE name = 'products' └──────────┴──────┴────────┴─────────────────┴─────────────────┴─────────────────┴───────────────┴─────────────────┘ ``` -В таком виде данные из словаря можно получить при помощи функций [dictGet*](../../functions/ext_dict_functions.md#ext_dict_functions). +В таком виде данные из словаря можно получить при помощи функций [dictGet*](../../query_language/functions/ext_dict_functions.md#ext_dict_functions). Такое представление неудобно, когда нам необходимо получить данные в чистом виде, а также при выполнении операции `JOIN`. Для этих случаев можно использовать движок `Dictionary`, который отобразит данные словаря в таблицу. diff --git a/docs/ru/agg_functions/combinators.md b/docs/ru/query_language/agg_functions/combinators.md similarity index 100% rename from docs/ru/agg_functions/combinators.md rename to docs/ru/query_language/agg_functions/combinators.md diff --git a/docs/ru/agg_functions/index.md b/docs/ru/query_language/agg_functions/index.md similarity index 100% rename from docs/ru/agg_functions/index.md rename to docs/ru/query_language/agg_functions/index.md diff --git a/docs/ru/agg_functions/parametric_functions.md b/docs/ru/query_language/agg_functions/parametric_functions.md similarity index 100% rename from docs/ru/agg_functions/parametric_functions.md rename to docs/ru/query_language/agg_functions/parametric_functions.md diff --git a/docs/ru/agg_functions/reference.md b/docs/ru/query_language/agg_functions/reference.md similarity index 98% rename from docs/ru/agg_functions/reference.md rename to docs/ru/query_language/agg_functions/reference.md index 6b30d771dd9..35f79533003 100644 --- a/docs/ru/agg_functions/reference.md +++ b/docs/ru/query_language/agg_functions/reference.md @@ -35,7 +35,7 @@ anyHeavy(column) **Пример** -Возьмем набор данных [OnTime](../getting_started/example_datasets/ontime.md#example_datasets-ontime) и выберем произвольное часто встречающееся значение в столбце `AirlineID`. +Возьмем набор данных [OnTime](../../getting_started/example_datasets/ontime.md#example_datasets-ontime) и выберем произвольное часто встречающееся значение в столбце `AirlineID`. ```sql SELECT anyHeavy(AirlineID) AS res @@ -336,7 +336,7 @@ topK(N)(column) **Пример** -Возьмем набор данных [OnTime](../getting_started/example_datasets/ontime.md#example_datasets-ontime) и выберем 3 наиболее часто встречающихся значения в столбце `AirlineID`. +Возьмем набор данных [OnTime](../../getting_started/example_datasets/ontime.md#example_datasets-ontime) и выберем 3 наиболее часто встречающихся значения в столбце `AirlineID`. ```sql SELECT topK(3)(AirlineID) AS res diff --git a/docs/ru/dicts/external_dicts.md b/docs/ru/query_language/dicts/external_dicts.md similarity index 93% rename from docs/ru/dicts/external_dicts.md rename to docs/ru/query_language/dicts/external_dicts.md index 0b7b9566ff9..9399e316248 100644 --- a/docs/ru/dicts/external_dicts.md +++ b/docs/ru/query_language/dicts/external_dicts.md @@ -9,9 +9,9 @@ ClickHouse: - Полностью или частично хранит словари в оперативной памяти. - Периодически обновляет их и динамически подгружает отсутствующие значения. Т.е. словари можно подгружать динамически. -Конфигурация внешних словарей находится в одном или нескольких файлах. Путь к конфигурации указывается в параметре [dictionaries_config](../operations/server_settings/settings.md#server_settings-dictionaries_config). +Конфигурация внешних словарей находится в одном или нескольких файлах. Путь к конфигурации указывается в параметре [dictionaries_config](../../operations/server_settings/settings.md#server_settings-dictionaries_config). -Словари могут загружаться при старте сервера или при первом использовании, в зависимости от настройки [dictionaries_lazy_load](../operations/server_settings/settings.md#server_settings-dictionaries_lazy_load). +Словари могут загружаться при старте сервера или при первом использовании, в зависимости от настройки [dictionaries_lazy_load](../../operations/server_settings/settings.md#server_settings-dictionaries_lazy_load). Конфигурационный файл словарей имеет вид: diff --git a/docs/ru/dicts/external_dicts_dict.md b/docs/ru/query_language/dicts/external_dicts_dict.md similarity index 100% rename from docs/ru/dicts/external_dicts_dict.md rename to docs/ru/query_language/dicts/external_dicts_dict.md diff --git a/docs/ru/dicts/external_dicts_dict_layout.md b/docs/ru/query_language/dicts/external_dicts_dict_layout.md similarity index 100% rename from docs/ru/dicts/external_dicts_dict_layout.md rename to docs/ru/query_language/dicts/external_dicts_dict_layout.md diff --git a/docs/ru/dicts/external_dicts_dict_lifetime.md b/docs/ru/query_language/dicts/external_dicts_dict_lifetime.md similarity index 100% rename from docs/ru/dicts/external_dicts_dict_lifetime.md rename to docs/ru/query_language/dicts/external_dicts_dict_lifetime.md diff --git a/docs/ru/dicts/external_dicts_dict_sources.md b/docs/ru/query_language/dicts/external_dicts_dict_sources.md similarity index 96% rename from docs/ru/dicts/external_dicts_dict_sources.md rename to docs/ru/query_language/dicts/external_dicts_dict_sources.md index 4811cb03f23..3e30cfba845 100644 --- a/docs/ru/dicts/external_dicts_dict_sources.md +++ b/docs/ru/query_language/dicts/external_dicts_dict_sources.md @@ -52,7 +52,7 @@ Поля настройки: - `path` - Абсолютный путь к файлу. -- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../interfaces/formats.md#formats)". +- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../../interfaces/formats.md#formats)". @@ -74,7 +74,7 @@ Поля настройки: - `command` - Абсолютный путь к исполняемому файлу или имя файла (если каталог программы прописан в `PATH`). -- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../interfaces/formats.md#formats)". +- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../../interfaces/formats.md#formats)". @@ -93,12 +93,12 @@ ``` -Чтобы ClickHouse смог обратиться к HTTPS-ресурсу, необходимо [настроить openSSL](../operations/server_settings/settings.md#server_settings-openSSL) в конфигурации сервера. +Чтобы ClickHouse смог обратиться к HTTPS-ресурсу, необходимо [настроить openSSL](../../operations/server_settings/settings.md#server_settings-openSSL) в конфигурации сервера. Поля настройки: - `url` - URL источника. -- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../interfaces/formats.md#formats)". +- `format` - Формат файла. Поддерживаются все форматы, описанные в разделе "[Форматы](../../interfaces/formats.md#formats)". @@ -355,7 +355,7 @@ MySQL можно подключить на локальном хосте чер Поля настройки: -- `host` - хост ClickHouse. Если host локальный, то запрос выполняется без сетевого взаимодействия. Чтобы повысить отказоустойчивость решения, можно создать таблицу типа [Distributed](../operations/table_engines/distributed.md#table_engines-distributed) и прописать её в дальнейших настройках. +- `host` - хост ClickHouse. Если host локальный, то запрос выполняется без сетевого взаимодействия. Чтобы повысить отказоустойчивость решения, можно создать таблицу типа [Distributed](../../operations/table_engines/distributed.md#table_engines-distributed) и прописать её в дальнейших настройках. - `port` - порт сервера ClickHouse. - `user` - имя пользователя ClickHouse. - `password` - пароль пользователя ClickHouse. diff --git a/docs/ru/dicts/external_dicts_dict_structure.md b/docs/ru/query_language/dicts/external_dicts_dict_structure.md similarity index 100% rename from docs/ru/dicts/external_dicts_dict_structure.md rename to docs/ru/query_language/dicts/external_dicts_dict_structure.md diff --git a/docs/ru/dicts/index.md b/docs/ru/query_language/dicts/index.md similarity index 100% rename from docs/ru/dicts/index.md rename to docs/ru/query_language/dicts/index.md diff --git a/docs/ru/dicts/internal_dicts.md b/docs/ru/query_language/dicts/internal_dicts.md similarity index 100% rename from docs/ru/dicts/internal_dicts.md rename to docs/ru/query_language/dicts/internal_dicts.md diff --git a/docs/ru/functions/arithmetic_functions.md b/docs/ru/query_language/functions/arithmetic_functions.md similarity index 100% rename from docs/ru/functions/arithmetic_functions.md rename to docs/ru/query_language/functions/arithmetic_functions.md diff --git a/docs/ru/functions/array_functions.md b/docs/ru/query_language/functions/array_functions.md similarity index 98% rename from docs/ru/functions/array_functions.md rename to docs/ru/query_language/functions/array_functions.md index 79818574fd7..9c9b244f2ce 100644 --- a/docs/ru/functions/array_functions.md +++ b/docs/ru/query_language/functions/array_functions.md @@ -232,7 +232,7 @@ arrayPushBack(array, single_value) **Аргументы** - `array` - Массив. -- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../data_types/index.md#data_types)". +- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../../data_types/index.md#data_types)". **Пример** @@ -256,7 +256,7 @@ arrayPushFront(array, single_value) **Аргументы** - `array` - Массив. -- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../data_types/index.md#data_types)". +- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../../data_types/index.md#data_types)". **Пример** diff --git a/docs/ru/functions/array_join.md b/docs/ru/query_language/functions/array_join.md similarity index 100% rename from docs/ru/functions/array_join.md rename to docs/ru/query_language/functions/array_join.md diff --git a/docs/ru/functions/bit_functions.md b/docs/ru/query_language/functions/bit_functions.md similarity index 100% rename from docs/ru/functions/bit_functions.md rename to docs/ru/query_language/functions/bit_functions.md diff --git a/docs/ru/functions/comparison_functions.md b/docs/ru/query_language/functions/comparison_functions.md similarity index 100% rename from docs/ru/functions/comparison_functions.md rename to docs/ru/query_language/functions/comparison_functions.md diff --git a/docs/ru/functions/conditional_functions.md b/docs/ru/query_language/functions/conditional_functions.md similarity index 100% rename from docs/ru/functions/conditional_functions.md rename to docs/ru/query_language/functions/conditional_functions.md diff --git a/docs/ru/functions/date_time_functions.md b/docs/ru/query_language/functions/date_time_functions.md similarity index 100% rename from docs/ru/functions/date_time_functions.md rename to docs/ru/query_language/functions/date_time_functions.md diff --git a/docs/ru/functions/encoding_functions.md b/docs/ru/query_language/functions/encoding_functions.md similarity index 100% rename from docs/ru/functions/encoding_functions.md rename to docs/ru/query_language/functions/encoding_functions.md diff --git a/docs/ru/functions/ext_dict_functions.md b/docs/ru/query_language/functions/ext_dict_functions.md similarity index 100% rename from docs/ru/functions/ext_dict_functions.md rename to docs/ru/query_language/functions/ext_dict_functions.md diff --git a/docs/ru/functions/geo.md b/docs/ru/query_language/functions/geo.md similarity index 100% rename from docs/ru/functions/geo.md rename to docs/ru/query_language/functions/geo.md diff --git a/docs/ru/functions/hash_functions.md b/docs/ru/query_language/functions/hash_functions.md similarity index 100% rename from docs/ru/functions/hash_functions.md rename to docs/ru/query_language/functions/hash_functions.md diff --git a/docs/ru/functions/higher_order_functions.md b/docs/ru/query_language/functions/higher_order_functions.md similarity index 100% rename from docs/ru/functions/higher_order_functions.md rename to docs/ru/query_language/functions/higher_order_functions.md diff --git a/docs/ru/functions/in_functions.md b/docs/ru/query_language/functions/in_functions.md similarity index 100% rename from docs/ru/functions/in_functions.md rename to docs/ru/query_language/functions/in_functions.md diff --git a/docs/ru/functions/index.md b/docs/ru/query_language/functions/index.md similarity index 100% rename from docs/ru/functions/index.md rename to docs/ru/query_language/functions/index.md diff --git a/docs/ru/functions/ip_address_functions.md b/docs/ru/query_language/functions/ip_address_functions.md similarity index 100% rename from docs/ru/functions/ip_address_functions.md rename to docs/ru/query_language/functions/ip_address_functions.md diff --git a/docs/ru/functions/json_functions.md b/docs/ru/query_language/functions/json_functions.md similarity index 100% rename from docs/ru/functions/json_functions.md rename to docs/ru/query_language/functions/json_functions.md diff --git a/docs/ru/functions/logical_functions.md b/docs/ru/query_language/functions/logical_functions.md similarity index 100% rename from docs/ru/functions/logical_functions.md rename to docs/ru/query_language/functions/logical_functions.md diff --git a/docs/ru/functions/math_functions.md b/docs/ru/query_language/functions/math_functions.md similarity index 100% rename from docs/ru/functions/math_functions.md rename to docs/ru/query_language/functions/math_functions.md diff --git a/docs/ru/functions/other_functions.md b/docs/ru/query_language/functions/other_functions.md similarity index 100% rename from docs/ru/functions/other_functions.md rename to docs/ru/query_language/functions/other_functions.md diff --git a/docs/ru/functions/random_functions.md b/docs/ru/query_language/functions/random_functions.md similarity index 100% rename from docs/ru/functions/random_functions.md rename to docs/ru/query_language/functions/random_functions.md diff --git a/docs/ru/functions/rounding_functions.md b/docs/ru/query_language/functions/rounding_functions.md similarity index 100% rename from docs/ru/functions/rounding_functions.md rename to docs/ru/query_language/functions/rounding_functions.md diff --git a/docs/ru/functions/splitting_merging_functions.md b/docs/ru/query_language/functions/splitting_merging_functions.md similarity index 100% rename from docs/ru/functions/splitting_merging_functions.md rename to docs/ru/query_language/functions/splitting_merging_functions.md diff --git a/docs/ru/functions/string_functions.md b/docs/ru/query_language/functions/string_functions.md similarity index 100% rename from docs/ru/functions/string_functions.md rename to docs/ru/query_language/functions/string_functions.md diff --git a/docs/ru/functions/string_replace_functions.md b/docs/ru/query_language/functions/string_replace_functions.md similarity index 100% rename from docs/ru/functions/string_replace_functions.md rename to docs/ru/query_language/functions/string_replace_functions.md diff --git a/docs/ru/functions/string_search_functions.md b/docs/ru/query_language/functions/string_search_functions.md similarity index 100% rename from docs/ru/functions/string_search_functions.md rename to docs/ru/query_language/functions/string_search_functions.md diff --git a/docs/ru/functions/type_conversion_functions.md b/docs/ru/query_language/functions/type_conversion_functions.md similarity index 100% rename from docs/ru/functions/type_conversion_functions.md rename to docs/ru/query_language/functions/type_conversion_functions.md diff --git a/docs/ru/functions/url_functions.md b/docs/ru/query_language/functions/url_functions.md similarity index 100% rename from docs/ru/functions/url_functions.md rename to docs/ru/query_language/functions/url_functions.md diff --git a/docs/ru/functions/ym_dict_functions.md b/docs/ru/query_language/functions/ym_dict_functions.md similarity index 100% rename from docs/ru/functions/ym_dict_functions.md rename to docs/ru/query_language/functions/ym_dict_functions.md diff --git a/docs/ru/operators/index.md b/docs/ru/query_language/operators.md similarity index 100% rename from docs/ru/operators/index.md rename to docs/ru/query_language/operators.md diff --git a/docs/ru/table_functions/file.md b/docs/ru/query_language/table_functions/file.md similarity index 82% rename from docs/ru/table_functions/file.md rename to docs/ru/query_language/table_functions/file.md index 73b4edb8be3..f3e35c7f8f0 100644 --- a/docs/ru/table_functions/file.md +++ b/docs/ru/query_language/table_functions/file.md @@ -4,9 +4,9 @@ `file(path, format, structure)` - возвращает таблицу со столбцами, указанными в structure, созданную из файла path типа format. -path - относительный путь до файла от [user_files_path](../operations/server_settings/settings.md#user_files_path). +path - относительный путь до файла от [user_files_path](../../operations/server_settings/settings.md#user_files_path). -format - [формат](../interfaces/formats.md#formats) файла. +format - [формат](../../interfaces/formats.md#formats) файла. structure - структура таблицы в форме 'UserID UInt64, URL String'. Определяет имена и типы столбцов. diff --git a/docs/ru/table_functions/index.md b/docs/ru/query_language/table_functions/index.md similarity index 100% rename from docs/ru/table_functions/index.md rename to docs/ru/query_language/table_functions/index.md diff --git a/docs/ru/table_functions/merge.md b/docs/ru/query_language/table_functions/merge.md similarity index 100% rename from docs/ru/table_functions/merge.md rename to docs/ru/query_language/table_functions/merge.md diff --git a/docs/ru/table_functions/numbers.md b/docs/ru/query_language/table_functions/numbers.md similarity index 100% rename from docs/ru/table_functions/numbers.md rename to docs/ru/query_language/table_functions/numbers.md diff --git a/docs/ru/table_functions/remote.md b/docs/ru/query_language/table_functions/remote.md similarity index 97% rename from docs/ru/table_functions/remote.md rename to docs/ru/query_language/table_functions/remote.md index ea62b52a0a9..71bf70ba8d8 100644 --- a/docs/ru/table_functions/remote.md +++ b/docs/ru/query_language/table_functions/remote.md @@ -52,7 +52,7 @@ example01-{01..02}-1 При наличии нескольких пар фигурных скобок, генерируется прямое произведение соответствующих множеств. -Адреса или их фрагменты в фигурных скобках можно указать через символ |. В этом случае, соответствующие множества адресов понимаются как реплики - запрос будет отправлен на первую живую реплику. При этом, реплики перебираются в порядке, согласно текущей настройке [load_balancing](../operations/settings/settings.md#settings-load_balancing). +Адреса или их фрагменты в фигурных скобках можно указать через символ |. В этом случае, соответствующие множества адресов понимаются как реплики - запрос будет отправлен на первую живую реплику. При этом, реплики перебираются в порядке, согласно текущей настройке [load_balancing](../../operations/settings/settings.md#settings-load_balancing). Пример: From 3e40ef5549c3598e28283e22f409a1ecb98cfba4 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 09:02:58 +0300 Subject: [PATCH 026/425] Move table functions lower in ToC --- docs/mkdocs_en.yml | 14 ++++++-------- docs/mkdocs_ru.yml | 13 ++++++------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 21f9957932a..7cb66a4f591 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -55,12 +55,6 @@ pages: - 'Queries': 'query_language/queries.md' - 'Syntax': 'query_language/syntax.md' - 'Operators': 'query_language/operators.md' - - 'Table functions': - - 'Introduction': 'query_language/table_functions/index.md' - - 'file': 'query_language/table_functions/file.md' - - 'merge': 'query_language/table_functions/merge.md' - - 'numbers': 'query_language/table_functions/numbers.md' - - 'remote': 'query_language/table_functions/remote.md' - 'Functions': - 'Introduction': 'query_language/functions/index.md' - 'Arithmetic functions': 'query_language/functions/arithmetic_functions.md' @@ -89,13 +83,17 @@ pages: - 'Functions for working with Yandex.Metrica dictionaries': 'query_language/functions/ym_dict_functions.md' - 'Functions for implementing the IN operator': 'query_language/functions/in_functions.md' - 'arrayJoin function': 'query_language/functions/array_join.md' - - 'Aggregate functions': - 'Introduction': 'query_language/agg_functions/index.md' - 'Function reference': 'query_language/agg_functions/reference.md' - 'Aggregate function combinators': 'query_language/agg_functions/combinators.md' - 'Parametric aggregate functions': 'query_language/agg_functions/parametric_functions.md' - + - 'Table functions': + - 'Introduction': 'query_language/table_functions/index.md' + - 'file': 'query_language/table_functions/file.md' + - 'merge': 'query_language/table_functions/merge.md' + - 'numbers': 'query_language/table_functions/numbers.md' + - 'remote': 'query_language/table_functions/remote.md' - 'Dictionaries': - 'Introduction': 'query_language/dicts/index.md' - 'External dictionaries': diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 277f1e2992e..545007616cb 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -90,7 +90,12 @@ pages: - 'Справочник функций': 'query_language/agg_functions/reference.md' - 'Комбинаторы агрегатных функций': 'query_language/agg_functions/combinators.md' - 'Параметрические агрегатные функции': 'query_language/agg_functions/parametric_functions.md' - + - 'Табличные функции': + - 'Введение': 'query_language/table_functions/index.md' + - 'file': 'query_language/table_functions/file.md' + - 'merge': 'query_language/table_functions/merge.md' + - 'numbers': 'query_language/table_functions/numbers.md' + - 'remote': 'query_language/table_functions/remote.md' - 'Словари': - 'Введение': 'query_language/dicts/index.md' - 'Внешние словари': @@ -102,12 +107,6 @@ pages: - 'Ключ и поля словаря': 'query_language/dicts/external_dicts_dict_structure.md' - 'Встроенные словари': 'query_language/dicts/internal_dicts.md' - - 'Табличные функции': - - 'Введение': 'query_language/table_functions/index.md' - - 'file': 'query_language/table_functions/file.md' - - 'merge': 'query_language/table_functions/merge.md' - - 'numbers': 'query_language/table_functions/numbers.md' - - 'remote': 'query_language/table_functions/remote.md' - 'Эксплуатация': # - 'Эксплуатация': 'operations/index.md' From b5ca36459c406fdb6b5a46f70b76bb0606ec952c Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 09:36:02 +0300 Subject: [PATCH 027/425] Lost redirects.txt update --- docs/redirects.txt | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/redirects.txt b/docs/redirects.txt index 73803e31a9f..f4172e05333 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -70,3 +70,47 @@ table_engines/set.md operations/table_engines/set.md table_engines/summingmergetree.md operations/table_engines/summingmergetree.md table_engines/tinylog.md operations/table_engines/tinylog.md table_engines/view.md operations/table_engines/view.md +agg_functions/combinators.md query_language/agg_functions/combinators.md +agg_functions/index.md query_language/agg_functions/index.md +agg_functions/parametric_functions.md query_language/agg_functions/parametric_functions.md +agg_functions/reference.md query_language/agg_functions/reference.md +dicts/external_dicts.md query_language/dicts/external_dicts.md +dicts/external_dicts_dict.md query_language/dicts/external_dicts_dict.md +dicts/external_dicts_dict_layout.md query_language/dicts/external_dicts_dict_layout.md +dicts/external_dicts_dict_lifetime.md query_language/dicts/external_dicts_dict_lifetime.md +dicts/external_dicts_dict_sources.md query_language/dicts/external_dicts_dict_sources.md +dicts/external_dicts_dict_structure.md query_language/dicts/external_dicts_dict_structure.md +dicts/index.md query_language/dicts/index.md +dicts/internal_dicts.md query_language/dicts/internal_dicts.md +functions/arithmetic_functions.md query_language/functions/arithmetic_functions.md +functions/array_functions.md query_language/functions/array_functions.md +functions/array_join.md query_language/functions/array_join.md +functions/bit_functions.md query_language/functions/bit_functions.md +functions/comparison_functions.md query_language/functions/comparison_functions.md +functions/conditional_functions.md query_language/functions/conditional_functions.md +functions/date_time_functions.md query_language/functions/date_time_functions.md +functions/encoding_functions.md query_language/functions/encoding_functions.md +functions/ext_dict_functions.md query_language/functions/ext_dict_functions.md +functions/hash_functions.md query_language/functions/hash_functions.md +functions/higher_order_functions.md query_language/functions/higher_order_functions.md +functions/in_functions.md query_language/functions/in_functions.md +functions/index.md query_language/functions/index.md +functions/ip_address_functions.md query_language/functions/ip_address_functions.md +functions/json_functions.md query_language/functions/json_functions.md +functions/logical_functions.md query_language/functions/logical_functions.md +functions/math_functions.md query_language/functions/math_functions.md +functions/other_functions.md query_language/functions/other_functions.md +functions/random_functions.md query_language/functions/random_functions.md +functions/rounding_functions.md query_language/functions/rounding_functions.md +functions/splitting_merging_functions.md query_language/functions/splitting_merging_functions.md +functions/string_functions.md query_language/functions/string_functions.md +functions/string_replace_functions.md query_language/functions/string_replace_functions.md +functions/string_search_functions.md query_language/functions/string_search_functions.md +functions/type_conversion_functions.md query_language/functions/type_conversion_functions.md +functions/url_functions.md query_language/functions/url_functions.md +functions/ym_dict_functions.md query_language/functions/ym_dict_functions.md +table_functions/file.md query_language/table_functions/file.md +table_functions/index.md query_language/table_functions/index.md +table_functions/merge.md query_language/table_functions/merge.md +table_functions/numbers.md query_language/table_functions/numbers.md +table_functions/remote.md query_language/table_functions/remote.md From 0fa70a08193a5fffc5006de1114a8f147c1480b4 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 09:39:49 +0300 Subject: [PATCH 028/425] Do not rely on comments in yaml + fix few ru titles --- docs/mkdocs_en.yml | 10 +++++----- docs/mkdocs_ru.yml | 20 +++++++++---------- .../partials/nav-item.html | 2 ++ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 7cb66a4f591..4fda9b68819 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -2,7 +2,7 @@ pages: - 'ClickHouse': 'index.md' - 'Introduction': -# - 'Введение': 'introduction/index.md' + - 'hidden': 'introduction/index.md' - 'Distinctive features of ClickHouse': 'introduction/distinctive_features.md' - 'ClickHouse features that can be considered disadvantages': 'introduction/features_considered_disadvantages.md' - 'The Yandex.Metrica task': 'introduction/ya_metrika_task.md' @@ -43,15 +43,15 @@ pages: - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' - 'Nested data structures': -# - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' + - 'hidden': 'data_types/nested_data_structures/index.md' - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' - 'Special data types': -# - 'Служебные типы данных': 'data_types/special_data_types/index.md' + - 'hidden': 'data_types/special_data_types/index.md' - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' - 'SQL query language': -# - 'Query language': 'query_language/index.md' + - 'hidden': 'query_language/index.md' - 'Queries': 'query_language/queries.md' - 'Syntax': 'query_language/syntax.md' - 'Operators': 'query_language/operators.md' @@ -157,7 +157,7 @@ pages: - 'clickhouse-local': 'operations/utils/clickhouse-local.md' - 'ClickHouse Development': -# - 'ClickHouse Development': 'development/index.md' + - 'hidden': 'development/index.md' - 'Overview of ClickHouse architecture': 'development/architecture.md' - 'How to build ClickHouse on Linux': 'development/build.md' - 'How to build ClickHouse on Mac OS X': 'development/build_osx.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 545007616cb..c0df56ba466 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -2,7 +2,7 @@ pages: - 'ClickHouse': 'index.md' - 'Введение': -# - 'Введение': 'introduction/index.md' + - 'hidden': 'introduction/index.md' - 'Отличительные возможности ClickHouse': 'introduction/distinctive_features.md' - 'Особенности ClickHouse, которые могут считаться недостатками': 'introduction/features_considered_disadvantages.md' - 'Постановка задачи в Яндекс.Метрике': 'introduction/ya_metrika_task.md' @@ -43,15 +43,15 @@ pages: - 'AggregateFunction(name, types_of_arguments...)': 'data_types/nested_data_structures/aggregatefunction.md' - 'Tuple(T1, T2, ...)': 'data_types/tuple.md' - 'Вложенные структуры данных': -# - 'Вложенные структуры данных': 'data_types/nested_data_structures/index.md' + - 'hidden': 'data_types/nested_data_structures/index.md' - 'Nested(Name1 Type1, Name2 Type2, ...)': 'data_types/nested_data_structures/nested.md' - 'Служебные типы данных': -# - 'Служебные типы данных': 'data_types/special_data_types/index.md' + - 'hidden': 'data_types/special_data_types/index.md' - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' - 'SQL язык запросов': -# - 'Язык запросов': 'query_language/index.md' + - 'hidden': 'query_language/index.md' - 'Запросы': 'query_language/queries.md' - 'Синтаксис': 'query_language/syntax.md' - 'Операторы': 'query_language/operators.md' @@ -109,7 +109,7 @@ pages: - 'Эксплуатация': -# - 'Эксплуатация': 'operations/index.md' + - 'hidden': 'operations/index.md' - 'Движки таблиц': - 'Введение': 'operations/table_engines/index.md' - 'Семейство MergeTree': @@ -158,13 +158,13 @@ pages: - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md' - 'clickhouse-local': 'operations/utils/clickhouse-local.md' -- 'ClickHouse Development': -# - 'ClickHouse Development': 'development/index.md' +- 'Разработка ClickHouse': + - 'hidden': 'development/index.md' - 'Overview of ClickHouse architecture': 'development/architecture.md' - - 'How to build ClickHouse on Linux': 'development/build.md' - - 'How to build ClickHouse on Mac OS X': 'development/build_osx.md' + - 'Как собрать ClickHouse на Linux': 'development/build.md' + - 'Как собрать ClickHouse на Mac OS X': 'development/build_osx.md' - 'Как писать код на C++': 'development/style.md' - - 'How to run ClickHouse tests': 'development/tests.md' + - 'Как запустить тесты': 'development/tests.md' - 'Roadmap': 'roadmap.md' - 'Changelog': 'changelog.md' diff --git a/docs/tools/mkdocs-material-theme/partials/nav-item.html b/docs/tools/mkdocs-material-theme/partials/nav-item.html index c3e0b51ba54..b1794314f12 100644 --- a/docs/tools/mkdocs-material-theme/partials/nav-item.html +++ b/docs/tools/mkdocs-material-theme/partials/nav-item.html @@ -1,3 +1,4 @@ +{% if nav_item.title != "hidden" %} {% set class = "md-nav__item" %} {% if nav_item.active %} {% set class = "md-nav__item md-nav__item--active" %} @@ -52,3 +53,4 @@ {% endif %} +{% endif %} From 3ab9c7368f879d21411f71b02b2b3e4928708f68 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 10:42:59 +0300 Subject: [PATCH 029/425] Extract major parts of queries.md into separate articles --- docs/en/query_language/alter.md | 266 ++++++ .../{queries.md => attach_detach.md} | 0 docs/en/query_language/create.md | 155 ++++ docs/en/query_language/index.md | 5 + docs/en/query_language/insert_into.md | 68 ++ docs/en/query_language/misc.md | 211 +++++ docs/en/query_language/select.md | 850 +++++++++++++++++ docs/mkdocs_en.yml | 10 +- docs/mkdocs_ru.yml | 10 +- docs/redirects.txt | 1 + docs/ru/query_language/alter.md | 265 ++++++ docs/ru/query_language/create.md | 155 ++++ docs/ru/query_language/index.md | 6 + docs/ru/query_language/insert_into.md | 67 ++ docs/ru/query_language/misc.md | 213 +++++ docs/ru/query_language/select.md | 852 ++++++++++++++++++ 16 files changed, 3128 insertions(+), 6 deletions(-) create mode 100644 docs/en/query_language/alter.md rename docs/en/query_language/{queries.md => attach_detach.md} (100%) create mode 100644 docs/en/query_language/create.md create mode 100644 docs/en/query_language/insert_into.md create mode 100644 docs/en/query_language/misc.md create mode 100644 docs/en/query_language/select.md create mode 100644 docs/ru/query_language/alter.md create mode 100644 docs/ru/query_language/create.md create mode 100644 docs/ru/query_language/insert_into.md create mode 100644 docs/ru/query_language/misc.md create mode 100644 docs/ru/query_language/select.md diff --git a/docs/en/query_language/alter.md b/docs/en/query_language/alter.md new file mode 100644 index 00000000000..e428bf27bef --- /dev/null +++ b/docs/en/query_language/alter.md @@ -0,0 +1,266 @@ + + +## ALTER + +The `ALTER` query is only supported for `*MergeTree` tables, as well as `Merge`and`Distributed`. The query has several variations. + +### Column manipulations + +Changing the table structure. + +```sql +ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|MODIFY COLUMN ... +``` + +In the query, specify a list of one or more comma-separated actions. +Each action is an operation on a column. + +The following actions are supported: + +```sql +ADD COLUMN name [type] [default_expr] [AFTER name_after] +``` + +Adds a new column to the table with the specified name, type, and `default_expr` (see the section "Default expressions"). If you specify `AFTER name_after` (the name of another column), the column is added after the specified one in the list of table columns. Otherwise, the column is added to the end of the table. Note that there is no way to add a column to the beginning of a table. For a chain of actions, 'name_after' can be the name of a column that is added in one of the previous actions. + +Adding a column just changes the table structure, without performing any actions with data. The data doesn't appear on the disk after ALTER. If the data is missing for a column when reading from the table, it is filled in with default values (by performing the default expression if there is one, or using zeros or empty strings). If the data is missing for a column when reading from the table, it is filled in with default values (by performing the default expression if there is one, or using zeros or empty strings). The column appears on the disk after merging data parts (see MergeTree). + +This approach allows us to complete the ALTER query instantly, without increasing the volume of old data. + +```sql +DROP COLUMN name +``` + +Deletes the column with the name 'name'. +Deletes data from the file system. Since this deletes entire files, the query is completed almost instantly. + +```sql +MODIFY COLUMN name [type] [default_expr] +``` + +Changes the 'name' column's type to 'type' and/or the default expression to 'default_expr'. When changing the type, values are converted as if the 'toType' function were applied to them. + +If only the default expression is changed, the query doesn't do anything complex, and is completed almost instantly. + +Changing the column type is the only complex action – it changes the contents of files with data. For large tables, this may take a long time. + +There are several processing stages: + +- Preparing temporary (new) files with modified data. +- Renaming old files. +- Renaming the temporary (new) files to the old names. +- Deleting the old files. + +Only the first stage takes time. If there is a failure at this stage, the data is not changed. +If there is a failure during one of the successive stages, data can be restored manually. The exception is if the old files were deleted from the file system but the data for the new files did not get written to the disk and was lost. + +There is no support for changing the column type in arrays and nested data structures. + +The `ALTER` query lets you create and delete separate elements (columns) in nested data structures, but not whole nested data structures. To add a nested data structure, you can add columns with a name like `name.nested_name` and the type `Array(T)`. A nested data structure is equivalent to multiple array columns with a name that has the same prefix before the dot. + +There is no support for deleting columns in the primary key or the sampling key (columns that are in the `ENGINE` expression). Changing the type for columns that are included in the primary key is only possible if this change does not cause the data to be modified (for example, it is allowed to add values to an Enum or change a type with `DateTime` to `UInt32`). + +If the `ALTER` query is not sufficient for making the table changes you need, you can create a new table, copy the data to it using the `INSERT SELECT` query, then switch the tables using the `RENAME` query and delete the old table. + +The `ALTER` query blocks all reads and writes for the table. In other words, if a long `SELECT` is running at the time of the `ALTER` query, the `ALTER` query will wait for it to complete. At the same time, all new queries to the same table will wait while this `ALTER` is running. + +For tables that don't store data themselves (such as `Merge` and `Distributed`), `ALTER` just changes the table structure, and does not change the structure of subordinate tables. For example, when running ALTER for a `Distributed` table, you will also need to run `ALTER` for the tables on all remote servers. + +The `ALTER` query for changing columns is replicated. The instructions are saved in ZooKeeper, then each replica applies them. All `ALTER` queries are run in the same order. The query waits for the appropriate actions to be completed on the other replicas. However, a query to change columns in a replicated table can be interrupted, and all actions will be performed asynchronously. + +### Manipulations with partitions and parts + +It only works for tables in the `MergeTree` family. The following operations are available: + +- `DETACH PARTITION` – Move a partition to the 'detached' directory and forget it. +- `DROP PARTITION` – Delete a partition. +- `ATTACH PART|PARTITION` – Add a new part or partition from the `detached` directory to the table. +- `FREEZE PARTITION` – Create a backup of a partition. +- `FETCH PARTITION` – Download a partition from another server. + +Each type of query is covered separately below. + +A partition in a table is data for a single calendar month. This is determined by the values of the date key specified in the table engine parameters. Each month's data is stored separately in order to simplify manipulations with this data. + +A "part" in the table is part of the data from a single partition, sorted by the primary key. + +You can use the `system.parts` table to view the set of table parts and partitions: + +```sql +SELECT * FROM system.parts WHERE active +``` + +`active` – Only count active parts. Inactive parts are, for example, source parts remaining after merging to a larger part – these parts are deleted approximately 10 minutes after merging. + +Another way to view a set of parts and partitions is to go into the directory with table data. +Data directory: `/var/lib/clickhouse/data/database/table/`,where `/var/lib/clickhouse/` is the path to the ClickHouse data, 'database' is the database name, and 'table' is the table name. Example: + +```bash +$ ls -l /var/lib/clickhouse/data/test/visits/ +total 48 +drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_2_2_0 +drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_4_4_0 +drwxrwxrwx 2 clickhouse clickhouse 4096 May 5 02:55 detached +-rw-rw-rw- 1 clickhouse clickhouse 2 May 5 02:58 increment.txt +``` + +Here, `20140317_20140323_2_2_0` and ` 20140317_20140323_4_4_0` are the directories of data parts. + +Let's break down the name of the first part: `20140317_20140323_2_2_0`. + +- `20140317` is the minimum date of the data in the chunk. +- `20140323` is the maximum date of the data in the chunk. +- `2` is the minimum number of the data block. +- `2` is the maximum number of the data block. +- `0` is the chunk level (the depth of the merge tree it is formed from). + +Each piece relates to a single partition and contains data for just one month. +`201403` is the name of the partition. A partition is a set of parts for a single month. + +On an operating server, you can't manually change the set of parts or their data on the file system, since the server won't know about it. +For non-replicated tables, you can do this when the server is stopped, but we don't recommended it. +For replicated tables, the set of parts can't be changed in any case. + +The `detached` directory contains parts that are not used by the server - detached from the table using the `ALTER ... DETACH` query. Parts that are damaged are also moved to this directory, instead of deleting them. You can add, delete, or modify the data in the 'detached' directory at any time – the server won't know about this until you make the `ALTER TABLE ... ATTACH` query. + +```sql +ALTER TABLE [db.]table DETACH PARTITION 'name' +``` + +Move all data for partitions named 'name' to the 'detached' directory and forget about them. +The partition name is specified in YYYYMM format. It can be indicated in single quotes or without them. + +After the query is executed, you can do whatever you want with the data in the 'detached' directory — delete it from the file system, or just leave it. + +The query is replicated – data will be moved to the 'detached' directory and forgotten on all replicas. The query can only be sent to a leader replica. To find out if a replica is a leader, perform SELECT to the 'system.replicas' system table. Alternatively, it is easier to make a query on all replicas, and all except one will throw an exception. + +```sql +ALTER TABLE [db.]table DROP PARTITION 'name' +``` + +The same as the `DETACH` operation. Deletes data from the table. Data parts will be tagged as inactive and will be completely deleted in approximately 10 minutes. The query is replicated – data will be deleted on all replicas. + +```sql +ALTER TABLE [db.]table ATTACH PARTITION|PART 'name' +``` + +Adds data to the table from the 'detached' directory. + +It is possible to add data for an entire partition or a separate part. For a part, specify the full name of the part in single quotes. + +The query is replicated. Each replica checks whether there is data in the 'detached' directory. If there is data, it checks the integrity, verifies that it matches the data on the server that initiated the query, and then adds it if everything is correct. If not, it downloads data from the query requestor replica, or from another replica where the data has already been added. + +So you can put data in the 'detached' directory on one replica, and use the ALTER ... ATTACH query to add it to the table on all replicas. + +```sql +ALTER TABLE [db.]table FREEZE PARTITION 'name' +``` + +Creates a local backup of one or multiple partitions. The name can be the full name of the partition (for example, 201403), or its prefix (for example, 2014): then the backup will be created for all the corresponding partitions. + +The query does the following: for a data snapshot at the time of execution, it creates hardlinks to table data in the directory `/var/lib/clickhouse/shadow/N/...` + +`/var/lib/clickhouse/` is the working ClickHouse directory from the config. +`N` is the incremental number of the backup. + +The same structure of directories is created inside the backup as inside `/var/lib/clickhouse/`. +It also performs 'chmod' for all files, forbidding writes to them. + +The backup is created almost instantly (but first it waits for current queries to the corresponding table to finish running). At first, the backup doesn't take any space on the disk. As the system works, the backup can take disk space, as data is modified. If the backup is made for old enough data, it won't take space on the disk. + +After creating the backup, data from `/var/lib/clickhouse/shadow/` can be copied to the remote server and then deleted on the local server. +The entire backup process is performed without stopping the server. + +The `ALTER ... FREEZE PARTITION` query is not replicated. A local backup is only created on the local server. + +As an alternative, you can manually copy data from the `/var/lib/clickhouse/data/database/table` directory. +But if you do this while the server is running, race conditions are possible when copying directories with files being added or changed, and the backup may be inconsistent. You can do this if the server isn't running – then the resulting data will be the same as after the `ALTER TABLE t FREEZE PARTITION` query. + +`ALTER TABLE ... FREEZE PARTITION` only copies data, not table metadata. To make a backup of table metadata, copy the file `/var/lib/clickhouse/metadata/database/table.sql` + +To restore from a backup: + +> - Use the CREATE query to create the table if it doesn't exist. The query can be taken from an .sql file (replace `ATTACH` in it with `CREATE`). +- Copy the data from the data/database/table/ directory inside the backup to the `/var/lib/clickhouse/data/database/table/detached/ directory.` +- Run `ALTER TABLE ... ATTACH PARTITION YYYYMM` queries, where `YYYYMM` is the month, for every month. + +In this way, data from the backup will be added to the table. +Restoring from a backup doesn't require stopping the server. + +### Backups and replication + +Replication provides protection from device failures. If all data disappeared on one of your replicas, follow the instructions in the "Restoration after failure" section to restore it. + +For protection from device failures, you must use replication. For more information about replication, see the section "Data replication". + +Backups protect against human error (accidentally deleting data, deleting the wrong data or in the wrong cluster, or corrupting data). +For high-volume databases, it can be difficult to copy backups to remote servers. In such cases, to protect from human error, you can keep a backup on the same server (it will reside in `/var/lib/clickhouse/shadow/`). + +```sql +ALTER TABLE [db.]table FETCH PARTITION 'name' FROM 'path-in-zookeeper' +``` + +This query only works for replicatable tables. + +It downloads the specified partition from the shard that has its `ZooKeeper path` specified in the `FROM` clause, then puts it in the `detached` directory for the specified table. + +Although the query is called `ALTER TABLE`, it does not change the table structure, and does not immediately change the data available in the table. + +Data is placed in the `detached` directory. You can use the `ALTER TABLE ... ATTACH` query to attach the data. + +The ` FROM` clause specifies the path in ` ZooKeeper`. For example, `/clickhouse/tables/01-01/visits`. +Before downloading, the system checks that the partition exists and the table structure matches. The most appropriate replica is selected automatically from the healthy replicas. + +The `ALTER ... FETCH PARTITION` query is not replicated. The partition will be downloaded to the 'detached' directory only on the local server. Note that if after this you use the `ALTER TABLE ... ATTACH` query to add data to the table, the data will be added on all replicas (on one of the replicas it will be added from the 'detached' directory, and on the rest it will be loaded from neighboring replicas). + +### Synchronicity of ALTER queries + +For non-replicatable tables, all `ALTER` queries are performed synchronously. For replicatable tables, the query just adds instructions for the appropriate actions to `ZooKeeper`, and the actions themselves are performed as soon as possible. However, the query can wait for these actions to be completed on all the replicas. + +For `ALTER ... ATTACH|DETACH|DROP` queries, you can use the `replication_alter_partitions_sync` setting to set up waiting. +Possible values: `0` – do not wait; `1` – only wait for own execution (default); `2` – wait for all. + + + +### Mutations + +Mutations are an ALTER query variant that allows changing or deleting rows in a table. In contrast to standard `UPDATE` and `DELETE` queries that are intended for point data changes, mutations are intended for heavy operations that change a lot of rows in a table. + +The functionality is in beta stage and is available starting with the 1.1.54388 version. Currently *MergeTree table engines are supported (both replicated and unreplicated). + +Existing tables are ready for mutations as-is (no conversion necessary), but after the first mutation is applied to a table, its metadata format becomes incompatible with previous server versions and falling back to a previous version becomes impossible. + +At the moment the `ALTER DELETE` command is available: + +```sql +ALTER TABLE [db.]table DELETE WHERE expr +``` + +The expression `expr` must be of UInt8 type. The query deletes rows for which this expression evaluates to a non-zero value. + +One query can contain several commands separated by commas. + +For *MergeTree tables mutations execute by rewriting whole data parts. There is no atomicity - parts are substituted for mutated parts as soon as they are ready and a `SELECT` query that started executing during a mutation will see data from parts that have already been mutated along with data from parts that have not been mutated yet. + +Mutations are totally ordered by their creation order and are applied to each part in that order. Mutations are also partially ordered with INSERTs - data that was inserted into the table before the mutation was submitted will be mutated and data that was inserted after that will not be mutated. Note that mutations do not block INSERTs in any way. + +A mutation query returns immediately after the mutation entry is added (in case of replicated tables to ZooKeeper, for nonreplicated tables - to the filesystem). The mutation itself executes asynchronously using the system profile settings. To track the progress of mutations you can use the `system.mutations` table. A mutation that was successfully submitted will continue to execute even if ClickHouse servers are restarted. There is no way to roll back the mutation once it is submitted. + +#### system.mutations table + +The table contains information about mutations of MergeTree tables and their progress. Each mutation command is represented by a single row. The table has the following columns: + +**database**, **table** - The name of the database and table to which the mutation was applied. + +**mutation_id** - The ID of the mutation. For replicated tables these IDs correspond to znode names in the `/mutations/` directory in ZooKeeper. For unreplicated tables the IDs correspond to file names in the data directory of the table. + +**command** - The mutation command string (the part of the query after `ALTER TABLE [db.]table`). + +**create_time** - When this mutation command was submitted for execution. + +**block_numbers.partition_id**, **block_numbers.number** - A Nested column. For mutations of replicated tables contains one record for each partition: the partition ID and the block number that was acquired by the mutation (in each partition only parts that contain blocks with numbers less than the block number acquired by the mutation in that partition will be mutated). Because in non-replicated tables blocks numbers in all partitions form a single sequence, for mutatations of non-replicated tables the column will contain one record with a single block number acquired by the mutation. + +**parts_to_do** - The number of data parts that need to be mutated for the mutation to finish. + +**is_done** - Is the mutation done? Note that even if `parts_to_do = 0` it is possible that a mutation of a replicated table is not done yet because of a long-running INSERT that will create a new data part that will need to be mutated. + diff --git a/docs/en/query_language/queries.md b/docs/en/query_language/attach_detach.md similarity index 100% rename from docs/en/query_language/queries.md rename to docs/en/query_language/attach_detach.md diff --git a/docs/en/query_language/create.md b/docs/en/query_language/create.md new file mode 100644 index 00000000000..ce07f31a251 --- /dev/null +++ b/docs/en/query_language/create.md @@ -0,0 +1,155 @@ +## CREATE DATABASE + +Creating db_name databases + +```sql +CREATE DATABASE [IF NOT EXISTS] db_name +``` + +`A database` is just a directory for tables. +If `IF NOT EXISTS` is included, the query won't return an error if the database already exists. + + + +## CREATE TABLE + +The `CREATE TABLE` query can have several forms. + +```sql +CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name [ON CLUSTER cluster] +( + name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], + name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2], + ... +) ENGINE = engine +``` + +Creates a table named 'name' in the 'db' database or the current database if 'db' is not set, with the structure specified in brackets and the 'engine' engine. +The structure of the table is a list of column descriptions. If indexes are supported by the engine, they are indicated as parameters for the table engine. + +A column description is `name type` in the simplest case. Example: `RegionID UInt32`. +Expressions can also be defined for default values (see below). + +```sql +CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine] +``` + +Creates a table with the same structure as another table. You can specify a different engine for the table. If the engine is not specified, the same engine will be used as for the `db2.name2` table. + +```sql +CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... +``` + +Creates a table with a structure like the result of the `SELECT` query, with the 'engine' engine, and fills it with data from SELECT. + +In all cases, if `IF NOT EXISTS` is specified, the query won't return an error if the table already exists. In this case, the query won't do anything. + +### Default values + +The column description can specify an expression for a default value, in one of the following ways:`DEFAULT expr`, `MATERIALIZED expr`, `ALIAS expr`. +Example: `URLDomain String DEFAULT domain(URL)`. + +If an expression for the default value is not defined, the default values will be set to zeros for numbers, empty strings for strings, empty arrays for arrays, and `0000-00-00` for dates or `0000-00-00 00:00:00` for dates with time. NULLs are not supported. + +If the default expression is defined, the column type is optional. If there isn't an explicitly defined type, the default expression type is used. Example: `EventDate DEFAULT toDate(EventTime)` – the 'Date' type will be used for the 'EventDate' column. + +If the data type and default expression are defined explicitly, this expression will be cast to the specified type using type casting functions. Example: `Hits UInt32 DEFAULT 0` means the same thing as `Hits UInt32 DEFAULT toUInt32(0)`. + +Default expressions may be defined as an arbitrary expression from table constants and columns. When creating and changing the table structure, it checks that expressions don't contain loops. For INSERT, it checks that expressions are resolvable – that all columns they can be calculated from have been passed. + +`DEFAULT expr` + +Normal default value. If the INSERT query doesn't specify the corresponding column, it will be filled in by computing the corresponding expression. + +`MATERIALIZED expr` + +Materialized expression. Such a column can't be specified for INSERT, because it is always calculated. +For an INSERT without a list of columns, these columns are not considered. +In addition, this column is not substituted when using an asterisk in a SELECT query. This is to preserve the invariant that the dump obtained using `SELECT *` can be inserted back into the table using INSERT without specifying the list of columns. + +`ALIAS expr` + +Synonym. Such a column isn't stored in the table at all. +Its values can't be inserted in a table, and it is not substituted when using an asterisk in a SELECT query. +It can be used in SELECTs if the alias is expanded during query parsing. + +When using the ALTER query to add new columns, old data for these columns is not written. Instead, when reading old data that does not have values for the new columns, expressions are computed on the fly by default. However, if running the expressions requires different columns that are not indicated in the query, these columns will additionally be read, but only for the blocks of data that need it. + +If you add a new column to a table but later change its default expression, the values used for old data will change (for data where values were not stored on the disk). Note that when running background merges, data for columns that are missing in one of the merging parts is written to the merged part. + +It is not possible to set default values for elements in nested data structures. + +### Temporary tables + +In all cases, if `TEMPORARY` is specified, a temporary table will be created. Temporary tables have the following characteristics: + +- Temporary tables disappear when the session ends, including if the connection is lost. +- A temporary table is created with the Memory engine. The other table engines are not supported. +- The DB can't be specified for a temporary table. It is created outside of databases. +- If a temporary table has the same name as another one and a query specifies the table name without specifying the DB, the temporary table will be used. +- For distributed query processing, temporary tables used in a query are passed to remote servers. + +In most cases, temporary tables are not created manually, but when using external data for a query, or for distributed `(GLOBAL) IN`. For more information, see the appropriate sections + +Distributed DDL queries (ON CLUSTER clause) +---------------------------------------------- + +The `CREATE`, `DROP`, `ALTER`, and `RENAME` queries support distributed execution on a cluster. +For example, the following query creates the `all_hits` `Distributed` table on each host in `cluster`: + +```sql +CREATE TABLE IF NOT EXISTS all_hits ON CLUSTER cluster (p Date, i Int32) ENGINE = Distributed(cluster, default, hits) +``` + +In order to run these queries correctly, each host must have the same cluster definition (to simplify syncing configs, you can use substitutions from ZooKeeper). They must also connect to the ZooKeeper servers. +The local version of the query will eventually be implemented on each host in the cluster, even if some hosts are currently not available. The order for executing queries within a single host is guaranteed. +` ALTER` queries are not yet supported for replicated tables. + +## CREATE VIEW + +```sql +CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT ... +``` + +Creates a view. There are two types of views: normal and MATERIALIZED. + +When creating a materialized view, you must specify ENGINE – the table engine for storing data. + +A materialized view works as follows: when inserting data to the table specified in SELECT, part of the inserted data is converted by this SELECT query, and the result is inserted in the view. + +Normal views don't store any data, but just perform a read from another table. In other words, a normal view is nothing more than a saved query. When reading from a view, this saved query is used as a subquery in the FROM clause. + +As an example, assume you've created a view: + +```sql +CREATE VIEW view AS SELECT ... +``` + +and written a query: + +```sql +SELECT a, b, c FROM view +``` + +This query is fully equivalent to using the subquery: + +```sql +SELECT a, b, c FROM (SELECT ...) +``` + +Materialized views store data transformed by the corresponding SELECT query. + +When creating a materialized view, you must specify ENGINE – the table engine for storing data. + +A materialized view is arranged as follows: when inserting data to the table specified in SELECT, part of the inserted data is converted by this SELECT query, and the result is inserted in the view. + +If you specify POPULATE, the existing table data is inserted in the view when creating it, as if making a `CREATE TABLE ... AS SELECT ...` . Otherwise, the query contains only the data inserted in the table after creating the view. We don't recommend using POPULATE, since data inserted in the table during the view creation will not be inserted in it. + +A `SELECT` query can contain `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`... Note that the corresponding conversions are performed independently on each block of inserted data. For example, if `GROUP BY` is set, data is aggregated during insertion, but only within a single packet of inserted data. The data won't be further aggregated. The exception is when using an ENGINE that independently performs data aggregation, such as `SummingMergeTree`. + +The execution of `ALTER` queries on materialized views has not been fully developed, so they might be inconvenient. If the materialized view uses the construction ``TO [db.]name``, you can ``DETACH`` the view, run ``ALTER`` for the target table, and then ``ATTACH`` the previously detached (``DETACH``) view. + +Views look the same as normal tables. For example, they are listed in the result of the `SHOW TABLES` query. + +There isn't a separate query for deleting views. To delete a view, use `DROP TABLE`. + diff --git a/docs/en/query_language/index.md b/docs/en/query_language/index.md index 769d94eb4fd..4f9e3704d12 100644 --- a/docs/en/query_language/index.md +++ b/docs/en/query_language/index.md @@ -1,2 +1,7 @@ # Query language +* [SELECT](select.md) +* [INSERT INTO](insert_into.md) +* [CREATE](create.md) +* [ALTER](alter.md) +* [Other kinds of queries](misc.md) diff --git a/docs/en/query_language/insert_into.md b/docs/en/query_language/insert_into.md new file mode 100644 index 00000000000..e485180fe36 --- /dev/null +++ b/docs/en/query_language/insert_into.md @@ -0,0 +1,68 @@ + + +## INSERT + +Adding data. + +Basic query format: + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ... +``` + +The query can specify a list of columns to insert `[(c1, c2, c3)]`. In this case, the rest of the columns are filled with: + +- The values calculated from the `DEFAULT` expressions specified in the table definition. +- Zeros and empty strings, if `DEFAULT` expressions are not defined. + +If [strict_insert_defaults=1](../operations/settings/settings.md#settings-strict_insert_defaults), columns that do not have `DEFAULT` defined must be listed in the query. + +Data can be passed to the INSERT in any [format](../interfaces/formats.md#formats) supported by ClickHouse. The format must be specified explicitly in the query: + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set +``` + +For example, the following query format is identical to the basic version of INSERT ... VALUES: + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ... +``` + +ClickHouse removes all spaces and one line feed (if there is one) before the data. When forming a query, we recommend putting the data on a new line after the query operators (this is important if the data begins with spaces). + +Example: + +```sql +INSERT INTO t FORMAT TabSeparated +11 Hello, world! +22 Qwerty +``` + +You can insert data separately from the query by using the command-line client or the HTTP interface. For more information, see the section "[Interfaces](../interfaces/index.md#interfaces)". + +### Inserting the results of `SELECT` + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] SELECT ... +``` + +Columns are mapped according to their position in the SELECT clause. However, their names in the SELECT expression and the table for INSERT may differ. If necessary, type casting is performed. + +None of the data formats except Values allow setting values to expressions such as `now()`, `1 + 2`, and so on. The Values format allows limited use of expressions, but this is not recommended, because in this case inefficient code is used for their execution. + +Other queries for modifying data parts are not supported: `UPDATE`, `DELETE`, `REPLACE`, `MERGE`, `UPSERT`, `INSERT UPDATE`. +However, you can delete old data using `ALTER TABLE ... DROP PARTITION`. + +### Performance considerations + +`INSERT` sorts the input data by primary key and splits them into partitions by month. If you insert data for mixed months, it can significantly reduce the performance of the `INSERT` query. To avoid this: + +- Add data in fairly large batches, such as 100,000 rows at a time. +- Group data by month before uploading it to ClickHouse. + +Performance will not decrease if: + +- Data is added in real time. +- You upload data that is usually sorted by time. + diff --git a/docs/en/query_language/misc.md b/docs/en/query_language/misc.md new file mode 100644 index 00000000000..237c58902a3 --- /dev/null +++ b/docs/en/query_language/misc.md @@ -0,0 +1,211 @@ +# Miscellaneous queries + +## ATTACH + +This query is exactly the same as `CREATE`, but + +- instead of the word `CREATE` it uses the word `ATTACH`. +- The query doesn't create data on the disk, but assumes that data is already in the appropriate places, and just adds information about the table to the server. +After executing an ATTACH query, the server will know about the existence of the table. + +If the table was previously detached (``DETACH``), meaning that its structure is known, you can use shorthand without defining the structure. + +```sql +ATTACH TABLE [IF NOT EXISTS] [db.]name +``` + +This query is used when starting the server. The server stores table metadata as files with `ATTACH` queries, which it simply runs at launch (with the exception of system tables, which are explicitly created on the server). + +## DROP + +This query has two types: `DROP DATABASE` and `DROP TABLE`. + +```sql +DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster] +``` + +Deletes all tables inside the 'db' database, then deletes the 'db' database itself. +If `IF EXISTS` is specified, it doesn't return an error if the database doesn't exist. + +```sql +DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster] +``` + +Deletes the table. +If `IF EXISTS` is specified, it doesn't return an error if the table doesn't exist or the database doesn't exist. + +## DETACH + +Deletes information about the 'name' table from the server. The server stops knowing about the table's existence. + +```sql +DETACH TABLE [IF EXISTS] [db.]name +``` + +This does not delete the table's data or metadata. On the next server launch, the server will read the metadata and find out about the table again. +Similarly, a "detached" table can be re-attached using the `ATTACH` query (with the exception of system tables, which do not have metadata stored for them). + +There is no `DETACH DATABASE` query. + +## RENAME + +Renames one or more tables. + +```sql +RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... [ON CLUSTER cluster] +``` + +All tables are renamed under global locking. Renaming tables is a light operation. If you indicated another database after TO, the table will be moved to this database. However, the directories with databases must reside in the same file system (otherwise, an error is returned). + +## SHOW DATABASES + +```sql +SHOW DATABASES [INTO OUTFILE filename] [FORMAT format] +``` + +Prints a list of all databases. +This query is identical to `SELECT name FROM system.databases [INTO OUTFILE filename] [FORMAT format]`. + +See also the section "Formats". + +## SHOW TABLES + +```sql +SHOW [TEMPORARY] TABLES [FROM db] [LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format] +``` + +Displays a list of tables + +- tables from the current database, or from the 'db' database if "FROM db" is specified. +- all tables, or tables whose name matches the pattern, if "LIKE 'pattern'" is specified. + +This query is identical to: `SELECT name FROM system.tables WHERE database = 'db' [AND name LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]`. + +See also the section "LIKE operator". + +## SHOW PROCESSLIST + +```sql +SHOW PROCESSLIST [INTO OUTFILE filename] [FORMAT format] +``` + +Outputs a list of queries currently being processed, other than `SHOW PROCESSLIST` queries. + +Prints a table containing the columns: + +**user** – The user who made the query. Keep in mind that for distributed processing, queries are sent to remote servers under the 'default' user. SHOW PROCESSLIST shows the username for a specific query, not for a query that this query initiated. + +**address** – The name of the host that the query was sent from. For distributed processing, on remote servers, this is the name of the query requestor host. To track where a distributed query was originally made from, look at SHOW PROCESSLIST on the query requestor server. + +**elapsed** – The execution time, in seconds. Queries are output in order of decreasing execution time. + +**rows_read**, **bytes_read** – How many rows and bytes of uncompressed data were read when processing the query. For distributed processing, data is totaled from all the remote servers. This is the data used for restrictions and quotas. + +**memory_usage** – Current RAM usage in bytes. See the setting 'max_memory_usage'. + +**query** – The query itself. In INSERT queries, the data for insertion is not output. + +**query_id** – The query identifier. Non-empty only if it was explicitly defined by the user. For distributed processing, the query ID is not passed to remote servers. + +This query is identical to: `SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]`. + +Tip (execute in the console): + +```bash +watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'" +``` + +## SHOW CREATE TABLE + +```sql +SHOW CREATE [TEMPORARY] TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] +``` + +Returns a single `String`-type 'statement' column, which contains a single value – the `CREATE` query used for creating the specified table. + +## DESCRIBE TABLE + +```sql +DESC|DESCRIBE TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] +``` + +Returns two `String`-type columns: `name` and `type`, which indicate the names and types of columns in the specified table. + +Nested data structures are output in "expanded" format. Each column is shown separately, with the name after a dot. + +## EXISTS + +```sql +EXISTS [TEMPORARY] TABLE [db.]name [INTO OUTFILE filename] [FORMAT format] +``` + +Returns a single `UInt8`-type column, which contains the single value `0` if the table or database doesn't exist, or `1` if the table exists in the specified database. + +## USE + +```sql +USE db +``` + +Lets you set the current database for the session. +The current database is used for searching for tables if the database is not explicitly defined in the query with a dot before the table name. +This query can't be made when using the HTTP protocol, since there is no concept of a session. + +## SET + +```sql +SET param = value +``` + +Allows you to set `param` to `value`. You can also make all the settings from the specified settings profile in a single query. To do this, specify 'profile' as the setting name. For more information, see the section "Settings". +The setting is made for the session, or for the server (globally) if `GLOBAL` is specified. +When making a global setting, the setting is not applied to sessions already running, including the current session. It will only be used for new sessions. + +When the server is restarted, global settings made using `SET` are lost. +To make settings that persist after a server restart, you can only use the server's config file. + +## OPTIMIZE + +```sql +OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] +``` + +Asks the table engine to do something for optimization. +Supported only by `*MergeTree` engines, in which this query initializes a non-scheduled merge of data parts. +If you specify a `PARTITION`, only the specified partition will be optimized. +If you specify `FINAL`, optimization will be performed even when all the data is already in one part. + +## KILL QUERY + +```sql +KILL QUERY + WHERE + [SYNC|ASYNC|TEST] + [FORMAT format] +``` + +Attempts to forcibly terminate the currently running queries. +The queries to terminate are selected from the system.processes table using the criteria defined in the `WHERE` clause of the `KILL` query. + +Examples: + +```sql +-- Forcibly terminates all queries with the specified query_id: +KILL QUERY WHERE query_id='2-857d-4a57-9ee0-327da5d60a90' + +-- Synchronously terminates all queries run by 'username': +KILL QUERY WHERE user='username' SYNC +``` + +Read-only users can only stop their own queries. + +By default, the asynchronous version of queries is used (`ASYNC`), which doesn't wait for confirmation that queries have stopped. + +The synchronous version (`SYNC`) waits for all queries to stop and displays information about each process as it stops. +The response contains the `kill_status` column, which can take the following values: + +1. 'finished' – The query was terminated successfully. +2. 'waiting' – Waiting for the query to end after sending it a signal to terminate. +3. The other values ​​explain why the query can't be stopped. + +A test query (`TEST`) only checks the user's rights and displays a list of queries to stop. diff --git a/docs/en/query_language/select.md b/docs/en/query_language/select.md new file mode 100644 index 00000000000..70df9020f57 --- /dev/null +++ b/docs/en/query_language/select.md @@ -0,0 +1,850 @@ +# SELECT queries syntax + +`SELECT` performs data retieval. + +```sql +SELECT [DISTINCT] expr_list + [FROM [db.]table | (subquery) | table_function] [FINAL] + [SAMPLE sample_coeff] + [ARRAY JOIN ...] + [GLOBAL] ANY|ALL INNER|LEFT JOIN (subquery)|table USING columns_list + [PREWHERE expr] + [WHERE expr] + [GROUP BY expr_list] [WITH TOTALS] + [HAVING expr] + [ORDER BY expr_list] + [LIMIT [n, ]m] + [UNION ALL ...] + [INTO OUTFILE filename] + [FORMAT format] + [LIMIT n BY columns] +``` + +All the clauses are optional, except for the required list of expressions immediately after SELECT. +The clauses below are described in almost the same order as in the query execution conveyor. + +If the query omits the `DISTINCT`, `GROUP BY` and `ORDER BY` clauses and the `IN` and `JOIN` subqueries, the query will be completely stream processed, using O(1) amount of RAM. +Otherwise, the query might consume a lot of RAM if the appropriate restrictions are not specified: `max_memory_usage`, `max_rows_to_group_by`, `max_rows_to_sort`, `max_rows_in_distinct`, `max_bytes_in_distinct`, `max_rows_in_set`, `max_bytes_in_set`, `max_rows_in_join`, `max_bytes_in_join`, `max_bytes_before_external_sort`, `max_bytes_before_external_group_by`. For more information, see the section "Settings". It is possible to use external sorting (saving temporary tables to a disk) and external aggregation. `The system does not have "merge join"`. + +### FROM clause + +If the FROM clause is omitted, data will be read from the `system.one` table. +The 'system.one' table contains exactly one row (this table fulfills the same purpose as the DUAL table found in other DBMSs). + +The FROM clause specifies the table to read data from, or a subquery, or a table function; ARRAY JOIN and the regular JOIN may also be included (see below). + +Instead of a table, the SELECT subquery may be specified in brackets. +In this case, the subquery processing pipeline will be built into the processing pipeline of an external query. +In contrast to standard SQL, a synonym does not need to be specified after a subquery. For compatibility, it is possible to write 'AS name' after a subquery, but the specified name isn't used anywhere. + +A table function may be specified instead of a table. For more information, see the section "Table functions". + +To execute a query, all the columns listed in the query are extracted from the appropriate table. Any columns not needed for the external query are thrown out of the subqueries. +If a query does not list any columns (for example, SELECT count() FROM t), some column is extracted from the table anyway (the smallest one is preferred), in order to calculate the number of rows. + +The FINAL modifier can be used only for a SELECT from a CollapsingMergeTree table. When you specify FINAL, data is selected fully "collapsed". Keep in mind that using FINAL leads to a selection that includes columns related to the primary key, in addition to the columns specified in the SELECT. Additionally, the query will be executed in a single stream, and data will be merged during query execution. This means that when using FINAL, the query is processed more slowly. In most cases, you should avoid using FINAL. For more information, see the section "CollapsingMergeTree engine". + +### SAMPLE clause + +The SAMPLE clause allows for approximated query processing. Approximated query processing is only supported by MergeTree\* type tables, and only if the sampling expression was specified during table creation (see the section "MergeTree engine"). + +`SAMPLE` has the `format SAMPLE k`, where `k` is a decimal number from 0 to 1, or `SAMPLE n`, where 'n' is a sufficiently large integer. + +In the first case, the query will be executed on 'k' percent of data. For example, `SAMPLE 0.1` runs the query on 10% of data. +In the second case, the query will be executed on a sample of no more than 'n' rows. For example, `SAMPLE 10000000` runs the query on a maximum of 10,000,000 rows. + +Example: + +```sql +SELECT + Title, + count() * 10 AS PageViews +FROM hits_distributed +SAMPLE 0.1 +WHERE + CounterID = 34 + AND toDate(EventDate) >= toDate('2013-01-29') + AND toDate(EventDate) <= toDate('2013-02-04') + AND NOT DontCountHits + AND NOT Refresh + AND Title != '' +GROUP BY Title +ORDER BY PageViews DESC LIMIT 1000 +``` + +In this example, the query is executed on a sample from 0.1 (10%) of data. Values of aggregate functions are not corrected automatically, so to get an approximate result, the value 'count()' is manually multiplied by 10. + +When using something like `SAMPLE 10000000`, there isn't any information about which relative percent of data was processed or what the aggregate functions should be multiplied by, so this method of writing is not always appropriate to the situation. + +A sample with a relative coefficient is "consistent": if we look at all possible data that could be in the table, a sample (when using a single sampling expression specified during table creation) with the same coefficient always selects the same subset of possible data. In other words, a sample from different tables on different servers at different times is made the same way. + +For example, a sample of user IDs takes rows with the same subset of all the possible user IDs from different tables. This allows using the sample in subqueries in the IN clause, as well as for manually correlating results of different queries with samples. + +### ARRAY JOIN clause + +Allows executing JOIN with an array or nested data structure. The intent is similar to the 'arrayJoin' function, but its functionality is broader. + +`ARRAY JOIN` is essentially `INNER JOIN` with an array. Example: + +```text +:) CREATE TABLE arrays_test (s String, arr Array(UInt8)) ENGINE = Memory + +CREATE TABLE arrays_test +( + s String, + arr Array(UInt8) +) ENGINE = Memory + +Ok. + +0 rows in set. Elapsed: 0.001 sec. + +:) INSERT INTO arrays_test VALUES ('Hello', [1,2]), ('World', [3,4,5]), ('Goodbye', []) + +INSERT INTO arrays_test VALUES + +Ok. + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT * FROM arrays_test + +SELECT * +FROM arrays_test + +┌─s───────┬─arr─────┐ +│ Hello │ [1,2] │ +│ World │ [3,4,5] │ +│ Goodbye │ [] │ +└─────────┴─────────┘ + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT s, arr FROM arrays_test ARRAY JOIN arr + +SELECT s, arr +FROM arrays_test +ARRAY JOIN arr + +┌─s─────┬─arr─┐ +│ Hello │ 1 │ +│ Hello │ 2 │ +│ World │ 3 │ +│ World │ 4 │ +│ World │ 5 │ +└───────┴─────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +An alias can be specified for an array in the ARRAY JOIN clause. In this case, an array item can be accessed by this alias, but the array itself by the original name. Example: + +```text +:) SELECT s, arr, a FROM arrays_test ARRAY JOIN arr AS a + +SELECT s, arr, a +FROM arrays_test +ARRAY JOIN arr AS a + +┌─s─────┬─arr─────┬─a─┐ +│ Hello │ [1,2] │ 1 │ +│ Hello │ [1,2] │ 2 │ +│ World │ [3,4,5] │ 3 │ +│ World │ [3,4,5] │ 4 │ +│ World │ [3,4,5] │ 5 │ +└───────┴─────────┴───┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +Multiple arrays of the same size can be comma-separated in the ARRAY JOIN clause. In this case, JOIN is performed with them simultaneously (the direct sum, not the direct product). Example: + +```text +:) SELECT s, arr, a, num, mapped FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(x -> x + 1, arr) AS mapped + +SELECT s, arr, a, num, mapped +FROM arrays_test +ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(lambda(tuple(x), plus(x, 1)), arr) AS mapped + +┌─s─────┬─arr─────┬─a─┬─num─┬─mapped─┐ +│ Hello │ [1,2] │ 1 │ 1 │ 2 │ +│ Hello │ [1,2] │ 2 │ 2 │ 3 │ +│ World │ [3,4,5] │ 3 │ 1 │ 4 │ +│ World │ [3,4,5] │ 4 │ 2 │ 5 │ +│ World │ [3,4,5] │ 5 │ 3 │ 6 │ +└───────┴─────────┴───┴─────┴────────┘ + +5 rows in set. Elapsed: 0.002 sec. + +:) SELECT s, arr, a, num, arrayEnumerate(arr) FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num + +SELECT s, arr, a, num, arrayEnumerate(arr) +FROM arrays_test +ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num + +┌─s─────┬─arr─────┬─a─┬─num─┬─arrayEnumerate(arr)─┐ +│ Hello │ [1,2] │ 1 │ 1 │ [1,2] │ +│ Hello │ [1,2] │ 2 │ 2 │ [1,2] │ +│ World │ [3,4,5] │ 3 │ 1 │ [1,2,3] │ +│ World │ [3,4,5] │ 4 │ 2 │ [1,2,3] │ +│ World │ [3,4,5] │ 5 │ 3 │ [1,2,3] │ +└───────┴─────────┴───┴─────┴─────────────────────┘ + +5 rows in set. Elapsed: 0.002 sec. +``` + +ARRAY JOIN also works with nested data structures. Example: + +```text +:) CREATE TABLE nested_test (s String, nest Nested(x UInt8, y UInt32)) ENGINE = Memory + +CREATE TABLE nested_test +( + s String, + nest Nested( + x UInt8, + y UInt32) +) ENGINE = Memory + +Ok. + +0 rows in set. Elapsed: 0.006 sec. + +:) INSERT INTO nested_test VALUES ('Hello', [1,2], [10,20]), ('World', [3,4,5], [30,40,50]), ('Goodbye', [], []) + +INSERT INTO nested_test VALUES + +Ok. + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT * FROM nested_test + +SELECT * +FROM nested_test + +┌─s───────┬─nest.x──┬─nest.y─────┐ +│ Hello │ [1,2] │ [10,20] │ +│ World │ [3,4,5] │ [30,40,50] │ +│ Goodbye │ [] │ [] │ +└─────────┴─────────┴────────────┘ + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest + +SELECT s, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN nest + +┌─s─────┬─nest.x─┬─nest.y─┐ +│ Hello │ 1 │ 10 │ +│ Hello │ 2 │ 20 │ +│ World │ 3 │ 30 │ +│ World │ 4 │ 40 │ +│ World │ 5 │ 50 │ +└───────┴────────┴────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +When specifying names of nested data structures in ARRAY JOIN, the meaning is the same as ARRAY JOIN with all the array elements that it consists of. Example: + +```text +:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x, nest.y + +SELECT s, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN `nest.x`, `nest.y` + +┌─s─────┬─nest.x─┬─nest.y─┐ +│ Hello │ 1 │ 10 │ +│ Hello │ 2 │ 20 │ +│ World │ 3 │ 30 │ +│ World │ 4 │ 40 │ +│ World │ 5 │ 50 │ +└───────┴────────┴────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +This variation also makes sense: + +```text +:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x + +SELECT s, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN `nest.x` + +┌─s─────┬─nest.x─┬─nest.y─────┐ +│ Hello │ 1 │ [10,20] │ +│ Hello │ 2 │ [10,20] │ +│ World │ 3 │ [30,40,50] │ +│ World │ 4 │ [30,40,50] │ +│ World │ 5 │ [30,40,50] │ +└───────┴────────┴────────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +An alias may be used for a nested data structure, in order to select either the JOIN result or the source array. Example: + +```text +:) SELECT s, n.x, n.y, nest.x, nest.y FROM nested_test ARRAY JOIN nest AS n + +SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN nest AS n + +┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┐ +│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ +│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ +│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ +│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ +│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ +└───────┴─────┴─────┴─────────┴────────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +Example of using the arrayEnumerate function: + +```text +:) SELECT s, n.x, n.y, nest.x, nest.y, num FROM nested_test ARRAY JOIN nest AS n, arrayEnumerate(nest.x) AS num + +SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y`, num +FROM nested_test +ARRAY JOIN nest AS n, arrayEnumerate(`nest.x`) AS num + +┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┬─num─┐ +│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ 1 │ +│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ 2 │ +│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ 1 │ +│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ 2 │ +│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ 3 │ +└───────┴─────┴─────┴─────────┴────────────┴─────┘ + +5 rows in set. Elapsed: 0.002 sec. +``` + +The query can only specify a single ARRAY JOIN clause. + +The corresponding conversion can be performed before the WHERE/PREWHERE clause (if its result is needed in this clause), or after completing WHERE/PREWHERE (to reduce the volume of calculations). + +### JOIN clause + +The normal JOIN, which is not related to ARRAY JOIN described above. + +```sql +[GLOBAL] ANY|ALL INNER|LEFT [OUTER] JOIN (subquery)|table USING columns_list +``` + +Performs joins with data from the subquery. At the beginning of query processing, the subquery specified after JOIN is run, and its result is saved in memory. Then it is read from the "left" table specified in the FROM clause, and while it is being read, for each of the read rows from the "left" table, rows are selected from the subquery results table (the "right" table) that meet the condition for matching the values of the columns specified in USING. + +The table name can be specified instead of a subquery. This is equivalent to the `SELECT * FROM table` subquery, except in a special case when the table has the Join engine – an array prepared for joining. + +All columns that are not needed for the JOIN are deleted from the subquery. + +There are several types of JOINs: + +`INNER` or `LEFT` type:If INNER is specified, the result will contain only those rows that have a matching row in the right table. +If LEFT is specified, any rows in the left table that don't have matching rows in the right table will be assigned the default value - zeros or empty rows. LEFT OUTER may be written instead of LEFT; the word OUTER does not affect anything. + +`ANY` or `ALL` stringency:If `ANY` is specified and the right table has several matching rows, only the first one found is joined. +If `ALL` is specified and the right table has several matching rows, the data will be multiplied by the number of these rows. + +Using ALL corresponds to the normal JOIN semantic from standard SQL. +Using ANY is optimal. If the right table has only one matching row, the results of ANY and ALL are the same. You must specify either ANY or ALL (neither of them is selected by default). + +`GLOBAL` distribution: + +When using a normal JOIN, the query is sent to remote servers. Subqueries are run on each of them in order to make the right table, and the join is performed with this table. In other words, the right table is formed on each server separately. + +When using `GLOBAL ... JOIN`, first the requestor server runs a subquery to calculate the right table. This temporary table is passed to each remote server, and queries are run on them using the temporary data that was transmitted. + +Be careful when using GLOBAL JOINs. For more information, see the section "Distributed subqueries". + +Any combination of JOINs is possible. For example, `GLOBAL ANY LEFT OUTER JOIN`. + +When running a JOIN, there is no optimization of the order of execution in relation to other stages of the query. The join (a search in the right table) is run before filtering in WHERE and before aggregation. In order to explicitly set the processing order, we recommend running a JOIN subquery with a subquery. + +Example: + +```sql +SELECT + CounterID, + hits, + visits +FROM +( + SELECT + CounterID, + count() AS hits + FROM test.hits + GROUP BY CounterID +) ANY LEFT JOIN +( + SELECT + CounterID, + sum(Sign) AS visits + FROM test.visits + GROUP BY CounterID +) USING CounterID +ORDER BY hits DESC +LIMIT 10 +``` + +```text +┌─CounterID─┬───hits─┬─visits─┐ +│ 1143050 │ 523264 │ 13665 │ +│ 731962 │ 475698 │ 102716 │ +│ 722545 │ 337212 │ 108187 │ +│ 722889 │ 252197 │ 10547 │ +│ 2237260 │ 196036 │ 9522 │ +│ 23057320 │ 147211 │ 7689 │ +│ 722818 │ 90109 │ 17847 │ +│ 48221 │ 85379 │ 4652 │ +│ 19762435 │ 77807 │ 7026 │ +│ 722884 │ 77492 │ 11056 │ +└───────────┴────────┴────────┘ +``` + +Subqueries don't allow you to set names or use them for referencing a column from a specific subquery. +The columns specified in USING must have the same names in both subqueries, and the other columns must be named differently. You can use aliases to change the names of columns in subqueries (the example uses the aliases 'hits' and 'visits'). + +The USING clause specifies one or more columns to join, which establishes the equality of these columns. The list of columns is set without brackets. More complex join conditions are not supported. + +The right table (the subquery result) resides in RAM. If there isn't enough memory, you can't run a JOIN. + +Only one JOIN can be specified in a query (on a single level). To run multiple JOINs, you can put them in subqueries. + +Each time a query is run with the same JOIN, the subquery is run again – the result is not cached. To avoid this, use the special 'Join' table engine, which is a prepared array for joining that is always in RAM. For more information, see the section "Table engines, Join". + +In some cases, it is more efficient to use IN instead of JOIN. +Among the various types of JOINs, the most efficient is ANY LEFT JOIN, then ANY INNER JOIN. The least efficient are ALL LEFT JOIN and ALL INNER JOIN. + +If you need a JOIN for joining with dimension tables (these are relatively small tables that contain dimension properties, such as names for advertising campaigns), a JOIN might not be very convenient due to the bulky syntax and the fact that the right table is re-accessed for every query. For such cases, there is an "external dictionaries" feature that you should use instead of JOIN. For more information, see the section "External dictionaries". + +### WHERE clause + +If there is a WHERE clause, it must contain an expression with the UInt8 type. This is usually an expression with comparison and logical operators. +This expression will be used for filtering data before all other transformations. + +If indexes are supported by the database table engine, the expression is evaluated on the ability to use indexes. + +### PREWHERE clause + +This clause has the same meaning as the WHERE clause. The difference is in which data is read from the table. +When using PREWHERE, first only the columns necessary for executing PREWHERE are read. Then the other columns are read that are needed for running the query, but only those blocks where the PREWHERE expression is true. + +It makes sense to use PREWHERE if there are filtration conditions that are not suitable for indexes that are used by a minority of the columns in the query, but that provide strong data filtration. This reduces the volume of data to read. + +For example, it is useful to write PREWHERE for queries that extract a large number of columns, but that only have filtration for a few columns. + +PREWHERE is only supported by tables from the `*MergeTree` family. + +A query may simultaneously specify PREWHERE and WHERE. In this case, PREWHERE precedes WHERE. + +Keep in mind that it does not make much sense for PREWHERE to only specify those columns that have an index, because when using an index, only the data blocks that match the index are read. + +If the 'optimize_move_to_prewhere' setting is set to 1 and PREWHERE is omitted, the system uses heuristics to automatically move parts of expressions from WHERE to PREWHERE. + +### GROUP BY clause + +This is one of the most important parts of a column-oriented DBMS. + +If there is a GROUP BY clause, it must contain a list of expressions. Each expression will be referred to here as a "key". +All the expressions in the SELECT, HAVING, and ORDER BY clauses must be calculated from keys or from aggregate functions. In other words, each column selected from the table must be used either in keys or inside aggregate functions. + +If a query contains only table columns inside aggregate functions, the GROUP BY clause can be omitted, and aggregation by an empty set of keys is assumed. + +Example: + +```sql +SELECT + count(), + median(FetchTiming > 60 ? 60 : FetchTiming), + count() - sum(Refresh) +FROM hits +``` + +However, in contrast to standard SQL, if the table doesn't have any rows (either there aren't any at all, or there aren't any after using WHERE to filter), an empty result is returned, and not the result from one of the rows containing the initial values of aggregate functions. + +As opposed to MySQL (and conforming to standard SQL), you can't get some value of some column that is not in a key or aggregate function (except constant expressions). To work around this, you can use the 'any' aggregate function (get the first encountered value) or 'min/max'. + +Example: + +```sql +SELECT + domainWithoutWWW(URL) AS domain, + count(), + any(Title) AS title -- getting the first occurred page header for each domain. +FROM hits +GROUP BY domain +``` + +For every different key value encountered, GROUP BY calculates a set of aggregate function values. + +GROUP BY is not supported for array columns. + +A constant can't be specified as arguments for aggregate functions. Example: sum(1). Instead of this, you can get rid of the constant. Example: `count()`. + +#### WITH TOTALS modifier + +If the WITH TOTALS modifier is specified, another row will be calculated. This row will have key columns containing default values (zeros or empty lines), and columns of aggregate functions with the values calculated across all the rows (the "total" values). + +This extra row is output in JSON\*, TabSeparated\*, and Pretty\* formats, separately from the other rows. In the other formats, this row is not output. + +In JSON\* formats, this row is output as a separate 'totals' field. In TabSeparated\* formats, the row comes after the main result, preceded by an empty row (after the other data). In Pretty\* formats, the row is output as a separate table after the main result. + +`WITH TOTALS` can be run in different ways when HAVING is present. The behavior depends on the 'totals_mode' setting. +By default, `totals_mode = 'before_having'`. In this case, 'totals' is calculated across all rows, including the ones that don't pass through HAVING and 'max_rows_to_group_by'. + +The other alternatives include only the rows that pass through HAVING in 'totals', and behave differently with the setting `max_rows_to_group_by` and `group_by_overflow_mode = 'any'`. + +`after_having_exclusive` – Don't include rows that didn't pass through `max_rows_to_group_by`. In other words, 'totals' will have less than or the same number of rows as it would if `max_rows_to_group_by` were omitted. + +`after_having_inclusive` – Include all the rows that didn't pass through 'max_rows_to_group_by' in 'totals'. In other words, 'totals' will have more than or the same number of rows as it would if `max_rows_to_group_by` were omitted. + +`after_having_auto` – Count the number of rows that passed through HAVING. If it is more than a certain amount (by default, 50%), include all the rows that didn't pass through 'max_rows_to_group_by' in 'totals'. Otherwise, do not include them. + +`totals_auto_threshold` – By default, 0.5. The coefficient for `after_having_auto`. + +If `max_rows_to_group_by` and `group_by_overflow_mode = 'any'` are not used, all variations of `after_having` are the same, and you can use any of them (for example, `after_having_auto`). + +You can use WITH TOTALS in subqueries, including subqueries in the JOIN clause (in this case, the respective total values are combined). + +#### GROUP BY in external memory + +You can enable dumping temporary data to the disk to restrict memory usage during GROUP BY. +The `max_bytes_before_external_group_by` setting determines the threshold RAM consumption for dumping GROUP BY temporary data to the file system. If set to 0 (the default), it is disabled. + +When using `max_bytes_before_external_group_by`, we recommend that you set max_memory_usage about twice as high. This is necessary because there are two stages to aggregation: reading the date and forming intermediate data (1) and merging the intermediate data (2). Dumping data to the file system can only occur during stage 1. If the temporary data wasn't dumped, then stage 2 might require up to the same amount of memory as in stage 1. + +For example, if `max_memory_usage` was set to 10000000000 and you want to use external aggregation, it makes sense to set `max_bytes_before_external_group_by` to 10000000000, and max_memory_usage to 20000000000. When external aggregation is triggered (if there was at least one dump of temporary data), maximum consumption of RAM is only slightly more than ` max_bytes_before_external_group_by`. + +With distributed query processing, external aggregation is performed on remote servers. In order for the requestor server to use only a small amount of RAM, set ` distributed_aggregation_memory_efficient` to 1. + +When merging data flushed to the disk, as well as when merging results from remote servers when the ` distributed_aggregation_memory_efficient` setting is enabled, consumes up to 1/256 \* the number of threads from the total amount of RAM. + +When external aggregation is enabled, if there was less than ` max_bytes_before_external_group_by` of data (i.e. data was not flushed), the query runs just as fast as without external aggregation. If any temporary data was flushed, the run time will be several times longer (approximately three times). + +If you have an ORDER BY with a small LIMIT after GROUP BY, then the ORDER BY CLAUSE will not use significant amounts of RAM. +But if the ORDER BY doesn't have LIMIT, don't forget to enable external sorting (`max_bytes_before_external_sort`). + +### LIMIT N BY clause + +LIMIT N BY COLUMNS selects the top N rows for each group of COLUMNS. LIMIT N BY is not related to LIMIT; they can both be used in the same query. The key for LIMIT N BY can contain any number of columns or expressions. + +Example: + +```sql +SELECT + domainWithoutWWW(URL) AS domain, + domainWithoutWWW(REFERRER_URL) AS referrer, + device_type, + count() cnt +FROM hits +GROUP BY domain, referrer, device_type +ORDER BY cnt DESC +LIMIT 5 BY domain, device_type +LIMIT 100 +``` + +The query will select the top 5 referrers for each `domain, device_type` pair, but not more than 100 rows (`LIMIT n BY + LIMIT`). + +### HAVING clause + +Allows filtering the result received after GROUP BY, similar to the WHERE clause. +WHERE and HAVING differ in that WHERE is performed before aggregation (GROUP BY), while HAVING is performed after it. +If aggregation is not performed, HAVING can't be used. + + + +### ORDER BY clause + +The ORDER BY clause contains a list of expressions, which can each be assigned DESC or ASC (the sorting direction). If the direction is not specified, ASC is assumed. ASC is sorted in ascending order, and DESC in descending order. The sorting direction applies to a single expression, not to the entire list. Example: `ORDER BY Visits DESC, SearchPhrase` + +For sorting by String values, you can specify collation (comparison). Example: `ORDER BY SearchPhrase COLLATE 'tr'` - for sorting by keyword in ascending order, using the Turkish alphabet, case insensitive, assuming that strings are UTF-8 encoded. COLLATE can be specified or not for each expression in ORDER BY independently. If ASC or DESC is specified, COLLATE is specified after it. When using COLLATE, sorting is always case-insensitive. + +We only recommend using COLLATE for final sorting of a small number of rows, since sorting with COLLATE is less efficient than normal sorting by bytes. + +Rows that have identical values for the list of sorting expressions are output in an arbitrary order, which can also be nondeterministic (different each time). +If the ORDER BY clause is omitted, the order of the rows is also undefined, and may be nondeterministic as well. + +When floating point numbers are sorted, NaNs are separate from the other values. Regardless of the sorting order, NaNs come at the end. In other words, for ascending sorting they are placed as if they are larger than all the other numbers, while for descending sorting they are placed as if they are smaller than the rest. + +Less RAM is used if a small enough LIMIT is specified in addition to ORDER BY. Otherwise, the amount of memory spent is proportional to the volume of data for sorting. For distributed query processing, if GROUP BY is omitted, sorting is partially done on remote servers, and the results are merged on the requestor server. This means that for distributed sorting, the volume of data to sort can be greater than the amount of memory on a single server. + +If there is not enough RAM, it is possible to perform sorting in external memory (creating temporary files on a disk). Use the setting `max_bytes_before_external_sort` for this purpose. If it is set to 0 (the default), external sorting is disabled. If it is enabled, when the volume of data to sort reaches the specified number of bytes, the collected data is sorted and dumped into a temporary file. After all data is read, all the sorted files are merged and the results are output. Files are written to the /var/lib/clickhouse/tmp/ directory in the config (by default, but you can use the 'tmp_path' parameter to change this setting). + +Running a query may use more memory than 'max_bytes_before_external_sort'. For this reason, this setting must have a value significantly smaller than 'max_memory_usage'. As an example, if your server has 128 GB of RAM and you need to run a single query, set 'max_memory_usage' to 100 GB, and 'max_bytes_before_external_sort' to 80 GB. + +External sorting works much less effectively than sorting in RAM. + +### SELECT clause + +The expressions specified in the SELECT clause are analyzed after the calculations for all the clauses listed above are completed. +More specifically, expressions are analyzed that are above the aggregate functions, if there are any aggregate functions. +The aggregate functions and everything below them are calculated during aggregation (GROUP BY). +These expressions work as if they are applied to separate rows in the result. + +### DISTINCT clause + +If DISTINCT is specified, only a single row will remain out of all the sets of fully matching rows in the result. +The result will be the same as if GROUP BY were specified across all the fields specified in SELECT without aggregate functions. But there are several differences from GROUP BY: + +- DISTINCT can be applied together with GROUP BY. +- When ORDER BY is omitted and LIMIT is defined, the query stops running immediately after the required number of different rows has been read. +- Data blocks are output as they are processed, without waiting for the entire query to finish running. + +DISTINCT is not supported if SELECT has at least one array column. + +### LIMIT clause + +LIMIT m allows you to select the first 'm' rows from the result. +LIMIT n, m allows you to select the first 'm' rows from the result after skipping the first 'n' rows. + +'n' and 'm' must be non-negative integers. + +If there isn't an ORDER BY clause that explicitly sorts results, the result may be arbitrary and nondeterministic. + +### UNION ALL clause + +You can use UNION ALL to combine any number of queries. Example: + +```sql +SELECT CounterID, 1 AS table, toInt64(count()) AS c + FROM test.hits + GROUP BY CounterID + +UNION ALL + +SELECT CounterID, 2 AS table, sum(Sign) AS c + FROM test.visits + GROUP BY CounterID + HAVING c > 0 +``` + +Only UNION ALL is supported. The regular UNION (UNION DISTINCT) is not supported. If you need UNION DISTINCT, you can write SELECT DISTINCT from a subquery containing UNION ALL. + +Queries that are parts of UNION ALL can be run simultaneously, and their results can be mixed together. + +The structure of results (the number and type of columns) must match for the queries. But the column names can differ. In this case, the column names for the final result will be taken from the first query. + +Queries that are parts of UNION ALL can't be enclosed in brackets. ORDER BY and LIMIT are applied to separate queries, not to the final result. If you need to apply a conversion to the final result, you can put all the queries with UNION ALL in a subquery in the FROM clause. + +### INTO OUTFILE clause + +Add the `INTO OUTFILE filename` clause (where filename is a string literal) to redirect query output to the specified file. +In contrast to MySQL, the file is created on the client side. The query will fail if a file with the same filename already exists. +This functionality is available in the command-line client and clickhouse-local (a query sent via HTTP interface will fail). + +The default output format is TabSeparated (the same as in the command-line client batch mode). + +### FORMAT clause + +Specify 'FORMAT format' to get data in any specified format. +You can use this for convenience, or for creating dumps. +For more information, see the section "Formats". +If the FORMAT clause is omitted, the default format is used, which depends on both the settings and the interface used for accessing the DB. For the HTTP interface and the command-line client in batch mode, the default format is TabSeparated. For the command-line client in interactive mode, the default format is PrettyCompact (it has attractive and compact tables). + +When using the command-line client, data is passed to the client in an internal efficient format. The client independently interprets the FORMAT clause of the query and formats the data itself (thus relieving the network and the server from the load). + +### IN operators + +The `IN`, `NOT IN`, `GLOBAL IN`, and `GLOBAL NOT IN` operators are covered separately, since their functionality is quite rich. + +The left side of the operator is either a single column or a tuple. + +Examples: + +```sql +SELECT UserID IN (123, 456) FROM ... +SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ... +``` + +If the left side is a single column that is in the index, and the right side is a set of constants, the system uses the index for processing the query. + +Don't list too many values explicitly (i.e. millions). If a data set is large, put it in a temporary table (for example, see the section "External data for query processing"), then use a subquery. + +The right side of the operator can be a set of constant expressions, a set of tuples with constant expressions (shown in the examples above), or the name of a database table or SELECT subquery in brackets. + +If the right side of the operator is the name of a table (for example, `UserID IN users`), this is equivalent to the subquery `UserID IN (SELECT * FROM users)`. Use this when working with external data that is sent along with the query. For example, the query can be sent together with a set of user IDs loaded to the 'users' temporary table, which should be filtered. + +If the right side of the operator is a table name that has the Set engine (a prepared data set that is always in RAM), the data set will not be created over again for each query. + +The subquery may specify more than one column for filtering tuples. +Example: + +```sql +SELECT (CounterID, UserID) IN (SELECT CounterID, UserID FROM ...) FROM ... +``` + +The columns to the left and right of the IN operator should have the same type. + +The IN operator and subquery may occur in any part of the query, including in aggregate functions and lambda functions. +Example: + +```sql +SELECT + EventDate, + avg(UserID IN + ( + SELECT UserID + FROM test.hits + WHERE EventDate = toDate('2014-03-17') + )) AS ratio +FROM test.hits +GROUP BY EventDate +ORDER BY EventDate ASC +``` + +```text +┌──EventDate─┬────ratio─┐ +│ 2014-03-17 │ 1 │ +│ 2014-03-18 │ 0.807696 │ +│ 2014-03-19 │ 0.755406 │ +│ 2014-03-20 │ 0.723218 │ +│ 2014-03-21 │ 0.697021 │ +│ 2014-03-22 │ 0.647851 │ +│ 2014-03-23 │ 0.648416 │ +└────────────┴──────────┘ +``` + +For each day after March 17th, count the percentage of pageviews made by users who visited the site on March 17th. +A subquery in the IN clause is always run just one time on a single server. There are no dependent subqueries. + + + +#### Distributed subqueries + +There are two options for IN-s with subqueries (similar to JOINs): normal `IN` / ` OIN` and `IN GLOBAL` / `GLOBAL JOIN`. They differ in how they are run for distributed query processing. + +
+ +Remember that the algorithms described below may work differently depending on the [settings](../operations/settings/settings.md#settings-distributed_product_mode) `distributed_product_mode` setting. + +
+ +When using the regular IN, the query is sent to remote servers, and each of them runs the subqueries in the `IN` or `JOIN` clause. + +When using `GLOBAL IN` / `GLOBAL JOINs`, first all the subqueries are run for `GLOBAL IN` / `GLOBAL JOINs`, and the results are collected in temporary tables. Then the temporary tables are sent to each remote server, where the queries are run using this temporary data. + +For a non-distributed query, use the regular `IN` / `JOIN`. + +Be careful when using subqueries in the `IN` / `JOIN` clauses for distributed query processing. + +Let's look at some examples. Assume that each server in the cluster has a normal **local_table**. Each server also has a **distributed_table** table with the **Distributed** type, which looks at all the servers in the cluster. + +For a query to the **distributed_table**, the query will be sent to all the remote servers and run on them using the **local_table**. + +For example, the query + +```sql +SELECT uniq(UserID) FROM distributed_table +``` + +will be sent to all remote servers as + +```sql +SELECT uniq(UserID) FROM local_table +``` + +and run on each of them in parallel, until it reaches the stage where intermediate results can be combined. Then the intermediate results will be returned to the requestor server and merged on it, and the final result will be sent to the client. + +Now let's examine a query with IN: + +```sql +SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) +``` + +- Calculation of the intersection of audiences of two sites. + +This query will be sent to all remote servers as + +```sql +SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) +``` + +In other words, the data set in the IN clause will be collected on each server independently, only across the data that is stored locally on each of the servers. + +This will work correctly and optimally if you are prepared for this case and have spread data across the cluster servers such that the data for a single UserID resides entirely on a single server. In this case, all the necessary data will be available locally on each server. Otherwise, the result will be inaccurate. We refer to this variation of the query as "local IN". + +To correct how the query works when data is spread randomly across the cluster servers, you could specify **distributed_table** inside a subquery. The query would look like this: + +```sql +SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) +``` + +This query will be sent to all remote servers as + +```sql +SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) +``` + +The subquery will begin running on each remote server. Since the subquery uses a distributed table, the subquery that is on each remote server will be resent to every remote server as + +```sql +SELECT UserID FROM local_table WHERE CounterID = 34 +``` + +For example, if you have a cluster of 100 servers, executing the entire query will require 10,000 elementary requests, which is generally considered unacceptable. + +In such cases, you should always use GLOBAL IN instead of IN. Let's look at how it works for the query + +```sql +SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID GLOBAL IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) +``` + +The requestor server will run the subquery + +```sql +SELECT UserID FROM distributed_table WHERE CounterID = 34 +``` + +and the result will be put in a temporary table in RAM. Then the request will be sent to each remote server as + +```sql +SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID GLOBAL IN _data1 +``` + +and the temporary table `_data1` will be sent to every remote server with the query (the name of the temporary table is implementation-defined). + +This is more optimal than using the normal IN. However, keep the following points in mind: + +1. When creating a temporary table, data is not made unique. To reduce the volume of data transmitted over the network, specify DISTINCT in the subquery. (You don't need to do this for a normal IN.) +2. The temporary table will be sent to all the remote servers. Transmission does not account for network topology. For example, if 10 remote servers reside in a datacenter that is very remote in relation to the requestor server, the data will be sent 10 times over the channel to the remote datacenter. Try to avoid large data sets when using GLOBAL IN. +3. When transmitting data to remote servers, restrictions on network bandwidth are not configurable. You might overload the network. +4. Try to distribute data across servers so that you don't need to use GLOBAL IN on a regular basis. +5. If you need to use GLOBAL IN often, plan the location of the ClickHouse cluster so that a single group of replicas resides in no more than one data center with a fast network between them, so that a query can be processed entirely within a single data center. + +It also makes sense to specify a local table in the `GLOBAL IN` clause, in case this local table is only available on the requestor server and you want to use data from it on remote servers. + +### Extreme values + +In addition to results, you can also get minimum and maximum values for the results columns. To do this, set the **extremes** setting to 1. Minimums and maximums are calculated for numeric types, dates, and dates with times. For other columns, the default values are output. + +An extra two rows are calculated – the minimums and maximums, respectively. These extra two rows are output in JSON\*, TabSeparated\*, and Pretty\* formats, separate from the other rows. They are not output for other formats. + +In JSON\* formats, the extreme values are output in a separate 'extremes' field. In TabSeparated\* formats, the row comes after the main result, and after 'totals' if present. It is preceded by an empty row (after the other data). In Pretty\* formats, the row is output as a separate table after the main result, and after 'totals' if present. + +Extreme values are calculated for rows that have passed through LIMIT. However, when using 'LIMIT offset, size', the rows before 'offset' are included in 'extremes'. In stream requests, the result may also include a small number of rows that passed through LIMIT. + +### Notes + +The `GROUP BY` and `ORDER BY` clauses do not support positional arguments. This contradicts MySQL, but conforms to standard SQL. +For example, `GROUP BY 1, 2` will be interpreted as grouping by constants (i.e. aggregation of all rows into one). + +You can use synonyms (`AS` aliases) in any part of a query. + +You can put an asterisk in any part of a query instead of an expression. When the query is analyzed, the asterisk is expanded to a list of all table columns (excluding the `MATERIALIZED` and `ALIAS` columns). There are only a few cases when using an asterisk is justified: + +- When creating a table dump. +- For tables containing just a few columns, such as system tables. +- For getting information about what columns are in a table. In this case, set `LIMIT 1`. But it is better to use the `DESC TABLE` query. +- When there is strong filtration on a small number of columns using `PREWHERE`. +- In subqueries (since columns that aren't needed for the external query are excluded from subqueries). + +In all other cases, we don't recommend using the asterisk, since it only gives you the drawbacks of a columnar DBMS instead of the advantages. In other words using the asterisk is not recommended. diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 4fda9b68819..1dd72a2b570 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -52,9 +52,11 @@ pages: - 'SQL query language': - 'hidden': 'query_language/index.md' - - 'Queries': 'query_language/queries.md' - - 'Syntax': 'query_language/syntax.md' - - 'Operators': 'query_language/operators.md' + - 'SELECT': 'query_language/select.md' + - 'INSERT INTO': 'query_language/insert_into.md' + - 'CREATE': 'query_language/create.md' + - 'ALTER': 'query_language/alter.md' + - 'Other kinds of queries': 'query_language/misc.md' - 'Functions': - 'Introduction': 'query_language/functions/index.md' - 'Arithmetic functions': 'query_language/functions/arithmetic_functions.md' @@ -104,6 +106,8 @@ pages: - 'Sources of external dictionaries': 'query_language/dicts/external_dicts_dict_sources.md' - 'Dictionary key and fields': 'query_language/dicts/external_dicts_dict_structure.md' - 'Internal dictionaries': 'query_language/dicts/internal_dicts.md' + - 'Operators': 'query_language/operators.md' + - 'General syntax': 'query_language/syntax.md' - 'Operations': - 'Operations': 'operations/index.md' diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index c0df56ba466..954a129f954 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -52,9 +52,11 @@ pages: - 'SQL язык запросов': - 'hidden': 'query_language/index.md' - - 'Запросы': 'query_language/queries.md' - - 'Синтаксис': 'query_language/syntax.md' - - 'Операторы': 'query_language/operators.md' + - 'SELECT': 'query_language/select.md' + - 'INSERT INTO': 'query_language/insert_into.md' + - 'CREATE': 'query_language/create.md' + - 'ALTER': 'query_language/alter.md' + - 'Прочие виды запросов': 'query_language/misc.md' - 'Функции': - 'Введение': 'query_language/functions/index.md' - 'Арифметические функции': 'query_language/functions/arithmetic_functions.md' @@ -106,6 +108,8 @@ pages: - 'Источники внешних словарей': 'query_language/dicts/external_dicts_dict_sources.md' - 'Ключ и поля словаря': 'query_language/dicts/external_dicts_dict_structure.md' - 'Встроенные словари': 'query_language/dicts/internal_dicts.md' + - 'Операторы': 'query_language/operators.md' + - 'Общий синтаксис': 'query_language/syntax.md' - 'Эксплуатация': diff --git a/docs/redirects.txt b/docs/redirects.txt index f4172e05333..6471896d5fa 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -114,3 +114,4 @@ table_functions/index.md query_language/table_functions/index.md table_functions/merge.md query_language/table_functions/merge.md table_functions/numbers.md query_language/table_functions/numbers.md table_functions/remote.md query_language/table_functions/remote.md +query_language/queries.md query_language.md diff --git a/docs/ru/query_language/alter.md b/docs/ru/query_language/alter.md new file mode 100644 index 00000000000..b26a3ba9e32 --- /dev/null +++ b/docs/ru/query_language/alter.md @@ -0,0 +1,265 @@ + + +## ALTER +Запрос `ALTER` поддерживается только для таблиц типа `*MergeTree`, а также `Merge` и `Distributed`. Запрос имеет несколько вариантов. + +### Манипуляции со столбцами + +Изменение структуры таблицы. + +```sql +ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|MODIFY COLUMN ... +``` + +В запросе указывается список из одного или более действий через запятую. +Каждое действие - операция над столбцом. + +Существуют следующие действия: + +```sql +ADD COLUMN name [type] [default_expr] [AFTER name_after] +``` + +Добавляет в таблицу новый столбец с именем name, типом type и выражением для умолчания `default_expr` (смотрите раздел "Значения по умолчанию"). Если указано `AFTER name_after` (имя другого столбца), то столбец добавляется (в список столбцов таблицы) после указанного. Иначе, столбец добавляется в конец таблицы. Внимательный читатель может заметить, что отсутствует возможность добавить столбец в начало таблицы. Для цепочки действий, name_after может быть именем столбца, который добавляется в одном из предыдущих действий. + +Добавление столбца всего лишь меняет структуру таблицы, и не производит никаких действий с данными - соответствующие данные не появляются на диске после ALTER-а. При чтении из таблицы, если для какого-либо столбца отсутствуют данные, то он заполняется значениями по умолчанию (выполняя выражение по умолчанию, если такое есть, или нулями, пустыми строками). Также, столбец появляется на диске при слиянии кусков данных (см. MergeTree). + +Такая схема позволяет добиться мгновенной работы запроса ALTER и отсутствия необходимости увеличивать объём старых данных. + +```sql +DROP COLUMN name +``` + +Удаляет столбец с именем name. +Удаляет данные из файловой системы. Так как это представляет собой удаление целых файлов, запрос выполняется почти мгновенно. + +```sql +MODIFY COLUMN name [type] [default_expr] +``` + +Изменяет тип столбца name на type и/или выражение для умолчания на default_expr. При изменении типа, значения преобразуются так, как если бы к ним была применена функция toType. + +Если изменяется только выражение для умолчания, то запрос не делает никакой сложной работы и выполняется мгновенно. + +Изменение типа столбца - это единственное действие, которое выполняет сложную работу - меняет содержимое файлов с данными. Для больших таблиц, выполнение может занять длительное время. + +Выполнение производится в несколько стадий: +- подготовка временных (новых) файлов с изменёнными данными; +- переименование старых файлов; +- переименование временных (новых) файлов в старые; +- удаление старых файлов. + +Из них, длительной является только первая стадия. Если на этой стадии возникнет сбой, то данные не поменяются. +Если на одной из следующих стадий возникнет сбой, то данные будет можно восстановить вручную. За исключением случаев, когда старые файлы удалены из файловой системы, а данные для новых файлов не доехали на диск и потеряны. + +Не поддерживается изменение типа столбца у массивов и вложенных структур данных. + +Запрос `ALTER` позволяет создавать и удалять отдельные элементы (столбцы) вложенных структур данных, но не вложенные структуры данных целиком. Для добавления вложенной структуры данных, вы можете добавить столбцы с именем вида `name.nested_name` и типом `Array(T)` - вложенная структура данных полностью эквивалентна нескольким столбцам-массивам с именем, имеющим одинаковый префикс до точки. + +Отсутствует возможность удалять столбцы, входящие в первичный ключ или ключ для сэмплирования (в общем, входящие в выражение `ENGINE`). Изменение типа у столбцов, входящих в первичный ключ возможно только в том случае, если это изменение не приводит к изменению данных (например, разрешено добавление значения в Enum или изменение типа с `DateTime` на `UInt32`). + +Если возможностей запроса `ALTER` не хватает для нужного изменения таблицы, вы можете создать новую таблицу, скопировать туда данные с помощью запроса `INSERT SELECT`, затем поменять таблицы местами с помощью запроса `RENAME`, и удалить старую таблицу. + +Запрос `ALTER` блокирует все чтения и записи для таблицы. То есть, если на момент запроса `ALTER`, выполнялся долгий `SELECT`, то запрос `ALTER` сначала дождётся его выполнения. И в это время, все новые запросы к той же таблице, будут ждать, пока завершится этот `ALTER`. + +Для таблиц, которые не хранят данные самостоятельно (типа `Merge` и `Distributed`), `ALTER` всего лишь меняет структуру таблицы, но не меняет структуру подчинённых таблиц. Для примера, при ALTER-е таблицы типа `Distributed`, вам также потребуется выполнить запрос `ALTER` для таблиц на всех удалённых серверах. + +Запрос `ALTER` на изменение столбцов реплицируется. Соответствующие инструкции сохраняются в ZooKeeper, и затем каждая реплика их применяет. Все запросы `ALTER` выполняются в одном и том же порядке. Запрос ждёт выполнения соответствующих действий на всех репликах. Но при этом, запрос на изменение столбцов в реплицируемой таблице можно прервать, и все действия будут осуществлены асинхронно. + +### Манипуляции с партициями и кусками + +Работает только для таблиц семейства `MergeTree`. Существуют следующие виды операций: + +- `DETACH PARTITION` - перенести партицию в директорию detached и забыть про неё. +- `DROP PARTITION` - удалить партицию. +- `ATTACH PART|PARTITION` - добавить в таблицу новый кусок или партицию из директории `detached`. +- `FREEZE PARTITION` - создать бэкап партиции. +- `FETCH PARTITION` - скачать партицию с другого сервера. + +Ниже будет рассмотрен каждый вид запроса по-отдельности. + +Партицией (partition) в таблице называются данные за один календарный месяц. Это определяется значениями ключа-даты, указанной в параметрах движка таблицы. Данные за каждый месяц хранятся отдельно, чтобы упростить всевозможные манипуляции с этими данными. + +Куском (part) в таблице называется часть данных одной партиции, отсортированная по первичному ключу. + +Чтобы посмотреть набор кусков и партиций таблицы, можно воспользоваться системной таблицей `system.parts`: + +```sql +SELECT * FROM system.parts WHERE active +``` + +`active` - учитывать только активные куски. Неактивными являются, например, исходные куски оставшиеся после слияния в более крупный кусок - такие куски удаляются приблизительно через 10 минут после слияния. + +Другой способ посмотреть набор кусков и партиций - зайти в директорию с данными таблицы. +Директория с данными - `/var/lib/clickhouse/data/database/table/`, +где `/var/lib/clickhouse/` - путь к данным ClickHouse, database - имя базы данных, table - имя таблицы. Пример: + +```bash +$ ls -l /var/lib/clickhouse/data/test/visits/ +total 48 +drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_2_2_0 +drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_4_4_0 +drwxrwxrwx 2 clickhouse clickhouse 4096 May 5 02:55 detached +-rw-rw-rw- 1 clickhouse clickhouse 2 May 5 02:58 increment.txt +``` + +Здесь `20140317_20140323_2_2_0`, `20140317_20140323_4_4_0` - директории кусков. + +Рассмотрим по порядку имя первого куска: `20140317_20140323_2_2_0`. + +- `20140317` - минимальная дата данных куска +- `20140323` - максимальная дата данных куска +- `2` - минимальный номер блока данных +- `2` - максимальный номер блока данных +- `0` - уровень куска - глубина дерева слияний, которыми он образован + +Каждый кусок относится к одной партиции и содержит данные только за один месяц. +`201403` - имя партиции. Партиция представляет собой набор кусков за один месяц. + +При работающем сервере, нельзя вручную изменять набор кусков или их данные на файловой системе, так как сервер не будет об этом знать. +Для нереплицируемых таблиц, вы можете это делать при остановленном сервере, хотя это не рекомендуется. +Для реплицируемых таблиц, набор кусков нельзя менять в любом случае. + +Директория `detached` содержит куски, не используемые сервером - отцепленные от таблицы с помощью запроса `ALTER ... DETACH`. Также в эту директорию переносятся куски, признанные повреждёнными, вместо их удаления. Вы можете в любое время добавлять, удалять, модифицировать данные в директории detached - сервер не будет об этом знать, пока вы не сделаете запрос `ALTER TABLE ... ATTACH`. + +```sql +ALTER TABLE [db.]table DETACH PARTITION 'name' +``` + +Перенести все данные для партиции с именем name в директорию detached и забыть про них. +Имя партиции указывается в формате YYYYMM. Оно может быть указано в одинарных кавычках или без них. + +После того, как запрос будет выполнен, вы можете самостоятельно сделать что угодно с данными в директории detached, например, удалить их из файловой системы, или ничего не делать. + +Запрос реплицируется - данные будут перенесены в директорию detached и забыты на всех репликах. Запрос может быть отправлен только на реплику-лидер. Вы можете узнать, является ли реплика лидером, сделав SELECT в системную таблицу system.replicas. Или, проще, вы можете выполнить запрос на всех репликах, и на всех кроме одной, он кинет исключение. + +```sql +ALTER TABLE [db.]table DROP PARTITION 'name' +``` + +Аналогично операции `DETACH`. Удалить данные из таблицы. Куски с данными будут помечены как неактивные и будут полностью удалены примерно через 10 минут. Запрос реплицируется - данные будут удалены на всех репликах. + +```sql +ALTER TABLE [db.]table ATTACH PARTITION|PART 'name' +``` + +Добавить данные в таблицу из директории detached. + +Существует возможность добавить данные для целой партиции (PARTITION) или отдельный кусок (PART). В случае PART, укажите полное имя куска в одинарных кавычках. + +Запрос реплицируется. Каждая реплика проверяет, если ли данные в директории detached. Если данные есть - проверяет их целостность, проверяет их соответствие данным на сервере-инициаторе запроса, и если всё хорошо, то добавляет их. Если нет, то скачивает данные с реплики-инициатора запроса, или с другой реплики, на которой уже добавлены эти данные. + +То есть, вы можете разместить данные в директории detached на одной реплике и, с помощью запроса ALTER ... ATTACH добавить их в таблицу на всех репликах. + +```sql +ALTER TABLE [db.]table FREEZE PARTITION 'name' +``` + +Создаёт локальный бэкап одной или нескольких партиций. В качестве имени может быть указано полное имя партиции (например, 201403) или его префикс (например, 2014) - тогда бэкап будет создан для всех соответствующих партиций. + +Запрос делает следующее: для снэпшота данных на момент его выполнения, создаёт hardlink-и на данные таблиц в директории `/var/lib/clickhouse/shadow/N/...` + +`/var/lib/clickhouse/` - рабочая директория ClickHouse из конфига. +`N` - инкрементальный номер бэкапа. + +Структура директорий внутри бэкапа создаётся такой же, как внутри `/var/lib/clickhouse/`. +Также делает chmod всех файлов, запрещая запись в них. + +Создание бэкапа происходит почти мгновенно (но сначала дожидается окончания выполняющихся в данный момент запросов к соответствующей таблице). Бэкап изначально не занимает места на диске. При дальнейшей работе системы, бэкап может отнимать место на диске, по мере модификации данных. Если бэкап делается для достаточно старых данных, то он не будет отнимать место на диске. + +После создания бэкапа, данные из `/var/lib/clickhouse/shadow/` можно скопировать на удалённый сервер и затем удалить на локальном сервере. +Весь процесс бэкапа не требует остановки сервера. + +Запрос `ALTER ... FREEZE PARTITION` не реплицируется. То есть, локальный бэкап создаётся только на локальном сервере. + +В качестве альтернативного варианта, вы можете скопировать данные из директории `/var/lib/clickhouse/data/database/table` вручную. +Но если это делать при запущенном сервере, то возможны race conditions при копировании директории с добавляющимися/изменяющимися файлами, и бэкап может быть неконсистентным. Этот вариант может использоваться, если сервер не запущен - тогда полученные данные будут такими же, как после запроса `ALTER TABLE t FREEZE PARTITION`. + +`ALTER TABLE ... FREEZE PARTITION` копирует только данные, но не метаданные таблицы. Чтобы сделать бэкап метаданных таблицы, скопируйте файл `/var/lib/clickhouse/metadata/database/table.sql` + +Для восстановления из бэкапа: + +> - создайте таблицу, если её нет, с помощью запроса CREATE. Запрос можно взять из .sql файла (замените в нём `ATTACH` на `CREATE`); +> - скопируйте данные из директории data/database/table/ внутри бэкапа в директорию `/var/lib/clickhouse/data/database/table/detached/` +> - выполните запросы `ALTER TABLE ... ATTACH PARTITION YYYYMM`, где `YYYYMM` - месяц, для каждого месяца. + +Таким образом, данные из бэкапа будут добавлены в таблицу. +Восстановление из бэкапа, так же, не требует остановки сервера. + +### Бэкапы и репликация + +Репликация защищает от аппаратных сбоев. В случае, если на одной из реплик у вас исчезли все данные, то восстановление делается по инструкции в разделе "Восстановление после сбоя". + +Для защиты от аппаратных сбоев, обязательно используйте репликацию. Подробнее про репликацию написано в разделе "Репликация данных". + +Бэкапы защищают от человеческих ошибок (случайно удалили данные, удалили не те данные или не на том кластере, испортили данные). +Для баз данных большого объёма, бывает затруднительно копировать бэкапы на удалённые серверы. В этих случаях, для защиты от человеческой ошибки, можно держать бэкап на том же сервере (он будет лежать в `/var/lib/clickhouse/shadow/`). + +```sql +ALTER TABLE [db.]table FETCH PARTITION 'name' FROM 'path-in-zookeeper' +``` + +Запрос работает только для реплицируемых таблиц. + +Скачивает указанную партицию с шарда, путь в `ZooKeeper` к которому указан в секции `FROM` и помещает в директорию `detached` указанной таблицы. + +Не смотря на то, что запрос называется `ALTER TABLE`, он не изменяет структуру таблицы, и не изменяет сразу доступные данные в таблице. + +Данные помещаются в директорию `detached`, и их можно прикрепить с помощью запроса `ALTER TABLE ... ATTACH`. + +В секции `FROM` указывается путь в `ZooKeeper`. Например, `/clickhouse/tables/01-01/visits`. +Перед скачиванием проверяется существование партиции и совпадение структуры таблицы. Автоматически выбирается наиболее актуальная реплика среди живых реплик. + +Запрос `ALTER ... FETCH PARTITION` не реплицируется. То есть, партиция будет скачана в директорию detached только на локальном сервере. Заметим, что если вы после этого добавите данные в таблицу с помощью запроса `ALTER TABLE ... ATTACH`, то данные будут добавлены на всех репликах (на одной из реплик будут добавлены из директории detached, а на других - загружены с соседних реплик). + +### Синхронность запросов ALTER + +Для нереплицируемых таблиц, все запросы `ALTER` выполняются синхронно. Для реплицируемых таблиц, запрос всего лишь добавляет инструкцию по соответствующим действиям в `ZooKeeper`, а сами действия осуществляются при первой возможности. Но при этом, запрос может ждать завершения выполнения этих действий на всех репликах. + +Для запросов `ALTER ... ATTACH|DETACH|DROP` можно настроить ожидание, с помощью настройки `replication_alter_partitions_sync`. +Возможные значения: `0` - не ждать, `1` - ждать выполнения только у себя (по умолчанию), `2` - ждать всех. + + + +### Мутации + +Мутации - разновидность запроса ALTER, позволяющая изменять или удалять данные в таблице. В отличие от стандартных запросов `DELETE` и `UPDATE`, рассчитанных на точечное изменение данных, область применения мутаций - достаточно тяжёлые изменения, затрагивающие много строк в таблице. + +Функциональность находится в состоянии beta и доступна начиная с версии 1.1.54388. Реализована поддержка *MergeTree таблиц (с репликацией и без). + +Конвертировать существующие таблицы для работы с мутациями не нужно. Но после применения первой мутации формат данных таблицы становится несовместимым с предыдущими версиями и откатиться на предыдущую версию уже не получится. + +На данный момент доступна команда `ALTER DELETE`: + +```sql +ALTER TABLE [db.]table DELETE WHERE expr +``` + +Выражение `expr` должно иметь тип UInt8. Запрос удаляет строки таблицы, для которых это выражение принимает ненулевое значение. + +В одном запросе можно указать несколько команд через запятую. + +Для *MergeTree-таблиц мутации выполняются, перезаписывая данные по кускам (parts). При этом атомарности нет - куски заменяются на помутированные по мере выполнения и запрос `SELECT`, заданный во время выполнения мутации, увидит данные как из измененных кусков, так и из кусков, которые еще не были изменены. + +Мутации линейно упорядочены между собой и накладываются на каждый кусок в порядке добавления. Мутации также упорядочены со вставками - гарантируется, что данные, вставленные в таблицу до начала выполнения запроса мутации, будут изменены, а данные, вставленные после окончания запроса мутации, изменены не будут. При этом мутации никак не блокируют вставки. + +Запрос завершается немедленно после добавления информации о мутации (для реплицированных таблиц - в ZooKeeper, для нереплицированных - на файловую систему). Сама мутация выполняется асинхронно, используя настройки системного профиля. Следить за ходом её выполнения можно по таблице `system.mutations`. Добавленные мутации будут выполняться до конца даже в случае перезапуска серверов ClickHouse. Откатить мутацию после её добавления нельзя. + +#### Таблица system.mutations + +Таблица содержит информацию о ходе выполнения мутаций MergeTree-таблиц. Каждой команде мутации соответствует одна строка. В таблице есть следующие столбцы: + +**database**, **table** - имя БД и таблицы, к которой была применена мутация. + +**mutation_id** - ID запроса. Для реплицированных таблиц эти ID соответствуют именам записей в директории `/mutations/` в ZooKeeper, для нереплицированных - именам файлов в директории с данными таблицы. + +**command** - Команда мутации (часть запроса после `ALTER TABLE [db.]table`). + +**create_time** - Время создания мутации. + +**block_numbers.partition_id**, **block_numbers.number** - Nested-столбец. Для мутаций реплицированных таблиц для каждой партиции содержит номер блока, полученный этой мутацией (в каждой партиции будут изменены только куски, содержащие блоки с номерами, меньшими номера, полученного мутацией в этой партиции). Для нереплицированных таблиц нумерация блоков сквозная по партициям, поэтому столбец содержит одну запись с единственным номером блока, полученным мутацией. + +**parts_to_do** - Количество кусков таблицы, которые ещё предстоит изменить. + +**is_done** - Завершена ли мутация. Замечание: даже если `parts_to_do = 0`, для реплицированной таблицы возможна ситуация, когда мутация ещё не завершена из-за долго выполняющейся вставки, которая добавляет данные, которые нужно будет мутировать. + diff --git a/docs/ru/query_language/create.md b/docs/ru/query_language/create.md new file mode 100644 index 00000000000..a33692d12b1 --- /dev/null +++ b/docs/ru/query_language/create.md @@ -0,0 +1,155 @@ +## CREATE DATABASE +Создание базы данных db_name + +```sql +CREATE DATABASE [IF NOT EXISTS] db_name +``` + +`База данных` - это просто директория для таблиц. +Если написано `IF NOT EXISTS`, то запрос не будет возвращать ошибку, если база данных уже существует. + + + + +## CREATE TABLE +Запрос `CREATE TABLE` может иметь несколько форм. + +```sql +CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name [ON CLUSTER cluster] +( + name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], + name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2], + ... +) ENGINE = engine +``` + +Создаёт таблицу с именем name в БД db или текущей БД, если db не указана, со структурой, указанной в скобках, и движком engine. +Структура таблицы представляет список описаний столбцов. Индексы, если поддерживаются движком, указываются в качестве параметров для движка таблицы. + +Описание столбца, это `name type`, в простейшем случае. Пример: `RegionID UInt32`. +Также могут быть указаны выражения для значений по умолчанию - смотрите ниже. + +```sql +CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine] +``` + +Создаёт таблицу с такой же структурой, как другая таблица. Можно указать другой движок для таблицы. Если движок не указан, то будет выбран такой же движок, как у таблицы `db2.name2`. + +```sql +CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... +``` + +Создаёт таблицу со структурой, как результат запроса `SELECT`, с движком engine, и заполняет её данными из SELECT-а. + +Во всех случаях, если указано `IF NOT EXISTS`, то запрос не будет возвращать ошибку, если таблица уже существует. В этом случае, запрос будет ничего не делать. + +### Значения по умолчанию + + +В описании столбца, может быть указано выражение для значения по умолчанию, одного из следующих видов: +`DEFAULT expr`, `MATERIALIZED expr`, `ALIAS expr`. +Пример: `URLDomain String DEFAULT domain(URL)`. + +Если выражение для значения по умолчанию не указано, то в качестве значений по умолчанию будут использоваться нули для чисел, пустые строки для строк, пустые массивы для массивов, а также `0000-00-00` для дат и `0000-00-00 00:00:00` для дат с временем. NULL-ы не поддерживаются. + +В случае, если указано выражение по умолчанию, то указание типа столбца не обязательно. При отсутствии явно указанного типа, будет использован тип выражения по умолчанию. Пример: `EventDate DEFAULT toDate(EventTime)` - для столбца EventDate будет использован тип Date. + +При наличии явно указанного типа данных и выражения по умолчанию, это выражение будет приводиться к указанному типу с использованием функций приведения типа. Пример: `Hits UInt32 DEFAULT 0` - имеет такой же смысл, как `Hits UInt32 DEFAULT toUInt32(0)`. + +В качестве выражения для умолчания, может быть указано произвольное выражение от констант и столбцов таблицы. При создании и изменении структуры таблицы, проверяется, что выражения не содержат циклов. При INSERT-е проверяется разрешимость выражений - что все столбцы, из которых их можно вычислить, переданы. + +`DEFAULT expr` + +Обычное значение по умолчанию. Если в запросе INSERT не указан соответствующий столбец, то он будет заполнен путём вычисления соответствующего выражения. + +`MATERIALIZED expr` + +Материализованное выражение. Такой столбец не может быть указан при INSERT, то есть, он всегда вычисляется. +При INSERT без указания списка столбцов, такие столбцы не рассматриваются. +Также этот столбец не подставляется при использовании звёздочки в запросе SELECT - чтобы сохранить инвариант, что дамп, полученный путём `SELECT *`, можно вставить обратно в таблицу INSERT-ом без указания списка столбцов. + +`ALIAS expr` + +Синоним. Такой столбец вообще не хранится в таблице. +Его значения не могут быть вставлены в таблицу, он не подставляется при использовании звёздочки в запросе SELECT. +Он может быть использован в SELECT-ах - в таком случае, во время разбора запроса, алиас раскрывается. + +При добавлении новых столбцов с помощью запроса ALTER, старые данные для этих столбцов не записываются. Вместо этого, при чтении старых данных, для которых отсутствуют значения новых столбцов, выполняется вычисление выражений по умолчанию на лету. При этом, если выполнение выражения требует использования других столбцов, не указанных в запросе, то эти столбцы будут дополнительно прочитаны, но только для тех блоков данных, для которых это необходимо. + +Если добавить в таблицу новый столбец, а через некоторое время изменить его выражение по умолчанию, то используемые значения для старых данных (для данных, где значения не хранились на диске) поменяются. Также заметим, что при выполнении фоновых слияний, данные для столбцов, отсутствующих в одном из сливаемых кусков, записываются в объединённый кусок. + +Отсутствует возможность задать значения по умолчанию для элементов вложенных структур данных. + +### Временные таблицы + +Во всех случаях, если указано `TEMPORARY`, то будет создана временная таблица. Временные таблицы обладают следующими особенностями: +- временные таблицы исчезают после завершения сессии; в том числе, при обрыве соединения; +- временная таблица создаётся с движком Memory; все остальные движки таблиц не поддерживаются; +- для временной таблицы нет возможности указать БД: она создаётся вне баз данных; +- если временная таблица имеет то же имя, что и некоторая другая, то, при упоминании в запросе без указания БД, будет использована временная таблица; +- при распределённой обработке запроса, используемые в запросе временные таблицы, передаются на удалённые серверы. + +В большинстве случаев, временные таблицы создаются не вручную, а при использовании внешних данных для запроса, или при распределённом `(GLOBAL) IN`. Подробнее см. соответствующие разделы + +Распределенные DDL запросы (секция ON CLUSTER) +---------------------------------------------- + +Запросы `CREATE`, `DROP`, `ALTER`, `RENAME` поддерживают возможность распределенного выполнения на кластере. +Например, следующий запрос создает `Distributed`-таблицу `all_hits` на каждом хосте кластера `cluster`: + +```sql +CREATE TABLE IF NOT EXISTS all_hits ON CLUSTER cluster (p Date, i Int32) ENGINE = Distributed(cluster, default, hits) +``` + +Для корректного выполнения таких запросов необходимо на каждом хосте иметь одинаковое определение кластера (для упрощения синхронизации конфигов можете использовать подстановки из ZooKeeper), также необходимо подключение к ZooKeeper серверам. +Локальная версия запроса в конечном итоге будет выполнена на каждом хосте кластера, даже если некоторые хосты в данный момент не доступны, гарантируется упорядоченность выполнения запросов в рамках одного хоста. +Пока не поддерживаются `ALTER`-запросы для реплицированных таблиц. + +## CREATE VIEW + +```sql +CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT ... +``` + +Создаёт представление. Представления бывают двух видов - обычные и материализованные (MATERIALIZED). + +При создании материализованного представления, нужно обязательно указать ENGINE - движок таблицы для хранения данных. + +Материализованное представление работает следующим образом: при вставлении данных в таблицу, указанную в SELECT, часть вставленных данных конвертируется запросом, а результат вставляется в представление. + +Обычные представления не хранят никаких данных, а всего лишь производят чтение из другой таблицы. То есть, обычное представление - не более чем сохранённый запрос. При чтении из представления, этот сохранённый запрос, используется в качестве подзапроса в секции FROM. + +Для примера, пусть вы создали представление: + +```sql +CREATE VIEW view AS SELECT ... +``` + +и написали запрос: + +```sql +SELECT a, b, c FROM view +``` + +Этот запрос полностью эквивалентен использованию подзапроса: + +```sql +SELECT a, b, c FROM (SELECT ...) +``` + +Материализованные (MATERIALIZED) представления хранят данные, преобразованные соответствующим запросом SELECT. + +При создании материализованного представления, нужно обязательно указать ENGINE - движок таблицы для хранения данных. + +Материализованное представление устроено следующим образом: при вставке данных в таблицу, указанную в SELECT-е, кусок вставляемых данных преобразуется этим запросом SELECT, и полученный результат вставляется в представление. + +Если указано POPULATE, то при создании представления, в него будут вставлены имеющиеся данные таблицы, как если бы был сделан запрос `CREATE TABLE ... AS SELECT ...` . Иначе, представление будет содержать только данные, вставляемые в таблицу после создания представления. Не рекомендуется использовать POPULATE, так как вставляемые в таблицу данные во время создания представления, не попадут в него. + +Запрос `SELECT` может содержать `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`... Следует иметь ввиду, что соответствующие преобразования будут выполняться независимо, на каждый блок вставляемых данных. Например, при наличии `GROUP BY`, данные будут агрегироваться при вставке, но только в рамках одной пачки вставляемых данных. Далее, данные не будут доагрегированы. Исключение - использование ENGINE, производящего агрегацию данных самостоятельно, например, `SummingMergeTree`. + +Недоработано выполнение запросов `ALTER` над материализованными представлениями, поэтому они могут быть неудобными для использования. Если материализованное представление использует конструкцию ``TO [db.]name``, то можно выполнить ``DETACH`` представления, ``ALTER`` для целевой таблицы и последующий ``ATTACH`` ранее отсоединенного (``DETACH``) представления. + +Представления выглядят так же, как обычные таблицы. Например, они перечисляются в результате запроса `SHOW TABLES`. + +Отсутствует отдельный запрос для удаления представлений. Чтобы удалить представление, следует использовать `DROP TABLE`. + diff --git a/docs/ru/query_language/index.md b/docs/ru/query_language/index.md index 5ad3b775836..666616b6003 100644 --- a/docs/ru/query_language/index.md +++ b/docs/ru/query_language/index.md @@ -1 +1,7 @@ # Язык запросов + +* [SELECT](select.md) +* [INSERT INTO](insert_into.md) +* [CREATE](create.md) +* [ALTER](alter.md) +* [Прочие виды запросов](misc.md) diff --git a/docs/ru/query_language/insert_into.md b/docs/ru/query_language/insert_into.md new file mode 100644 index 00000000000..9d2e6280e3a --- /dev/null +++ b/docs/ru/query_language/insert_into.md @@ -0,0 +1,67 @@ + + +## INSERT + +Добавление данных. + +Базовый формат запроса: + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ... +``` + +В запросе можно указать список столбцов для вставки `[(c1, c2, c3)]`. В этом случае, в остальные столбцы записываются: + +- Значения, вычисляемые из `DEFAULT` выражений, указанных в определении таблицы. +- Нули и пустые строки, если `DEFAULT` не определены. + +Если [strict_insert_defaults=1](../operations/settings/settings.md#settings-strict_insert_defaults), то столбцы, для которых не определены `DEFAULT`, необходимо перечислить в запросе. + +В INSERT можно передавать данные любого [формата](../interfaces/formats.md#formats), который поддерживает ClickHouse. Для этого формат необходимо указать в запросе в явном виде: + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set +``` + +Например, следующий формат запроса идентичен базовому варианту INSERT ... VALUES: + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ... +``` + +ClickHouse отсекает все пробелы и один перенос строки (если он есть) перед данными. Рекомендуем при формировании запроса переносить данные на новую строку после операторов запроса (это важно, если данные начинаются с пробелов). + +Пример: + +```sql +INSERT INTO t FORMAT TabSeparated +11 Hello, world! +22 Qwerty +``` + +С помощью консольного клиента или HTTP интерфейса можно вставлять данные отдельно от запроса. Как это сделать, читайте в разделе "[Интерфейсы](../interfaces/index.md#interfaces)". + +### Вставка результатов `SELECT` + +```sql +INSERT INTO [db.]table [(c1, c2, c3)] SELECT ... +``` + +Соответствие столбцов определяется их позицией в секции SELECT. При этом, их имена в выражении SELECT и в таблице для INSERT, могут отличаться. При необходимости выполняется приведение типов данных, эквивалентное соответствующему оператору CAST. + +Все форматы данных кроме Values не позволяют использовать в качестве значений выражения, такие как `now()`, `1 + 2` и подобные. Формат Values позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода. + +Не поддерживаются другие запросы на модификацию части данных: `UPDATE`, `DELETE`, `REPLACE`, `MERGE`, `UPSERT`, `INSERT UPDATE`. +Вы можете удалять старые данные с помощью запроса `ALTER TABLE ... DROP PARTITION`. + +### Замечания о производительности + +`INSERT` сортирует входящие данные по первичному ключу и разбивает их на партиции по месяцам. Если вы вставляете данные за разные месяцы вперемешку, то это может значительно снизить производительность запроса `INSERT`. Чтобы избежать этого: + +- Добавляйте данные достаточно большими пачками. Например, по 100 000 строк. +- Группируйте данные по месацам самостоятельно перед загрузкой в ClickHouse. + +Снижения производительности не будет, если: + +- Данные поступают в режиме реального времени. +- Вы загружаете данные, которые как правило отсортированы по времени. diff --git a/docs/ru/query_language/misc.md b/docs/ru/query_language/misc.md new file mode 100644 index 00000000000..4027a5fba43 --- /dev/null +++ b/docs/ru/query_language/misc.md @@ -0,0 +1,213 @@ + + + + +## ATTACH +Запрос полностью аналогичен запросу `CREATE`, но: + +- вместо слова `CREATE` используется слово `ATTACH`; +- запрос не создаёт данные на диске, а предполагает, что данные уже лежат в соответствующих местах, и всего лишь добавляет информацию о таблице в сервер. + +После выполнения `ATTACH`, сервер будет знать о существовании таблицы. + +Если таблица перед этим была отсоединена (`DETACH`), т.е. её структура известна, то можно использовать сокращенную форму записи без определения структуры. + +```sql +ATTACH TABLE [IF NOT EXISTS] [db.]name +``` + +Этот запрос используется при старте сервера. Сервер хранит метаданные таблиц в виде файлов с запросами `ATTACH`, которые он просто исполняет при запуске (за исключением системных таблиц, создание которых явно вписано в сервер). + +## DROP +Запрос имеет два вида: `DROP DATABASE` и `DROP TABLE`. + +```sql +DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster] +``` + +Удаляет все таблицы внутри базы данных db, а затем саму базу данных db. +Если указано `IF EXISTS` - не выдавать ошибку, если база данных не существует. + +```sql +DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster] +``` + +Удаляет таблицу. +Если указано `IF EXISTS` - не выдавать ошибку, если таблица не существует или база данных не существует. + +## DETACH +Удаляет из сервера информацию о таблице name. Сервер перестаёт знать о существовании таблицы. + +```sql +DETACH TABLE [IF EXISTS] [db.]name +``` + +Но ни данные, ни метаданные таблицы не удаляются. При следующем запуске сервера, сервер прочитает метаданные и снова узнает о таблице. +Также, "отцепленную" таблицу можно прицепить заново запросом `ATTACH` (за исключением системных таблиц, для которых метаданные не хранятся). + +Запроса `DETACH DATABASE` нет. + +## RENAME +Переименовывает одну или несколько таблиц. + +```sql +RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... [ON CLUSTER cluster] +``` + +Все таблицы переименовываются под глобальной блокировкой. Переименовывание таблицы является лёгкой операцией. Если вы указали после TO другую базу данных, то таблица будет перенесена в эту базу данных. При этом, директории с базами данных должны быть расположены в одной файловой системе (иначе возвращается ошибка). + +## SHOW DATABASES + +```sql +SHOW DATABASES [INTO OUTFILE filename] [FORMAT format] +``` + +Выводит список всех баз данных. +Запрос полностью аналогичен запросу `SELECT name FROM system.databases [INTO OUTFILE filename] [FORMAT format]`. + +Смотрите также раздел "Форматы". + +## SHOW TABLES + +```sql +SHOW [TEMPORARY] TABLES [FROM db] [LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format] +``` + +Выводит список таблиц + +- из текущей БД или из БД db, если указано FROM db; +- всех, или имя которых соответствует шаблону pattern, если указано LIKE 'pattern'; + +Запрос полностью аналогичен запросу: `SELECT name FROM system.tables WHERE database = 'db' [AND name LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]`. + +Смотрите также раздел "Оператор LIKE". + +## SHOW PROCESSLIST + +```sql +SHOW PROCESSLIST [INTO OUTFILE filename] [FORMAT format] +``` + +Выводит список запросов, выполняющихся в данный момент времени, кроме запросов `SHOW PROCESSLIST`. + +Выдаёт таблицу, содержащую столбцы: + +**user** - пользователь, под которым был задан запрос. Следует иметь ввиду, что при распределённой обработке запроса на удалённые серверы запросы отправляются под пользователем default. И SHOW PROCESSLIST показывает имя пользователя для конкретного запроса, а не для запроса, который данный запрос инициировал. + +**address** - имя хоста, с которого был отправлен запрос. При распределённой обработке запроса на удалённых серверах — это имя хоста-инициатора запроса. Чтобы проследить, откуда был задан распределённый запрос изначально, следует смотреть SHOW PROCESSLIST на сервере-инициаторе запроса. + +**elapsed** - время выполнения запроса, в секундах. Запросы выводятся упорядоченными по убыванию времени выполнения. + +**rows_read**, **bytes_read** - сколько было прочитано строк, байт несжатых данных при обработке запроса. При распределённой обработке запроса суммируются данные со всех удалённых серверов. Именно эти данные используются для ограничений и квот. + +**memory_usage** - текущее потребление оперативки в байтах. Смотрите настройку max_memory_usage. + +**query** - сам запрос. В запросах INSERT данные для вставки не выводятся. + +**query_id** - идентификатор запроса. Непустой, только если был явно задан пользователем. При распределённой обработке запроса идентификатор запроса не передаётся на удалённые серверы. + +Запрос полностью аналогичен запросу: `SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]`. + +Полезный совет (выполните в консоли): + +```bash +watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'" +``` + +## SHOW CREATE TABLE + +```sql +SHOW CREATE [TEMPORARY] TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] +``` + +Возвращает один столбец statement типа `String`, содержащий одно значение - запрос `CREATE`, с помощью которого создана указанная таблица. + +## DESCRIBE TABLE + +```sql +DESC|DESCRIBE TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] +``` + +Возвращает два столбца: `name`, `type` типа `String`, в которых описаны имена и типы столбцов указанной таблицы. + +Вложенные структуры данных выводятся в "развёрнутом" виде. То есть, каждый столбец - по отдельности, с именем через точку. + +## EXISTS + +```sql +EXISTS [TEMPORARY] TABLE [db.]name [INTO OUTFILE filename] [FORMAT format] +``` + +Возвращает один столбец типа `UInt8`, содержащий одно значение - `0`, если таблицы или БД не существует и `1`, если таблица в указанной БД существует. + +## USE + +```sql +USE db +``` + +Позволяет установить текущую базу данных для сессии. +Текущая база данных используется для поиска таблиц, если база данных не указана в запросе явно через точку перед именем таблицы. +При использовании HTTP протокола, запрос не может быть выполнен, так как понятия сессии не существует. + +## SET + +```sql +SET param = value +``` + +Позволяет установить настройку `param` в значение `value`. Также можно одним запросом установить все настройки из заданного профиля настроек - для этого, укажите в качестве имени настройки profile. Подробнее смотри раздел "Настройки". +Настройка устанавливается на сессию, или на сервер (глобально), если указано `GLOBAL`. +При установке глобальной настройки, настройка на все уже запущенные сессии, включая текущую сессию, не устанавливается, а будет использована только для новых сессий. + +При перезапуске сервера, теряются настройки, установленные с помощью `SET`. +Установить настройки, которые переживут перезапуск сервера, можно только с помощью конфигурационного файла сервера. + +## OPTIMIZE + +```sql +OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] +``` + +Просит движок таблицы сделать что-нибудь, что может привести к более оптимальной работе. +Поддерживается только движками `*MergeTree`, в котором выполнение этого запроса инициирует внеочередное слияние кусков данных. +Если указан `PARTITION`, то оптимизация будет производиться только для указаной партиции. +Если указан `FINAL`, то оптимизация будет производиться даже когда все данные уже лежат в одном куске. + +
+Запрос OPTIMIZE не может устранить причину появления ошибки "Too many parts". +
+ +## KILL QUERY + +```sql +KILL QUERY + WHERE + [SYNC|ASYNC|TEST] + [FORMAT format] +``` + +Пытается принудительно остановить исполняющиеся в данный момент запросы. +Запросы для принудительной остановки выбираются из таблицы system.processes с помощью условия, указанного в секции `WHERE` запроса `KILL`. + +Примеры: +```sql +-- Принудительно останавливает все запросы с указанным query_id: +KILL QUERY WHERE query_id='2-857d-4a57-9ee0-327da5d60a90' + +-- Синхронно останавливает все запросы пользователя 'username': +KILL QUERY WHERE user='username' SYNC +``` + +Readonly-пользователи могут останавливать только свои запросы. + +По-умолчанию используется асинхронный вариант запроса (`ASYNC`), который не дожидается подтверждения остановки запросов. + +Синхронный вариант (`SYNC`) ожидает остановки всех запросов и построчно выводит информацию о процессах по ходу их остановки. +Ответ содержит колонку `kill_status`, которая может принимать следующие значения: + +1. 'finished' - запрос был успешно остановлен; +2. 'waiting' - запросу отправлен сигнал завершения, ожидается его остановка; +3. остальные значения описывают причину невозможности остановки запроса. + +Тестовый вариант запроса (`TEST`) только проверяет права пользователя и выводит список запросов для остановки. diff --git a/docs/ru/query_language/select.md b/docs/ru/query_language/select.md new file mode 100644 index 00000000000..8f006ef4965 --- /dev/null +++ b/docs/ru/query_language/select.md @@ -0,0 +1,852 @@ +# SELECT запросы + +`SELECT` осуществляет выборку данных. + +```sql +SELECT [DISTINCT] expr_list + [FROM [db.]table | (subquery) | table_function] [FINAL] + [SAMPLE sample_coeff] + [ARRAY JOIN ...] + [GLOBAL] ANY|ALL INNER|LEFT JOIN (subquery)|table USING columns_list + [PREWHERE expr] + [WHERE expr] + [GROUP BY expr_list] [WITH TOTALS] + [HAVING expr] + [ORDER BY expr_list] + [LIMIT [n, ]m] + [UNION ALL ...] + [INTO OUTFILE filename] + [FORMAT format] + [LIMIT n BY columns] +``` + +Все секции, кроме списка выражений сразу после SELECT, являются необязательными. +Ниже секции будут описаны в порядке, почти соответствующем конвейеру выполнения запроса. + +Если в запросе отсутствуют секции `DISTINCT`, `GROUP BY`, `ORDER BY`, подзапросы в `IN` и `JOIN`, то запрос будет обработан полностью потоково, с использованием O(1) количества оперативки. +Иначе запрос может съесть много оперативки, если не указаны подходящие ограничения `max_memory_usage`, `max_rows_to_group_by`, `max_rows_to_sort`, `max_rows_in_distinct`, `max_bytes_in_distinct`, `max_rows_in_set`, `max_bytes_in_set`, `max_rows_in_join`, `max_bytes_in_join`, `max_bytes_before_external_sort`, `max_bytes_before_external_group_by`. Подробнее смотрите в разделе "Настройки". Присутствует возможность использовать внешнюю сортировку (с сохранением временных данных на диск) и внешнюю агрегацию. `Merge join` в системе нет. + +### Секция FROM + +Если секция FROM отсутствует, то данные будут читаться из таблицы `system.one`. +Таблица system.one содержит ровно одну строку (то есть, эта таблица выполняет такую же роль, как таблица DUAL, которую можно найти в других СУБД). + +В секции FROM указывается таблица, из которой будут читаться данные, либо подзапрос, либо табличная функция; дополнительно могут присутствовать ARRAY JOIN и обычный JOIN (смотрите ниже). + +Вместо таблицы, может быть указан подзапрос SELECT в скобках. +В этом случае, конвейер обработки подзапроса будет встроен в конвейер обработки внешнего запроса. +В отличие от стандартного SQL, после подзапроса не нужно указывать его синоним. Для совместимости, присутствует возможность написать AS name после подзапроса, но указанное имя нигде не используется. + +Вместо таблицы, может быть указана табличная функция. Подробнее смотрите раздел "Табличные функции". + +Для выполнения запроса, из соответствующей таблицы, вынимаются все столбцы, перечисленные в запросе. Из подзапросов выкидываются столбцы, не нужные для внешнего запроса. +Если в запросе не перечислено ни одного столбца (например, SELECT count() FROM t), то из таблицы всё равно вынимается один какой-нибудь столбец (предпочитается самый маленький), для того, чтобы можно было хотя бы посчитать количество строк. + +Модификатор FINAL может быть использован только при SELECT-е из таблицы типа CollapsingMergeTree. При указании FINAL, данные будут выбираться полностью "сколлапсированными". Стоит учитывать, что использование FINAL приводит к выбору кроме указанных в SELECT-е столбцов также столбцов, относящихся к первичному ключу. Также, запрос будет выполняться в один поток, и при выполнении запроса будет выполняться слияние данных. Это приводит к тому, что при использовании FINAL, запрос выполняется медленнее. В большинстве случаев, следует избегать использования FINAL. Подробнее смотрите раздел "Движок CollapsingMergeTree". + +### Секция SAMPLE + +Секция SAMPLE позволяет выполнить запрос приближённо. Приближённое выполнение запроса поддерживается только таблицами типа MergeTree\* и только если при создании таблицы было указано выражение, по которому производится выборка (смотрите раздел "Движок MergeTree"). + +`SAMPLE` имеет вид `SAMPLE k`, где `k` - дробное число в интервале от 0 до 1, или `SAMPLE n`, где n - достаточно большое целое число. + +В первом случае, запрос будет выполнен по k-доле данных. Например, если указано `SAMPLE 0.1`, то запрос будет выполнен по 10% данных. +Во втором случае, запрос будет выполнен по выборке из не более n строк. Например, если указано `SAMPLE 10000000`, то запрос будет выполнен по не более чем 10 000 000 строкам. + +Пример: + +```sql +SELECT + Title, + count() * 10 AS PageViews +FROM hits_distributed +SAMPLE 0.1 +WHERE + CounterID = 34 + AND toDate(EventDate) >= toDate('2013-01-29') + AND toDate(EventDate) <= toDate('2013-02-04') + AND NOT DontCountHits + AND NOT Refresh + AND Title != '' +GROUP BY Title +ORDER BY PageViews DESC LIMIT 1000 +``` + +В этом примере, запрос выполняется по выборке из 0.1 (10%) данных. Значения агрегатных функций не корректируются автоматически, поэтому для получения приближённого результата, значение count() вручную домножается на 10. + +При использовании варианта вида `SAMPLE 10000000`, нет информации, какая относительная доля данных была обработана, и на что следует домножить агрегатные функции, поэтому такой способ записи подходит не для всех случаев. + +Выборка с указанием относительного коэффициента является "согласованной": если рассмотреть все возможные данные, которые могли бы быть в таблице, то выборка (при использовании одного выражения сэмплирования, указанного при создании таблицы), с одинаковым коэффициентом, выбирает всегда одно и то же подмножество этих всевозможных данных. То есть, выборка из разных таблиц, на разных серверах, в разное время, делается одинаковым образом. + +Например, выборка по идентификаторам посетителей, выберет из разных таблиц строки с одинаковым подмножеством всех возможных идентификаторов посетителей. Это позволяет использовать выборку в подзапросах в секции IN, а также при ручном сопоставлении результатов разных запросов с выборками. + +### Секция ARRAY JOIN + +Позволяет выполнить JOIN с массивом или вложенной структурой данных. Смысл похож на функцию arrayJoin, но функциональность более широкая. + +`ARRAY JOIN` - это, по сути, `INNER JOIN` с массивом. Пример: + +```text +:) CREATE TABLE arrays_test (s String, arr Array(UInt8)) ENGINE = Memory + +CREATE TABLE arrays_test +( + s String, + arr Array(UInt8) +) ENGINE = Memory + +Ok. + +0 rows in set. Elapsed: 0.001 sec. + +:) INSERT INTO arrays_test VALUES ('Hello', [1,2]), ('World', [3,4,5]), ('Goodbye', []) + +INSERT INTO arrays_test VALUES + +Ok. + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT * FROM arrays_test + +SELECT * +FROM arrays_test + +┌─s───────┬─arr─────┐ +│ Hello │ [1,2] │ +│ World │ [3,4,5] │ +│ Goodbye │ [] │ +└─────────┴─────────┘ + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT s, arr FROM arrays_test ARRAY JOIN arr + +SELECT s, arr +FROM arrays_test +ARRAY JOIN arr + +┌─s─────┬─arr─┐ +│ Hello │ 1 │ +│ Hello │ 2 │ +│ World │ 3 │ +│ World │ 4 │ +│ World │ 5 │ +└───────┴─────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +Для массива в секции ARRAY JOIN может быть указан алиас. В этом случае, элемент массива будет доступен под этим алиасом, а сам массив - под исходным именем. Пример: + +```text +:) SELECT s, arr, a FROM arrays_test ARRAY JOIN arr AS a + +SELECT s, arr, a +FROM arrays_test +ARRAY JOIN arr AS a + +┌─s─────┬─arr─────┬─a─┐ +│ Hello │ [1,2] │ 1 │ +│ Hello │ [1,2] │ 2 │ +│ World │ [3,4,5] │ 3 │ +│ World │ [3,4,5] │ 4 │ +│ World │ [3,4,5] │ 5 │ +└───────┴─────────┴───┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +В секции ARRAY JOIN может быть указано несколько массивов одинаковых размеров через запятую. В этом случае, JOIN делается с ними одновременно (прямая сумма, а не прямое произведение). Пример: + +```text +:) SELECT s, arr, a, num, mapped FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(x -> x + 1, arr) AS mapped + +SELECT s, arr, a, num, mapped +FROM arrays_test +ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(lambda(tuple(x), plus(x, 1)), arr) AS mapped + +┌─s─────┬─arr─────┬─a─┬─num─┬─mapped─┐ +│ Hello │ [1,2] │ 1 │ 1 │ 2 │ +│ Hello │ [1,2] │ 2 │ 2 │ 3 │ +│ World │ [3,4,5] │ 3 │ 1 │ 4 │ +│ World │ [3,4,5] │ 4 │ 2 │ 5 │ +│ World │ [3,4,5] │ 5 │ 3 │ 6 │ +└───────┴─────────┴───┴─────┴────────┘ + +5 rows in set. Elapsed: 0.002 sec. + +:) SELECT s, arr, a, num, arrayEnumerate(arr) FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num + +SELECT s, arr, a, num, arrayEnumerate(arr) +FROM arrays_test +ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num + +┌─s─────┬─arr─────┬─a─┬─num─┬─arrayEnumerate(arr)─┐ +│ Hello │ [1,2] │ 1 │ 1 │ [1,2] │ +│ Hello │ [1,2] │ 2 │ 2 │ [1,2] │ +│ World │ [3,4,5] │ 3 │ 1 │ [1,2,3] │ +│ World │ [3,4,5] │ 4 │ 2 │ [1,2,3] │ +│ World │ [3,4,5] │ 5 │ 3 │ [1,2,3] │ +└───────┴─────────┴───┴─────┴─────────────────────┘ + +5 rows in set. Elapsed: 0.002 sec. +``` + +ARRAY JOIN также работает с вложенными структурами данных. Пример: + +```text +:) CREATE TABLE nested_test (s String, nest Nested(x UInt8, y UInt32)) ENGINE = Memory + +CREATE TABLE nested_test +( + s String, + nest Nested( + x UInt8, + y UInt32) +) ENGINE = Memory + +Ok. + +0 rows in set. Elapsed: 0.006 sec. + +:) INSERT INTO nested_test VALUES ('Hello', [1,2], [10,20]), ('World', [3,4,5], [30,40,50]), ('Goodbye', [], []) + +INSERT INTO nested_test VALUES + +Ok. + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT * FROM nested_test + +SELECT * +FROM nested_test + +┌─s───────┬─nest.x──┬─nest.y─────┐ +│ Hello │ [1,2] │ [10,20] │ +│ World │ [3,4,5] │ [30,40,50] │ +│ Goodbye │ [] │ [] │ +└─────────┴─────────┴────────────┘ + +3 rows in set. Elapsed: 0.001 sec. + +:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest + +SELECT s, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN nest + +┌─s─────┬─nest.x─┬─nest.y─┐ +│ Hello │ 1 │ 10 │ +│ Hello │ 2 │ 20 │ +│ World │ 3 │ 30 │ +│ World │ 4 │ 40 │ +│ World │ 5 │ 50 │ +└───────┴────────┴────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +При указании имени вложенной структуры данных в ARRAY JOIN, смысл такой же, как ARRAY JOIN со всеми элементами-массивами, из которых она состоит. Пример: + +```text +:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x, nest.y + +SELECT s, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN `nest.x`, `nest.y` + +┌─s─────┬─nest.x─┬─nest.y─┐ +│ Hello │ 1 │ 10 │ +│ Hello │ 2 │ 20 │ +│ World │ 3 │ 30 │ +│ World │ 4 │ 40 │ +│ World │ 5 │ 50 │ +└───────┴────────┴────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +Такой вариант тоже имеет смысл: + +```text +:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x + +SELECT s, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN `nest.x` + +┌─s─────┬─nest.x─┬─nest.y─────┐ +│ Hello │ 1 │ [10,20] │ +│ Hello │ 2 │ [10,20] │ +│ World │ 3 │ [30,40,50] │ +│ World │ 4 │ [30,40,50] │ +│ World │ 5 │ [30,40,50] │ +└───────┴────────┴────────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +Алиас для вложенной структуры данных можно использовать, чтобы выбрать как результат JOIN-а, так и исходный массив. Пример: + +```text +:) SELECT s, n.x, n.y, nest.x, nest.y FROM nested_test ARRAY JOIN nest AS n + +SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y` +FROM nested_test +ARRAY JOIN nest AS n + +┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┐ +│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ +│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ +│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ +│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ +│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ +└───────┴─────┴─────┴─────────┴────────────┘ + +5 rows in set. Elapsed: 0.001 sec. +``` + +Пример использования функции arrayEnumerate: + +```text +:) SELECT s, n.x, n.y, nest.x, nest.y, num FROM nested_test ARRAY JOIN nest AS n, arrayEnumerate(nest.x) AS num + +SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y`, num +FROM nested_test +ARRAY JOIN nest AS n, arrayEnumerate(`nest.x`) AS num + +┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┬─num─┐ +│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ 1 │ +│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ 2 │ +│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ 1 │ +│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ 2 │ +│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ 3 │ +└───────┴─────┴─────┴─────────┴────────────┴─────┘ + +5 rows in set. Elapsed: 0.002 sec. +``` + +В запросе может быть указано не более одной секции ARRAY JOIN. + +Соответствующее преобразование может выполняться как до секции WHERE/PREWHERE (если его результат нужен в этой секции), так и после выполнения WHERE/PREWHERE (чтобы уменьшить объём вычислений). + +### Секция JOIN + +Обычный JOIN, не имеет отношения к ARRAY JOIN, который описан выше. + +```sql +[GLOBAL] ANY|ALL INNER|LEFT [OUTER] JOIN (subquery)|table USING columns_list +``` + +Выполняет соединение с данными из подзапроса. В начале выполнения запроса, выполняется подзапрос, указанный после JOIN, и его результат сохраняется в память. Затем производится чтение из "левой" таблицы, указанной в секции FROM, и во время этого чтения, для каждой прочитанной строчки из "левой" таблицы, из таблицы-результата подзапроса ("правой" таблицы) выбираются строчки, соответствующие условию на совпадение значений столбцов, указанных в USING. + +Вместо подзапроса может быть указано имя таблицы. Это эквивалентно подзапросу `SELECT * FROM table`, кроме особого случая, когда таблица имеет движок Join - подготовленное множество для соединения. + +Из подзапроса удаляются все ненужные для JOIN-а столбцы. + +JOIN-ы бывают нескольких видов: + +`INNER` или `LEFT` - тип: +Если указано INNER, то в результат попадают только строки, для которых найдена соответствующая строка в "правой" таблице. +Если указано LEFT, то для строчек "левой" таблицы, для которых нет соответствующих в "правой" таблице, будут присоединены значения "по умолчанию" - нули, пустые строки. Вместо LEFT может быть написано LEFT OUTER - слово OUTER ни на что не влияет. + +`ANY` или `ALL` - строгость: +Если указано `ANY`, то при наличии в "правой" таблице нескольких соответствующих строк, будет присоединена только первая попавшаяся. +Если указано `ALL`, то при наличии в "правой" таблице нескольких соответствующих строк, данные будут размножены по количеству этих строк. + +Использование ALL соответствует обычной семантике JOIN-а из стандартного SQL. +Использование ANY является более оптимальным. Если известно, что в "правой" таблице есть не более одной подходящей строки, то результаты ANY и ALL совпадают. Обязательно необходимо указать ANY или ALL (ни один из этих вариантов не выбран по умолчанию). + +`GLOBAL` - распределённость: + +При использовании обычного JOIN-а, запрос отправляется на удалённые серверы, и на каждом из них выполняются подзапросы для формирования "правой" таблицы, и с этой таблицей выполняется соединение. То есть, "правая" таблица формируется на каждом сервере отдельно. + +При использовании `GLOBAL ... JOIN-а`, сначала, на сервере-инициаторе запроса, выполняется подзапрос для вычисления "правой" таблицы, и затем эта временная таблица передаётся на каждый удалённый сервер, и на них выполняются запросы, с использованием этих переданных временных данных. + +Следует быть аккуратным при использовании GLOBAL JOIN-ов. Подробнее читайте в разделе "Распределённые подзапросы" ниже. + +Возможны все комбинации JOIN-ов. Например, `GLOBAL ANY LEFT OUTER JOIN`. + +При выполнении JOIN-а отсутствует оптимизация порядка выполнения по отношению к другим стадиям запроса: соединение (поиск в "правой" таблице) выполняется до фильтрации в WHERE, до агрегации. Поэтому, чтобы явно задать порядок вычислений, рекомендуется выполнять JOIN подзапроса с подзапросом. + +Пример: + +```sql +SELECT + CounterID, + hits, + visits +FROM +( + SELECT + CounterID, + count() AS hits + FROM test.hits + GROUP BY CounterID +) ANY LEFT JOIN +( + SELECT + CounterID, + sum(Sign) AS visits + FROM test.visits + GROUP BY CounterID +) USING CounterID +ORDER BY hits DESC +LIMIT 10 +``` + +```text +┌─CounterID─┬───hits─┬─visits─┐ +│ 1143050 │ 523264 │ 13665 │ +│ 731962 │ 475698 │ 102716 │ +│ 722545 │ 337212 │ 108187 │ +│ 722889 │ 252197 │ 10547 │ +│ 2237260 │ 196036 │ 9522 │ +│ 23057320 │ 147211 │ 7689 │ +│ 722818 │ 90109 │ 17847 │ +│ 48221 │ 85379 │ 4652 │ +│ 19762435 │ 77807 │ 7026 │ +│ 722884 │ 77492 │ 11056 │ +└───────────┴────────┴────────┘ +``` + +У подзапросов нет возможности задать имена и нет возможности их использовать для того, чтобы сослаться на столбец из конкретного подзапроса. +Требуется, чтобы столбцы, указанные в USING, назывались одинаково в обоих подзапросах, а остальные столбцы - по-разному. Изменить имена столбцов в подзапросах можно с помощью алиасов (в примере используются алиасы hits и visits). + +В секции USING указывается один или несколько столбцов для соединения, что обозначает условие на равенство этих столбцов. Список столбцов задаётся без скобок. Более сложные условия соединения не поддерживаются. + +"Правая" таблица (результат подзапроса) располагается в оперативке. Если оперативки не хватает, вы не сможете выполнить JOIN. + +В запросе (на одном уровне) можно указать только один JOIN. Чтобы выполнить несколько JOIN-ов, вы можете разместить их в подзапросах. + +Каждый раз для выполнения запроса с одинаковым JOIN-ом, подзапрос выполняется заново - результат не кэшируется. Это можно избежать, используя специальный движок таблиц Join, представляющий собой подготовленное множество для соединения, которое всегда находится в оперативке. Подробнее смотрите в разделе "Движки таблиц, Join". + +В некоторых случаях, вместо использования JOIN достаточно использовать IN - это более эффективно. +Среди разных типов JOIN-ов, наиболее эффективен ANY LEFT JOIN, затем ANY INNER JOIN; наименее эффективны ALL LEFT JOIN и ALL INNER JOIN. + +Если JOIN необходим для соединения с таблицами измерений (dimension tables - сравнительно небольшие таблицы, которые содержат свойства измерений - например, имена для рекламных кампаний), то использование JOIN может быть не очень удобным из-за громоздкости синтаксиса, а также из-за того, что правая таблица читается заново при каждом запросе. Специально для таких случаев существует функциональность "Внешние словари", которую следует использовать вместо JOIN. Подробнее смотрите раздел "Внешние словари". + +### Секция WHERE + +Секция WHERE, если есть, должна содержать выражение, имеющее тип UInt8. Обычно это какое-либо выражение с операторами сравнения и логическими операторами. +Это выражение будет использовано для фильтрации данных перед всеми остальными преобразованиями. + +Выражение анализируется на возможность использования индексов, если индексы поддерживаются движком таблицы. + +### Секция PREWHERE + +Имеет такой же смысл, как и секция WHERE. Отличие состоит в том, какие данные читаются из таблицы. +При использовании PREWHERE, из таблицы сначала читаются только столбцы, необходимые для выполнения PREWHERE. Затем читаются остальные столбцы, нужные для выполнения запроса, но из них только те блоки, в которых выражение в PREWHERE истинное. + +PREWHERE имеет смысл использовать, если есть условия фильтрации, не подходящие под индексы, которые использует меньшинство столбцов из тех, что есть в запросе, но достаточно сильно фильтрует данные. Таким образом, сокращается количество читаемых данных. + +Например, полезно писать PREWHERE для запросов, которые вынимают много столбцов, но в которых фильтрация производится лишь по нескольким столбцам. + +PREWHERE поддерживается только таблицами семейства `*MergeTree`. + +В запросе могут быть одновременно указаны секции PREWHERE и WHERE. В этом случае, PREWHERE идёт перед WHERE. + +Следует иметь ввиду, что указывать в PREWHERE только столбцы, по которым существует индекс, имеет мало смысла, так как при использовании индекса и так читаются лишь блоки данных, соответствующие индексу. + +Если настройка optimize_move_to_prewhere выставлена в 1, то при отсутствии PREWHERE, система будет автоматически переносить части выражений из WHERE в PREWHERE согласно некоторой эвристике. + +### Секция GROUP BY + +Это одна из наиболее важных частей СУБД. + +Секция GROUP BY, если есть, должна содержать список выражений. Каждое выражение далее будем называть "ключом". +При этом, все выражения в секциях SELECT, HAVING, ORDER BY, должны вычисляться из ключей или из агрегатных функций. То есть, каждый выбираемый из таблицы столбец, должен использоваться либо в ключах, либо внутри агрегатных функций. + +Если запрос содержит столбцы таблицы только внутри агрегатных функций, то секция GROUP BY может не указываться, и подразумевается агрегация по пустому набору ключей. + +Пример: + +```sql +SELECT + count(), + median(FetchTiming > 60 ? 60 : FetchTiming), + count() - sum(Refresh) +FROM hits +``` + +Но, в отличие от стандартного SQL, если в таблице нет строк (вообще нет или после фильтрации с помощью WHERE), в качестве результата возвращается пустой результат, а не результат из одной строки, содержащий "начальные" значения агрегатных функций. + +В отличие от MySQL (и в соответствии со стандартом SQL), вы не можете получить какое-нибудь значение некоторого столбца, не входящего в ключ или агрегатную функцию (за исключением константных выражений). Для обхода этого вы можете воспользоваться агрегатной функцией any (получить первое попавшееся значение) или min/max. + +Пример: + +```sql +SELECT + domainWithoutWWW(URL) AS domain, + count(), + any(Title) AS title -- getting the first occurred page header for each domain. +FROM hits +GROUP BY domain +``` + +GROUP BY вычисляет для каждого встретившегося различного значения ключей, набор значений агрегатных функций. + +Не поддерживается GROUP BY по столбцам-массивам. + +Не поддерживается указание констант в качестве аргументов агрегатных функций. Пример: sum(1). Вместо этого, вы можете избавиться от констант. Пример: `count()`. + +#### Модификатор WITH TOTALS + +Если указан модификатор WITH TOTALS, то будет посчитана ещё одна строчка, в которой в столбцах-ключах будут содержаться значения по умолчанию (нули, пустые строки), а в столбцах агрегатных функций - значения, посчитанные по всем строкам ("тотальные" значения). + +Эта дополнительная строчка выводится в форматах JSON\*, TabSeparated\*, Pretty\* отдельно от остальных строчек. В остальных форматах эта строчка не выводится. + +В форматах JSON\* строчка выводится отдельным полем totals. В форматах TabSeparated\* строчка выводится после основного результата, и перед ней (после остальных данных) вставляется пустая строка. В форматах Pretty\* строчка выводится отдельной табличкой после основного результата. + +`WITH TOTALS` может выполняться по-разному при наличии HAVING. Поведение зависит от настройки totals_mode. +По умолчанию `totals_mode = 'before_having'`. В этом случае totals считается по всем строчкам, включая непрошедших через HAVING и max_rows_to_group_by. + +Остальные варианты учитывают в totals только строчки, прошедшие через HAVING, и имеют разное поведение при наличии настройки `max_rows_to_group_by` и `group_by_overflow_mode = 'any'`. + +`after_having_exclusive` - не учитывать строчки, не прошедшие `max_rows_to_group_by`. То есть в totals попадёт меньше или столько же строчек, чем если бы `max_rows_to_group_by` не было. + +`after_having_inclusive` - учитывать в totals все строчки, не прошедшие max_rows_to_group_by. То есть в totals попадёт больше или столько же строчек, чем если бы `max_rows_to_group_by` не было. + +`after_having_auto` - считать долю строчек, прошедших через HAVING. Если она больше некоторого значения (по умолчанию - 50%), то включить все строчки, не прошедшие max_rows_to_group_by в totals, иначе - не включить. + +`totals_auto_threshold` - по умолчанию 0.5. Коэффициент для работы `after_having_auto`. + +Если `max_rows_to_group_by` и `group_by_overflow_mode = 'any'` не используются, то все варианты вида `after_having` не отличаются, и вы можете использовать любой из них, например, `after_having_auto`. + +Вы можете использовать WITH TOTALS в подзапросах, включая подзапросы в секции JOIN (в этом случае соответствующие тотальные значения будут соединены). + +#### GROUP BY во внешней памяти + +Существует возможность включить сброс временных данных на диск для ограничения потребления оперативной памяти при GROUP BY. +Настройка `max_bytes_before_external_group_by` - потребление оперативки, при котором временные данные GROUP BY сбрасываются в файловую систему. Если равно 0 (по умолчанию) - значит выключено. + +При использовании `max_bytes_before_external_group_by` рекомендуется выставить max_memory_usage примерно в два раза больше. Это следует сделать, потому что агрегация выполняется в две стадии: чтение и формирование промежуточных данных (1) и слияние промежуточных данных (2). Сброс данных на файловую систему может производиться только на стадии 1. Если сброса временных данных не было, то на стадии 2 может потребляться до такого же объёма памяти, как на стадии 1. + +Например, если у вас `max_memory_usage` было выставлено в 10000000000, и вы хотите использовать внешнюю агрегацию, то имеет смысл выставить `max_bytes_before_external_group_by` в 10000000000, а max_memory_usage в 20000000000. При срабатывании внешней агрегации (если был хотя бы один сброс временных данных в файловую систему) максимальное потребление оперативки будет лишь чуть-чуть больше `max_bytes_before_external_group_by`. + +При распределённой обработке запроса внешняя агрегация производится на удалённых серверах. Для того чтобы на сервере-инициаторе запроса использовалось немного оперативки, нужно выставить настройку `distributed_aggregation_memory_efficient` в 1. + +При слиянии данных, сброшенных на диск, а также при слиянии результатов с удалённых серверов, при включенной настройке `distributed_aggregation_memory_efficient`, потребляется до 1/256 \* количество потоков от общего объёма оперативки. + +При включенной внешней агрегации, если данных было меньше `max_bytes_before_external_group_by` (то есть сброса данных не было), то запрос работает так же быстро, как без внешней агрегации. Если же какие-то временные данные были сброшены, то время выполнения будет в несколько раз больше (примерно в три раза). + +Если после GROUP BY у вас есть ORDER BY с небольшим LIMIT, то на ORDER BY не будет тратиться существенного количества оперативки. +Но если есть ORDER BY без LIMIT, то не забудьте включить внешнюю сортировку (`max_bytes_before_external_sort`). + +### Секция LIMIT N BY + +LIMIT N BY COLUMNS выбирает топ N строк для каждой группы COLUMNS. LIMIT N BY не связан с LIMIT и они могут использоваться в одном запросе. Ключ для LIMIT N BY может содержать произвольное число колонок или выражений. + +Пример: + +```sql +SELECT + domainWithoutWWW(URL) AS domain, + domainWithoutWWW(REFERRER_URL) AS referrer, + device_type, + count() cnt +FROM hits +GROUP BY domain, referrer, device_type +ORDER BY cnt DESC +LIMIT 5 BY domain, device_type +LIMIT 100 +``` + +Запрос выберет топ 5 рефереров для каждой пары `domain, device_type`, но не более 100 строк (`LIMIT n BY + LIMIT`). + +### Секция HAVING + +Позволяет отфильтровать результат, полученный после GROUP BY, аналогично секции WHERE. +WHERE и HAVING отличаются тем, что WHERE выполняется до агрегации (GROUP BY), а HAVING - после. +Если агрегации не производится, то HAVING использовать нельзя. + + + +### Секция ORDER BY + +Секция ORDER BY содержит список выражений, к каждому из которых также может быть приписано DESC или ASC (направление сортировки). Если ничего не приписано - это аналогично приписыванию ASC. ASC - сортировка по возрастанию, DESC - сортировка по убыванию. Обозначение направления сортировки действует на одно выражение, а не на весь список. Пример: `ORDER BY Visits DESC, SearchPhrase` + +Для сортировки по значениям типа String есть возможность указать collation (сравнение). Пример: `ORDER BY SearchPhrase COLLATE 'tr'` - для сортировки по поисковой фразе, по возрастанию, с учётом турецкого алфавита, регистронезависимо, при допущении, что строки в кодировке UTF-8. COLLATE может быть указан или не указан для каждого выражения в ORDER BY независимо. Если есть ASC или DESC, то COLLATE указывается после них. При использовании COLLATE сортировка всегда регистронезависима. + +Рекомендуется использовать COLLATE только для окончательной сортировки небольшого количества строк, так как производительность сортировки с указанием COLLATE меньше, чем обычной сортировки по байтам. + +Строки, для которых список выражений, по которым производится сортировка, принимает одинаковые значения, выводятся в произвольном порядке, который может быть также недетерминированным (каждый раз разным). +Если секция ORDER BY отсутствует, то, аналогично, порядок, в котором идут строки, не определён, и может быть недетерминированным. + +При сортировке чисел с плавающей запятой, NaN-ы идут отдельно от остальных значений. Вне зависимости от порядка сортировки, NaN-ы помещаются в конец. То есть, при сортировке по возрастанию, они как будто больше всех чисел, а при сортировке по убыванию - как будто меньше всех. + +Если кроме 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 оперативки, и вам нужно выполнить один запрос, то выставите max_memory_usage в 100 GB, а max_bytes_before_external_sort в 80 GB. + +Внешняя сортировка работает существенно менее эффективно, чем сортировка в оперативке. + +### Секция SELECT + +После вычислений, соответствующих всем перечисленным выше секциям, производится вычисление выражений, указанных в секции SELECT. +Вернее, вычисляются выражения, стоящие над агрегатными функциями, если есть агрегатные функции. +Сами агрегатные функции и то, что под ними, вычисляются при агрегации (GROUP BY). +Эти выражения работают так, как будто применяются к отдельным строкам результата. + +### Секция DISTINCT + +Если указано DISTINCT, то из всех множеств полностью совпадающих строк результата, будет оставляться только одна строка. +Результат выполнения будет таким же, как если указано GROUP BY по всем указанным полям в SELECT-е и не указаны агрегатные функции. Но имеется несколько отличий от GROUP BY: + +- DISTINCT может применяться совместно с GROUP BY; +- при отсутствии ORDER BY и наличии LIMIT, запрос прекратит выполнение сразу после того, как будет прочитано необходимое количество различных строк - в этом случае использование DISTINCT существенно более оптимально; +- блоки данных будут выдаваться по мере их обработки, не дожидаясь выполнения всего запроса. + +DISTINCT не поддерживается, если в SELECT-е присутствует хотя бы один столбец типа массив. + +### Секция LIMIT + +LIMIT m позволяет выбрать из результата первые m строк. +LIMIT n, m позволяет выбрать из результата первые m строк после пропуска первых n строк. + +n и m должны быть неотрицательными целыми числами. + +При отсутствии секции ORDER BY, однозначно сортирующей результат, результат может быть произвольным и может являться недетерминированным. + +### Секция UNION ALL + +Произвольное количество запросов может быть объединено с помощью UNION ALL. Пример: + +```sql +SELECT CounterID, 1 AS table, toInt64(count()) AS c + FROM test.hits + GROUP BY CounterID + +UNION ALL + +SELECT CounterID, 2 AS table, sum(Sign) AS c + FROM test.visits + GROUP BY CounterID + HAVING c > 0 +``` + +Поддерживается только UNION ALL. Обычный UNION (UNION DISTINCT) не поддерживается. Если вам нужен UNION DISTINCT, то вы можете написать SELECT DISTINCT из подзапроса, содержащего UNION ALL. + +Запросы - части UNION ALL могут выполняться параллельно, и их результаты могут возвращаться вперемешку. + +Структура результатов (количество и типы столбцов) у запросов должна совпадать. Но имена столбцов могут отличаться. В этом случае, имена столбцов для общего результата будут взяты из первого запроса. + +Запросы - части UNION ALL нельзя заключить в скобки. ORDER BY и LIMIT применяются к отдельным запросам, а не к общему результату. Если вам нужно применить какое-либо преобразование к общему результату, то вы можете разместить все запросы с UNION ALL в подзапросе в секции FROM. + +### Секция INTO OUTFILE + +При указании `INTO OUTFILE filename` (где filename - строковый литерал), результат запроса будет сохранён в файл filename. +В отличие от MySQL, файл создаётся на стороне клиента. Если файл с таким именем уже существует, это приведёт к ошибке. +Функциональность доступна в клиенте командной строки и clickhouse-local (попытка выполнить запрос с INTO OUTFILE через HTTP интерфейс приведёт к ошибке). + +Формат вывода по умолчанию - TabSeparated, как и в неинтерактивном режиме клиента командной строки. + +### Секция FORMAT + +При указании FORMAT format вы можете получить данные в любом указанном формате. +Это может использоваться для удобства или для создания дампов. +Подробнее смотрите раздел "Форматы". +Если секция FORMAT отсутствует, то используется формат по умолчанию, который зависит от используемого интерфейса для доступа к БД и от настроек. Для HTTP интерфейса, а также для клиента командной строки, используемого в batch-режиме, по умолчанию используется формат TabSeparated. Для клиента командной строки, используемого в интерактивном режиме, по умолчанию используется формат PrettyCompact (прикольные таблички, компактные). + +При использовании клиента командной строки данные на клиент передаются во внутреннем эффективном формате. При этом клиент самостоятельно интерпретирует секцию FORMAT запроса и форматирует данные на своей стороне (снимая нагрузку на сеть и сервер). + +### Операторы IN + +Операторы `IN`, `NOT IN`, `GLOBAL IN`, `GLOBAL NOT IN` рассматриваются отдельно, так как их функциональность достаточно богатая. + +В качестве левой части оператора, может присутствовать как один столбец, так и кортеж. + +Примеры: + +```sql +SELECT UserID IN (123, 456) FROM ... +SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ... +``` + +Если слева стоит один столбец, входящий в индекс, а справа - множество констант, то при выполнении запроса, система воспользуется индексом. + +Не перечисляйте слишком большое количество значений (миллионы) явно. Если множество большое - лучше загрузить его во временную таблицу (например, смотрите раздел "Внешние данные для обработки запроса"), и затем воспользоваться подзапросом. + +В качестве правой части оператора может быть множество константных выражений, множество кортежей с константными выражениями (показано в примерах выше), а также имя таблицы или подзапрос SELECT в скобках. + +Если в качестве правой части оператора указано имя таблицы (например, `UserID IN users`), то это эквивалентно подзапросу `UserID IN (SELECT * FROM users)`. Это используется при работе с внешними данными, отправляемым вместе с запросом. Например, вместе с запросом может быть отправлено множество идентификаторов посетителей, загруженное во временную таблицу users, по которому следует выполнить фильтрацию. + +Если качестве правой части оператора, указано имя таблицы, имеющий движок Set (подготовленное множество, постоянно находящееся в оперативке), то множество не будет создаваться заново при каждом запросе. + +В подзапросе может быть указано более одного столбца для фильтрации кортежей. +Пример: + +```sql +SELECT (CounterID, UserID) IN (SELECT CounterID, UserID FROM ...) FROM ... +``` + +Типы столбцов слева и справа оператора IN, должны совпадать. + +Оператор IN и подзапрос могут встречаться в любой части запроса, в том числе в агрегатных и лямбда функциях. +Пример: + +```sql +SELECT + EventDate, + avg(UserID IN + ( + SELECT UserID + FROM test.hits + WHERE EventDate = toDate('2014-03-17') + )) AS ratio +FROM test.hits +GROUP BY EventDate +ORDER BY EventDate ASC +``` + +```text +┌──EventDate─┬────ratio─┐ +│ 2014-03-17 │ 1 │ +│ 2014-03-18 │ 0.807696 │ +│ 2014-03-19 │ 0.755406 │ +│ 2014-03-20 │ 0.723218 │ +│ 2014-03-21 │ 0.697021 │ +│ 2014-03-22 │ 0.647851 │ +│ 2014-03-23 │ 0.648416 │ +└────────────┴──────────┘ +``` + +за каждый день после 17 марта считаем долю хитов, сделанных посетителями, которые заходили на сайт 17 марта. +Подзапрос в секции IN на одном сервере всегда выполняется только один раз. Зависимых подзапросов не существует. + + + +#### Распределённые подзапросы + +Существует два варианта IN-ов с подзапросами (аналогично для JOIN-ов): обычный `IN` / `JOIN` и `GLOBAL IN` / `GLOBAL JOIN`. Они отличаются способом выполнения при распределённой обработке запроса. + +
+ +Помните, что алгоритмы, описанные ниже, могут работать иначе в зависимости от [настройки](../operations/settings/settings.md#settings-distributed_product_mode) `distributed_product_mode`. + +
+ +При использовании обычного IN-а, запрос отправляется на удалённые серверы, и на каждом из них выполняются подзапросы в секциях `IN` / `JOIN`. + +При использовании `GLOBAL IN` / `GLOBAL JOIN-а`, сначала выполняются все подзапросы для `GLOBAL IN` / `GLOBAL JOIN-ов`, и результаты складываются во временные таблицы. Затем эти временные таблицы передаются на каждый удалённый сервер, и на них выполняются запросы, с использованием этих переданных временных данных. + +Если запрос не распределённый, используйте обычный `IN` / `JOIN`. + +Следует быть внимательным при использовании подзапросов в секции `IN` / `JOIN` в случае распределённой обработки запроса. + +Рассмотрим это на примерах. Пусть на каждом сервере кластера есть обычная таблица **local_table**. Пусть также есть таблица **distributed_table** типа **Distributed**, которая смотрит на все серверы кластера. + +При запросе к распределённой таблице **distributed_table**, запрос будет отправлен на все удалённые серверы, и на них будет выполнен с использованием таблицы **local_table**. + +Например, запрос + +```sql +SELECT uniq(UserID) FROM distributed_table +``` + +будет отправлен на все удалённые серверы в виде + +```sql +SELECT uniq(UserID) FROM local_table +``` + +, выполнен параллельно на каждом из них до стадии, позволяющей объединить промежуточные результаты; затем промежуточные результаты вернутся на сервер-инициатор запроса, будут на нём объединены, и финальный результат будет отправлен клиенту. + +Теперь рассмотрим запрос с IN-ом: + +```sql +SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) +``` + +- расчёт пересечения аудиторий двух сайтов. + +Этот запрос будет отправлен на все удалённые серверы в виде + +```sql +SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) +``` + +То есть, множество в секции IN будет собрано на каждом сервере независимо, только по тем данным, которые есть локально на каждом из серверов. + +Это будет работать правильно и оптимально, если вы предусмотрели такой случай, и раскладываете данные по серверам кластера таким образом, чтобы данные одного UserID-а лежали только на одном сервере. В таком случае все необходимые данные будут присутствовать на каждом сервере локально. В противном случае результат будет посчитан неточно. Назовём этот вариант запроса "локальный IN". + +Чтобы исправить работу запроса, когда данные размазаны по серверам кластера произвольным образом, можно было бы указать **distributed_table** внутри подзапроса. Запрос будет выглядеть так: + +```sql +SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) +``` + +Этот запрос будет отправлен на все удалённые серверы в виде + +```sql +SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) +``` + +На каждом удалённом сервере начнёт выполняться подзапрос. Так как в подзапросе используется распределённая таблица, то подзапрос будет, на каждом удалённом сервере, снова отправлен на каждый удалённый сервер, в виде + +```sql +SELECT UserID FROM local_table WHERE CounterID = 34 +``` + +Например, если у вас кластер из 100 серверов, то выполнение всего запроса потребует 10 000 элементарных запросов, что, как правило, является неприемлемым. + +В таких случаях всегда следует использовать GLOBAL IN вместо IN. Рассмотрим его работу для запроса + +```sql +SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID GLOBAL IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) +``` + +На сервере-инициаторе запроса будет выполнен подзапрос + +```sql +SELECT UserID FROM distributed_table WHERE CounterID = 34 +``` + +, и результат будет сложен во временную таблицу в оперативке. Затем запрос будет отправлен на каждый удалённый сервер в виде + +```sql +SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID GLOBAL IN _data1 +``` + +, и вместе с запросом, на каждый удалённый сервер будет отправлена временная таблица `_data1` (имя временной таблицы - implementation defined). + +Это гораздо более оптимально, чем при использовании обычного IN. Но при этом, следует помнить о нескольких вещах: + +1. При создании временной таблицы данные не уникализируются. Чтобы уменьшить объём передаваемых по сети данных, укажите в подзапросе DISTINCT (для обычного IN-а этого делать не нужно). +2. Временная таблица будет передана на все удалённые серверы. Передача не учитывает топологию сети. Например, если 10 удалённых серверов расположены в удалённом относительно сервера-инициатора запроса датацентре, то по каналу в удалённый датацентр данные будет переданы 10 раз. Старайтесь не использовать большие множества при использовании GLOBAL IN. +3. При передаче данных на удалённые серверы не настраивается ограничение использования сетевой полосы. Вы можете перегрузить сеть. +4. Старайтесь распределять данные по серверам так, чтобы в GLOBAL IN-ах не было частой необходимости. +5. Если в GLOBAL IN есть частая необходимость, то спланируйте размещение кластера ClickHouse таким образом, чтобы в каждом датацентре была хотя бы одна реплика каждого шарда, и среди них была быстрая сеть - чтобы запрос целиком можно было бы выполнить, передавая данные в пределах одного датацентра. + +В секции `GLOBAL IN` также имеет смысл указывать локальную таблицу - в случае, если эта локальная таблица есть только на сервере-инициаторе запроса, и вы хотите воспользоваться данными из неё на удалённых серверах. + +### Экстремальные значения + +Вы можете получить в дополнение к результату также минимальные и максимальные значения по столбцам результата. Для этого выставите настройку **extremes** в 1. Минимумы и максимумы считаются для числовых типов, дат, дат-с-временем. Для остальных столбцов будут выведены значения по умолчанию. + +Вычисляются дополнительные две строчки - минимумы и максимумы, соответственно. Эти дополнительные две строчки выводятся в форматах JSON\*, TabSeparated\*, Pretty\* отдельно от остальных строчек. В остальных форматах они не выводится. + +В форматах JSON\* экстремальные значения выводятся отдельным полем extremes. В форматах TabSeparated\* строчка выводится после основного результата и после totals, если есть. Перед ней (после остальных данных) вставляется пустая строка. В форматах Pretty\* строчка выводится отдельной табличкой после основного результата и после totals, если есть. + +Экстремальные значения считаются по строчкам, прошедшим через LIMIT. Но при этом, при использовании LIMIT offset, size, строчки до offset учитываются в extremes. В потоковых запросах, в результате может учитываться также небольшое количество строчек, прошедших LIMIT. + +### Замечания + +В секциях `GROUP BY`, `ORDER BY`, в отличие от диалекта MySQL, и в соответствии со стандартным SQL, не поддерживаются позиционные аргументы. +Например, если вы напишите `GROUP BY 1, 2` - то это будет воспринято, как группировка по константам (то есть, агрегация всех строк в одну). + +Вы можете использовать синонимы (алиасы `AS`) в любом месте запроса. + +В любом месте запроса, вместо выражения, может стоять звёздочка. При анализе запроса звёздочка раскрывается в список всех столбцов таблицы (за исключением `MATERIALIZED` и `ALIAS` столбцов). Есть лишь немного случаев, когда оправдано использовать звёздочку: + +- при создании дампа таблицы; +- для таблиц, содержащих всего несколько столбцов - например, системных таблиц; +- для получения информации о том, какие столбцы есть в таблице; в этом случае, укажите `LIMIT 1`. Но лучше используйте запрос `DESC TABLE`; +- при наличии сильной фильтрации по небольшому количеству столбцов с помощью `PREWHERE`; +- в подзапросах (так как из подзапросов выкидываются столбцы, не нужные для внешнего запроса). + +В других случаях использование звёздочки является издевательством над системой, так как вместо преимуществ столбцовой СУБД вы получаете недостатки. То есть использовать звёздочку не рекомендуется. From ef0e452bf5ff2ae267d190d3a2aa9d12b4ba5d8b Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 10:45:26 +0300 Subject: [PATCH 030/425] queries.md has been supposed to be removed --- docs/ru/query_language/queries.md | 1556 ----------------------------- 1 file changed, 1556 deletions(-) delete mode 100644 docs/ru/query_language/queries.md diff --git a/docs/ru/query_language/queries.md b/docs/ru/query_language/queries.md deleted file mode 100644 index 8bf39a8aa71..00000000000 --- a/docs/ru/query_language/queries.md +++ /dev/null @@ -1,1556 +0,0 @@ - - -# Запросы - -## CREATE DATABASE -Создание базы данных db_name - -```sql -CREATE DATABASE [IF NOT EXISTS] db_name -``` - -`База данных` - это просто директория для таблиц. -Если написано `IF NOT EXISTS`, то запрос не будет возвращать ошибку, если база данных уже существует. - - - - -## CREATE TABLE -Запрос `CREATE TABLE` может иметь несколько форм. - -```sql -CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name [ON CLUSTER cluster] -( - name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], - name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2], - ... -) ENGINE = engine -``` - -Создаёт таблицу с именем name в БД db или текущей БД, если db не указана, со структурой, указанной в скобках, и движком engine. -Структура таблицы представляет список описаний столбцов. Индексы, если поддерживаются движком, указываются в качестве параметров для движка таблицы. - -Описание столбца, это `name type`, в простейшем случае. Пример: `RegionID UInt32`. -Также могут быть указаны выражения для значений по умолчанию - смотрите ниже. - -```sql -CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine] -``` - -Создаёт таблицу с такой же структурой, как другая таблица. Можно указать другой движок для таблицы. Если движок не указан, то будет выбран такой же движок, как у таблицы `db2.name2`. - -```sql -CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... -``` - -Создаёт таблицу со структурой, как результат запроса `SELECT`, с движком engine, и заполняет её данными из SELECT-а. - -Во всех случаях, если указано `IF NOT EXISTS`, то запрос не будет возвращать ошибку, если таблица уже существует. В этом случае, запрос будет ничего не делать. - -### Значения по умолчанию - - -В описании столбца, может быть указано выражение для значения по умолчанию, одного из следующих видов: -`DEFAULT expr`, `MATERIALIZED expr`, `ALIAS expr`. -Пример: `URLDomain String DEFAULT domain(URL)`. - -Если выражение для значения по умолчанию не указано, то в качестве значений по умолчанию будут использоваться нули для чисел, пустые строки для строк, пустые массивы для массивов, а также `0000-00-00` для дат и `0000-00-00 00:00:00` для дат с временем. NULL-ы не поддерживаются. - -В случае, если указано выражение по умолчанию, то указание типа столбца не обязательно. При отсутствии явно указанного типа, будет использован тип выражения по умолчанию. Пример: `EventDate DEFAULT toDate(EventTime)` - для столбца EventDate будет использован тип Date. - -При наличии явно указанного типа данных и выражения по умолчанию, это выражение будет приводиться к указанному типу с использованием функций приведения типа. Пример: `Hits UInt32 DEFAULT 0` - имеет такой же смысл, как `Hits UInt32 DEFAULT toUInt32(0)`. - -В качестве выражения для умолчания, может быть указано произвольное выражение от констант и столбцов таблицы. При создании и изменении структуры таблицы, проверяется, что выражения не содержат циклов. При INSERT-е проверяется разрешимость выражений - что все столбцы, из которых их можно вычислить, переданы. - -`DEFAULT expr` - -Обычное значение по умолчанию. Если в запросе INSERT не указан соответствующий столбец, то он будет заполнен путём вычисления соответствующего выражения. - -`MATERIALIZED expr` - -Материализованное выражение. Такой столбец не может быть указан при INSERT, то есть, он всегда вычисляется. -При INSERT без указания списка столбцов, такие столбцы не рассматриваются. -Также этот столбец не подставляется при использовании звёздочки в запросе SELECT - чтобы сохранить инвариант, что дамп, полученный путём `SELECT *`, можно вставить обратно в таблицу INSERT-ом без указания списка столбцов. - -`ALIAS expr` - -Синоним. Такой столбец вообще не хранится в таблице. -Его значения не могут быть вставлены в таблицу, он не подставляется при использовании звёздочки в запросе SELECT. -Он может быть использован в SELECT-ах - в таком случае, во время разбора запроса, алиас раскрывается. - -При добавлении новых столбцов с помощью запроса ALTER, старые данные для этих столбцов не записываются. Вместо этого, при чтении старых данных, для которых отсутствуют значения новых столбцов, выполняется вычисление выражений по умолчанию на лету. При этом, если выполнение выражения требует использования других столбцов, не указанных в запросе, то эти столбцы будут дополнительно прочитаны, но только для тех блоков данных, для которых это необходимо. - -Если добавить в таблицу новый столбец, а через некоторое время изменить его выражение по умолчанию, то используемые значения для старых данных (для данных, где значения не хранились на диске) поменяются. Также заметим, что при выполнении фоновых слияний, данные для столбцов, отсутствующих в одном из сливаемых кусков, записываются в объединённый кусок. - -Отсутствует возможность задать значения по умолчанию для элементов вложенных структур данных. - -### Временные таблицы - -Во всех случаях, если указано `TEMPORARY`, то будет создана временная таблица. Временные таблицы обладают следующими особенностями: -- временные таблицы исчезают после завершения сессии; в том числе, при обрыве соединения; -- временная таблица создаётся с движком Memory; все остальные движки таблиц не поддерживаются; -- для временной таблицы нет возможности указать БД: она создаётся вне баз данных; -- если временная таблица имеет то же имя, что и некоторая другая, то, при упоминании в запросе без указания БД, будет использована временная таблица; -- при распределённой обработке запроса, используемые в запросе временные таблицы, передаются на удалённые серверы. - -В большинстве случаев, временные таблицы создаются не вручную, а при использовании внешних данных для запроса, или при распределённом `(GLOBAL) IN`. Подробнее см. соответствующие разделы - -Распределенные DDL запросы (секция ON CLUSTER) ----------------------------------------------- - -Запросы `CREATE`, `DROP`, `ALTER`, `RENAME` поддерживают возможность распределенного выполнения на кластере. -Например, следующий запрос создает `Distributed`-таблицу `all_hits` на каждом хосте кластера `cluster`: - -```sql -CREATE TABLE IF NOT EXISTS all_hits ON CLUSTER cluster (p Date, i Int32) ENGINE = Distributed(cluster, default, hits) -``` - -Для корректного выполнения таких запросов необходимо на каждом хосте иметь одинаковое определение кластера (для упрощения синхронизации конфигов можете использовать подстановки из ZooKeeper), также необходимо подключение к ZooKeeper серверам. -Локальная версия запроса в конечном итоге будет выполнена на каждом хосте кластера, даже если некоторые хосты в данный момент не доступны, гарантируется упорядоченность выполнения запросов в рамках одного хоста. -Пока не поддерживаются `ALTER`-запросы для реплицированных таблиц. - -## CREATE VIEW - -```sql -CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT ... -``` - -Создаёт представление. Представления бывают двух видов - обычные и материализованные (MATERIALIZED). - -При создании материализованного представления, нужно обязательно указать ENGINE - движок таблицы для хранения данных. - -Материализованное представление работает следующим образом: при вставлении данных в таблицу, указанную в SELECT, часть вставленных данных конвертируется запросом, а результат вставляется в представление. - -Обычные представления не хранят никаких данных, а всего лишь производят чтение из другой таблицы. То есть, обычное представление - не более чем сохранённый запрос. При чтении из представления, этот сохранённый запрос, используется в качестве подзапроса в секции FROM. - -Для примера, пусть вы создали представление: - -```sql -CREATE VIEW view AS SELECT ... -``` - -и написали запрос: - -```sql -SELECT a, b, c FROM view -``` - -Этот запрос полностью эквивалентен использованию подзапроса: - -```sql -SELECT a, b, c FROM (SELECT ...) -``` - -Материализованные (MATERIALIZED) представления хранят данные, преобразованные соответствующим запросом SELECT. - -При создании материализованного представления, нужно обязательно указать ENGINE - движок таблицы для хранения данных. - -Материализованное представление устроено следующим образом: при вставке данных в таблицу, указанную в SELECT-е, кусок вставляемых данных преобразуется этим запросом SELECT, и полученный результат вставляется в представление. - -Если указано POPULATE, то при создании представления, в него будут вставлены имеющиеся данные таблицы, как если бы был сделан запрос `CREATE TABLE ... AS SELECT ...` . Иначе, представление будет содержать только данные, вставляемые в таблицу после создания представления. Не рекомендуется использовать POPULATE, так как вставляемые в таблицу данные во время создания представления, не попадут в него. - -Запрос `SELECT` может содержать `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`... Следует иметь ввиду, что соответствующие преобразования будут выполняться независимо, на каждый блок вставляемых данных. Например, при наличии `GROUP BY`, данные будут агрегироваться при вставке, но только в рамках одной пачки вставляемых данных. Далее, данные не будут доагрегированы. Исключение - использование ENGINE, производящего агрегацию данных самостоятельно, например, `SummingMergeTree`. - -Недоработано выполнение запросов `ALTER` над материализованными представлениями, поэтому они могут быть неудобными для использования. Если материализованное представление использует конструкцию ``TO [db.]name``, то можно выполнить ``DETACH`` представления, ``ALTER`` для целевой таблицы и последующий ``ATTACH`` ранее отсоединенного (``DETACH``) представления. - -Представления выглядят так же, как обычные таблицы. Например, они перечисляются в результате запроса `SHOW TABLES`. - -Отсутствует отдельный запрос для удаления представлений. Чтобы удалить представление, следует использовать `DROP TABLE`. - - - -## ATTACH -Запрос полностью аналогичен запросу `CREATE`, но: - -- вместо слова `CREATE` используется слово `ATTACH`; -- запрос не создаёт данные на диске, а предполагает, что данные уже лежат в соответствующих местах, и всего лишь добавляет информацию о таблице в сервер. - -После выполнения `ATTACH`, сервер будет знать о существовании таблицы. - -Если таблица перед этим была отсоединена (`DETACH`), т.е. её структура известна, то можно использовать сокращенную форму записи без определения структуры. - -```sql -ATTACH TABLE [IF NOT EXISTS] [db.]name -``` - -Этот запрос используется при старте сервера. Сервер хранит метаданные таблиц в виде файлов с запросами `ATTACH`, которые он просто исполняет при запуске (за исключением системных таблиц, создание которых явно вписано в сервер). - -## DROP -Запрос имеет два вида: `DROP DATABASE` и `DROP TABLE`. - -```sql -DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster] -``` - -Удаляет все таблицы внутри базы данных db, а затем саму базу данных db. -Если указано `IF EXISTS` - не выдавать ошибку, если база данных не существует. - -```sql -DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster] -``` - -Удаляет таблицу. -Если указано `IF EXISTS` - не выдавать ошибку, если таблица не существует или база данных не существует. - -## DETACH -Удаляет из сервера информацию о таблице name. Сервер перестаёт знать о существовании таблицы. - -```sql -DETACH TABLE [IF EXISTS] [db.]name -``` - -Но ни данные, ни метаданные таблицы не удаляются. При следующем запуске сервера, сервер прочитает метаданные и снова узнает о таблице. -Также, "отцепленную" таблицу можно прицепить заново запросом `ATTACH` (за исключением системных таблиц, для которых метаданные не хранятся). - -Запроса `DETACH DATABASE` нет. - -## RENAME -Переименовывает одну или несколько таблиц. - -```sql -RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... [ON CLUSTER cluster] -``` - -Все таблицы переименовываются под глобальной блокировкой. Переименовывание таблицы является лёгкой операцией. Если вы указали после TO другую базу данных, то таблица будет перенесена в эту базу данных. При этом, директории с базами данных должны быть расположены в одной файловой системе (иначе возвращается ошибка). - - - -## ALTER -Запрос `ALTER` поддерживается только для таблиц типа `*MergeTree`, а также `Merge` и `Distributed`. Запрос имеет несколько вариантов. - -### Манипуляции со столбцами - -Изменение структуры таблицы. - -```sql -ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|MODIFY COLUMN ... -``` - -В запросе указывается список из одного или более действий через запятую. -Каждое действие - операция над столбцом. - -Существуют следующие действия: - -```sql -ADD COLUMN name [type] [default_expr] [AFTER name_after] -``` - -Добавляет в таблицу новый столбец с именем name, типом type и выражением для умолчания `default_expr` (смотрите раздел "Значения по умолчанию"). Если указано `AFTER name_after` (имя другого столбца), то столбец добавляется (в список столбцов таблицы) после указанного. Иначе, столбец добавляется в конец таблицы. Внимательный читатель может заметить, что отсутствует возможность добавить столбец в начало таблицы. Для цепочки действий, name_after может быть именем столбца, который добавляется в одном из предыдущих действий. - -Добавление столбца всего лишь меняет структуру таблицы, и не производит никаких действий с данными - соответствующие данные не появляются на диске после ALTER-а. При чтении из таблицы, если для какого-либо столбца отсутствуют данные, то он заполняется значениями по умолчанию (выполняя выражение по умолчанию, если такое есть, или нулями, пустыми строками). Также, столбец появляется на диске при слиянии кусков данных (см. MergeTree). - -Такая схема позволяет добиться мгновенной работы запроса ALTER и отсутствия необходимости увеличивать объём старых данных. - -```sql -DROP COLUMN name -``` - -Удаляет столбец с именем name. -Удаляет данные из файловой системы. Так как это представляет собой удаление целых файлов, запрос выполняется почти мгновенно. - -```sql -MODIFY COLUMN name [type] [default_expr] -``` - -Изменяет тип столбца name на type и/или выражение для умолчания на default_expr. При изменении типа, значения преобразуются так, как если бы к ним была применена функция toType. - -Если изменяется только выражение для умолчания, то запрос не делает никакой сложной работы и выполняется мгновенно. - -Изменение типа столбца - это единственное действие, которое выполняет сложную работу - меняет содержимое файлов с данными. Для больших таблиц, выполнение может занять длительное время. - -Выполнение производится в несколько стадий: -- подготовка временных (новых) файлов с изменёнными данными; -- переименование старых файлов; -- переименование временных (новых) файлов в старые; -- удаление старых файлов. - -Из них, длительной является только первая стадия. Если на этой стадии возникнет сбой, то данные не поменяются. -Если на одной из следующих стадий возникнет сбой, то данные будет можно восстановить вручную. За исключением случаев, когда старые файлы удалены из файловой системы, а данные для новых файлов не доехали на диск и потеряны. - -Не поддерживается изменение типа столбца у массивов и вложенных структур данных. - -Запрос `ALTER` позволяет создавать и удалять отдельные элементы (столбцы) вложенных структур данных, но не вложенные структуры данных целиком. Для добавления вложенной структуры данных, вы можете добавить столбцы с именем вида `name.nested_name` и типом `Array(T)` - вложенная структура данных полностью эквивалентна нескольким столбцам-массивам с именем, имеющим одинаковый префикс до точки. - -Отсутствует возможность удалять столбцы, входящие в первичный ключ или ключ для сэмплирования (в общем, входящие в выражение `ENGINE`). Изменение типа у столбцов, входящих в первичный ключ возможно только в том случае, если это изменение не приводит к изменению данных (например, разрешено добавление значения в Enum или изменение типа с `DateTime` на `UInt32`). - -Если возможностей запроса `ALTER` не хватает для нужного изменения таблицы, вы можете создать новую таблицу, скопировать туда данные с помощью запроса `INSERT SELECT`, затем поменять таблицы местами с помощью запроса `RENAME`, и удалить старую таблицу. - -Запрос `ALTER` блокирует все чтения и записи для таблицы. То есть, если на момент запроса `ALTER`, выполнялся долгий `SELECT`, то запрос `ALTER` сначала дождётся его выполнения. И в это время, все новые запросы к той же таблице, будут ждать, пока завершится этот `ALTER`. - -Для таблиц, которые не хранят данные самостоятельно (типа `Merge` и `Distributed`), `ALTER` всего лишь меняет структуру таблицы, но не меняет структуру подчинённых таблиц. Для примера, при ALTER-е таблицы типа `Distributed`, вам также потребуется выполнить запрос `ALTER` для таблиц на всех удалённых серверах. - -Запрос `ALTER` на изменение столбцов реплицируется. Соответствующие инструкции сохраняются в ZooKeeper, и затем каждая реплика их применяет. Все запросы `ALTER` выполняются в одном и том же порядке. Запрос ждёт выполнения соответствующих действий на всех репликах. Но при этом, запрос на изменение столбцов в реплицируемой таблице можно прервать, и все действия будут осуществлены асинхронно. - -### Манипуляции с партициями и кусками - -Работает только для таблиц семейства `MergeTree`. Существуют следующие виды операций: - -- `DETACH PARTITION` - перенести партицию в директорию detached и забыть про неё. -- `DROP PARTITION` - удалить партицию. -- `ATTACH PART|PARTITION` - добавить в таблицу новый кусок или партицию из директории `detached`. -- `FREEZE PARTITION` - создать бэкап партиции. -- `FETCH PARTITION` - скачать партицию с другого сервера. - -Ниже будет рассмотрен каждый вид запроса по-отдельности. - -Партицией (partition) в таблице называются данные за один календарный месяц. Это определяется значениями ключа-даты, указанной в параметрах движка таблицы. Данные за каждый месяц хранятся отдельно, чтобы упростить всевозможные манипуляции с этими данными. - -Куском (part) в таблице называется часть данных одной партиции, отсортированная по первичному ключу. - -Чтобы посмотреть набор кусков и партиций таблицы, можно воспользоваться системной таблицей `system.parts`: - -```sql -SELECT * FROM system.parts WHERE active -``` - -`active` - учитывать только активные куски. Неактивными являются, например, исходные куски оставшиеся после слияния в более крупный кусок - такие куски удаляются приблизительно через 10 минут после слияния. - -Другой способ посмотреть набор кусков и партиций - зайти в директорию с данными таблицы. -Директория с данными - `/var/lib/clickhouse/data/database/table/`, -где `/var/lib/clickhouse/` - путь к данным ClickHouse, database - имя базы данных, table - имя таблицы. Пример: - -```bash -$ ls -l /var/lib/clickhouse/data/test/visits/ -total 48 -drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_2_2_0 -drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_4_4_0 -drwxrwxrwx 2 clickhouse clickhouse 4096 May 5 02:55 detached --rw-rw-rw- 1 clickhouse clickhouse 2 May 5 02:58 increment.txt -``` - -Здесь `20140317_20140323_2_2_0`, `20140317_20140323_4_4_0` - директории кусков. - -Рассмотрим по порядку имя первого куска: `20140317_20140323_2_2_0`. - -- `20140317` - минимальная дата данных куска -- `20140323` - максимальная дата данных куска -- `2` - минимальный номер блока данных -- `2` - максимальный номер блока данных -- `0` - уровень куска - глубина дерева слияний, которыми он образован - -Каждый кусок относится к одной партиции и содержит данные только за один месяц. -`201403` - имя партиции. Партиция представляет собой набор кусков за один месяц. - -При работающем сервере, нельзя вручную изменять набор кусков или их данные на файловой системе, так как сервер не будет об этом знать. -Для нереплицируемых таблиц, вы можете это делать при остановленном сервере, хотя это не рекомендуется. -Для реплицируемых таблиц, набор кусков нельзя менять в любом случае. - -Директория `detached` содержит куски, не используемые сервером - отцепленные от таблицы с помощью запроса `ALTER ... DETACH`. Также в эту директорию переносятся куски, признанные повреждёнными, вместо их удаления. Вы можете в любое время добавлять, удалять, модифицировать данные в директории detached - сервер не будет об этом знать, пока вы не сделаете запрос `ALTER TABLE ... ATTACH`. - -```sql -ALTER TABLE [db.]table DETACH PARTITION 'name' -``` - -Перенести все данные для партиции с именем name в директорию detached и забыть про них. -Имя партиции указывается в формате YYYYMM. Оно может быть указано в одинарных кавычках или без них. - -После того, как запрос будет выполнен, вы можете самостоятельно сделать что угодно с данными в директории detached, например, удалить их из файловой системы, или ничего не делать. - -Запрос реплицируется - данные будут перенесены в директорию detached и забыты на всех репликах. Запрос может быть отправлен только на реплику-лидер. Вы можете узнать, является ли реплика лидером, сделав SELECT в системную таблицу system.replicas. Или, проще, вы можете выполнить запрос на всех репликах, и на всех кроме одной, он кинет исключение. - -```sql -ALTER TABLE [db.]table DROP PARTITION 'name' -``` - -Аналогично операции `DETACH`. Удалить данные из таблицы. Куски с данными будут помечены как неактивные и будут полностью удалены примерно через 10 минут. Запрос реплицируется - данные будут удалены на всех репликах. - -```sql -ALTER TABLE [db.]table ATTACH PARTITION|PART 'name' -``` - -Добавить данные в таблицу из директории detached. - -Существует возможность добавить данные для целой партиции (PARTITION) или отдельный кусок (PART). В случае PART, укажите полное имя куска в одинарных кавычках. - -Запрос реплицируется. Каждая реплика проверяет, если ли данные в директории detached. Если данные есть - проверяет их целостность, проверяет их соответствие данным на сервере-инициаторе запроса, и если всё хорошо, то добавляет их. Если нет, то скачивает данные с реплики-инициатора запроса, или с другой реплики, на которой уже добавлены эти данные. - -То есть, вы можете разместить данные в директории detached на одной реплике и, с помощью запроса ALTER ... ATTACH добавить их в таблицу на всех репликах. - -```sql -ALTER TABLE [db.]table FREEZE PARTITION 'name' -``` - -Создаёт локальный бэкап одной или нескольких партиций. В качестве имени может быть указано полное имя партиции (например, 201403) или его префикс (например, 2014) - тогда бэкап будет создан для всех соответствующих партиций. - -Запрос делает следующее: для снэпшота данных на момент его выполнения, создаёт hardlink-и на данные таблиц в директории `/var/lib/clickhouse/shadow/N/...` - -`/var/lib/clickhouse/` - рабочая директория ClickHouse из конфига. -`N` - инкрементальный номер бэкапа. - -Структура директорий внутри бэкапа создаётся такой же, как внутри `/var/lib/clickhouse/`. -Также делает chmod всех файлов, запрещая запись в них. - -Создание бэкапа происходит почти мгновенно (но сначала дожидается окончания выполняющихся в данный момент запросов к соответствующей таблице). Бэкап изначально не занимает места на диске. При дальнейшей работе системы, бэкап может отнимать место на диске, по мере модификации данных. Если бэкап делается для достаточно старых данных, то он не будет отнимать место на диске. - -После создания бэкапа, данные из `/var/lib/clickhouse/shadow/` можно скопировать на удалённый сервер и затем удалить на локальном сервере. -Весь процесс бэкапа не требует остановки сервера. - -Запрос `ALTER ... FREEZE PARTITION` не реплицируется. То есть, локальный бэкап создаётся только на локальном сервере. - -В качестве альтернативного варианта, вы можете скопировать данные из директории `/var/lib/clickhouse/data/database/table` вручную. -Но если это делать при запущенном сервере, то возможны race conditions при копировании директории с добавляющимися/изменяющимися файлами, и бэкап может быть неконсистентным. Этот вариант может использоваться, если сервер не запущен - тогда полученные данные будут такими же, как после запроса `ALTER TABLE t FREEZE PARTITION`. - -`ALTER TABLE ... FREEZE PARTITION` копирует только данные, но не метаданные таблицы. Чтобы сделать бэкап метаданных таблицы, скопируйте файл `/var/lib/clickhouse/metadata/database/table.sql` - -Для восстановления из бэкапа: - -> - создайте таблицу, если её нет, с помощью запроса CREATE. Запрос можно взять из .sql файла (замените в нём `ATTACH` на `CREATE`); -> - скопируйте данные из директории data/database/table/ внутри бэкапа в директорию `/var/lib/clickhouse/data/database/table/detached/` -> - выполните запросы `ALTER TABLE ... ATTACH PARTITION YYYYMM`, где `YYYYMM` - месяц, для каждого месяца. - -Таким образом, данные из бэкапа будут добавлены в таблицу. -Восстановление из бэкапа, так же, не требует остановки сервера. - -### Бэкапы и репликация - -Репликация защищает от аппаратных сбоев. В случае, если на одной из реплик у вас исчезли все данные, то восстановление делается по инструкции в разделе "Восстановление после сбоя". - -Для защиты от аппаратных сбоев, обязательно используйте репликацию. Подробнее про репликацию написано в разделе "Репликация данных". - -Бэкапы защищают от человеческих ошибок (случайно удалили данные, удалили не те данные или не на том кластере, испортили данные). -Для баз данных большого объёма, бывает затруднительно копировать бэкапы на удалённые серверы. В этих случаях, для защиты от человеческой ошибки, можно держать бэкап на том же сервере (он будет лежать в `/var/lib/clickhouse/shadow/`). - -```sql -ALTER TABLE [db.]table FETCH PARTITION 'name' FROM 'path-in-zookeeper' -``` - -Запрос работает только для реплицируемых таблиц. - -Скачивает указанную партицию с шарда, путь в `ZooKeeper` к которому указан в секции `FROM` и помещает в директорию `detached` указанной таблицы. - -Не смотря на то, что запрос называется `ALTER TABLE`, он не изменяет структуру таблицы, и не изменяет сразу доступные данные в таблице. - -Данные помещаются в директорию `detached`, и их можно прикрепить с помощью запроса `ALTER TABLE ... ATTACH`. - -В секции `FROM` указывается путь в `ZooKeeper`. Например, `/clickhouse/tables/01-01/visits`. -Перед скачиванием проверяется существование партиции и совпадение структуры таблицы. Автоматически выбирается наиболее актуальная реплика среди живых реплик. - -Запрос `ALTER ... FETCH PARTITION` не реплицируется. То есть, партиция будет скачана в директорию detached только на локальном сервере. Заметим, что если вы после этого добавите данные в таблицу с помощью запроса `ALTER TABLE ... ATTACH`, то данные будут добавлены на всех репликах (на одной из реплик будут добавлены из директории detached, а на других - загружены с соседних реплик). - -### Синхронность запросов ALTER - -Для нереплицируемых таблиц, все запросы `ALTER` выполняются синхронно. Для реплицируемых таблиц, запрос всего лишь добавляет инструкцию по соответствующим действиям в `ZooKeeper`, а сами действия осуществляются при первой возможности. Но при этом, запрос может ждать завершения выполнения этих действий на всех репликах. - -Для запросов `ALTER ... ATTACH|DETACH|DROP` можно настроить ожидание, с помощью настройки `replication_alter_partitions_sync`. -Возможные значения: `0` - не ждать, `1` - ждать выполнения только у себя (по умолчанию), `2` - ждать всех. - - - -### Мутации - -Мутации - разновидность запроса ALTER, позволяющая изменять или удалять данные в таблице. В отличие от стандартных запросов `DELETE` и `UPDATE`, рассчитанных на точечное изменение данных, область применения мутаций - достаточно тяжёлые изменения, затрагивающие много строк в таблице. - -Функциональность находится в состоянии beta и доступна начиная с версии 1.1.54388. Реализована поддержка *MergeTree таблиц (с репликацией и без). - -Конвертировать существующие таблицы для работы с мутациями не нужно. Но после применения первой мутации формат данных таблицы становится несовместимым с предыдущими версиями и откатиться на предыдущую версию уже не получится. - -На данный момент доступна команда `ALTER DELETE`: - -```sql -ALTER TABLE [db.]table DELETE WHERE expr -``` - -Выражение `expr` должно иметь тип UInt8. Запрос удаляет строки таблицы, для которых это выражение принимает ненулевое значение. - -В одном запросе можно указать несколько команд через запятую. - -Для *MergeTree-таблиц мутации выполняются, перезаписывая данные по кускам (parts). При этом атомарности нет - куски заменяются на помутированные по мере выполнения и запрос `SELECT`, заданный во время выполнения мутации, увидит данные как из измененных кусков, так и из кусков, которые еще не были изменены. - -Мутации линейно упорядочены между собой и накладываются на каждый кусок в порядке добавления. Мутации также упорядочены со вставками - гарантируется, что данные, вставленные в таблицу до начала выполнения запроса мутации, будут изменены, а данные, вставленные после окончания запроса мутации, изменены не будут. При этом мутации никак не блокируют вставки. - -Запрос завершается немедленно после добавления информации о мутации (для реплицированных таблиц - в ZooKeeper, для нереплицированных - на файловую систему). Сама мутация выполняется асинхронно, используя настройки системного профиля. Следить за ходом её выполнения можно по таблице `system.mutations`. Добавленные мутации будут выполняться до конца даже в случае перезапуска серверов ClickHouse. Откатить мутацию после её добавления нельзя. - -#### Таблица system.mutations - -Таблица содержит информацию о ходе выполнения мутаций MergeTree-таблиц. Каждой команде мутации соответствует одна строка. В таблице есть следующие столбцы: - -**database**, **table** - имя БД и таблицы, к которой была применена мутация. - -**mutation_id** - ID запроса. Для реплицированных таблиц эти ID соответствуют именам записей в директории `/mutations/` в ZooKeeper, для нереплицированных - именам файлов в директории с данными таблицы. - -**command** - Команда мутации (часть запроса после `ALTER TABLE [db.]table`). - -**create_time** - Время создания мутации. - -**block_numbers.partition_id**, **block_numbers.number** - Nested-столбец. Для мутаций реплицированных таблиц для каждой партиции содержит номер блока, полученный этой мутацией (в каждой партиции будут изменены только куски, содержащие блоки с номерами, меньшими номера, полученного мутацией в этой партиции). Для нереплицированных таблиц нумерация блоков сквозная по партициям, поэтому столбец содержит одну запись с единственным номером блока, полученным мутацией. - -**parts_to_do** - Количество кусков таблицы, которые ещё предстоит изменить. - -**is_done** - Завершена ли мутация. Замечание: даже если `parts_to_do = 0`, для реплицированной таблицы возможна ситуация, когда мутация ещё не завершена из-за долго выполняющейся вставки, которая добавляет данные, которые нужно будет мутировать. - -## SHOW DATABASES - -```sql -SHOW DATABASES [INTO OUTFILE filename] [FORMAT format] -``` - -Выводит список всех баз данных. -Запрос полностью аналогичен запросу `SELECT name FROM system.databases [INTO OUTFILE filename] [FORMAT format]`. - -Смотрите также раздел "Форматы". - -## SHOW TABLES - -```sql -SHOW [TEMPORARY] TABLES [FROM db] [LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format] -``` - -Выводит список таблиц - -- из текущей БД или из БД db, если указано FROM db; -- всех, или имя которых соответствует шаблону pattern, если указано LIKE 'pattern'; - -Запрос полностью аналогичен запросу: `SELECT name FROM system.tables WHERE database = 'db' [AND name LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]`. - -Смотрите также раздел "Оператор LIKE". - -## SHOW PROCESSLIST - -```sql -SHOW PROCESSLIST [INTO OUTFILE filename] [FORMAT format] -``` - -Выводит список запросов, выполняющихся в данный момент времени, кроме запросов `SHOW PROCESSLIST`. - -Выдаёт таблицу, содержащую столбцы: - -**user** - пользователь, под которым был задан запрос. Следует иметь ввиду, что при распределённой обработке запроса на удалённые серверы запросы отправляются под пользователем default. И SHOW PROCESSLIST показывает имя пользователя для конкретного запроса, а не для запроса, который данный запрос инициировал. - -**address** - имя хоста, с которого был отправлен запрос. При распределённой обработке запроса на удалённых серверах — это имя хоста-инициатора запроса. Чтобы проследить, откуда был задан распределённый запрос изначально, следует смотреть SHOW PROCESSLIST на сервере-инициаторе запроса. - -**elapsed** - время выполнения запроса, в секундах. Запросы выводятся упорядоченными по убыванию времени выполнения. - -**rows_read**, **bytes_read** - сколько было прочитано строк, байт несжатых данных при обработке запроса. При распределённой обработке запроса суммируются данные со всех удалённых серверов. Именно эти данные используются для ограничений и квот. - -**memory_usage** - текущее потребление оперативки в байтах. Смотрите настройку max_memory_usage. - -**query** - сам запрос. В запросах INSERT данные для вставки не выводятся. - -**query_id** - идентификатор запроса. Непустой, только если был явно задан пользователем. При распределённой обработке запроса идентификатор запроса не передаётся на удалённые серверы. - -Запрос полностью аналогичен запросу: `SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]`. - -Полезный совет (выполните в консоли): - -```bash -watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'" -``` - -## SHOW CREATE TABLE - -```sql -SHOW CREATE [TEMPORARY] TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] -``` - -Возвращает один столбец statement типа `String`, содержащий одно значение - запрос `CREATE`, с помощью которого создана указанная таблица. - -## DESCRIBE TABLE - -```sql -DESC|DESCRIBE TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] -``` - -Возвращает два столбца: `name`, `type` типа `String`, в которых описаны имена и типы столбцов указанной таблицы. - -Вложенные структуры данных выводятся в "развёрнутом" виде. То есть, каждый столбец - по отдельности, с именем через точку. - -## EXISTS - -```sql -EXISTS [TEMPORARY] TABLE [db.]name [INTO OUTFILE filename] [FORMAT format] -``` - -Возвращает один столбец типа `UInt8`, содержащий одно значение - `0`, если таблицы или БД не существует и `1`, если таблица в указанной БД существует. - -## USE - -```sql -USE db -``` - -Позволяет установить текущую базу данных для сессии. -Текущая база данных используется для поиска таблиц, если база данных не указана в запросе явно через точку перед именем таблицы. -При использовании HTTP протокола, запрос не может быть выполнен, так как понятия сессии не существует. - -## SET - -```sql -SET param = value -``` - -Позволяет установить настройку `param` в значение `value`. Также можно одним запросом установить все настройки из заданного профиля настроек - для этого, укажите в качестве имени настройки profile. Подробнее смотри раздел "Настройки". -Настройка устанавливается на сессию, или на сервер (глобально), если указано `GLOBAL`. -При установке глобальной настройки, настройка на все уже запущенные сессии, включая текущую сессию, не устанавливается, а будет использована только для новых сессий. - -При перезапуске сервера, теряются настройки, установленные с помощью `SET`. -Установить настройки, которые переживут перезапуск сервера, можно только с помощью конфигурационного файла сервера. - -## OPTIMIZE - -```sql -OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] -``` - -Просит движок таблицы сделать что-нибудь, что может привести к более оптимальной работе. -Поддерживается только движками `*MergeTree`, в котором выполнение этого запроса инициирует внеочередное слияние кусков данных. -Если указан `PARTITION`, то оптимизация будет производиться только для указаной партиции. -Если указан `FINAL`, то оптимизация будет производиться даже когда все данные уже лежат в одном куске. - -
-Запрос OPTIMIZE не может устранить причину появления ошибки "Too many parts". -
- - - -## INSERT - -Добавление данных. - -Базовый формат запроса: - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ... -``` - -В запросе можно указать список столбцов для вставки `[(c1, c2, c3)]`. В этом случае, в остальные столбцы записываются: - -- Значения, вычисляемые из `DEFAULT` выражений, указанных в определении таблицы. -- Нули и пустые строки, если `DEFAULT` не определены. - -Если [strict_insert_defaults=1](../operations/settings/settings.md#settings-strict_insert_defaults), то столбцы, для которых не определены `DEFAULT`, необходимо перечислить в запросе. - -В INSERT можно передавать данные любого [формата](../interfaces/formats.md#formats), который поддерживает ClickHouse. Для этого формат необходимо указать в запросе в явном виде: - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set -``` - -Например, следующий формат запроса идентичен базовому варианту INSERT ... VALUES: - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ... -``` - -ClickHouse отсекает все пробелы и один перенос строки (если он есть) перед данными. Рекомендуем при формировании запроса переносить данные на новую строку после операторов запроса (это важно, если данные начинаются с пробелов). - -Пример: - -```sql -INSERT INTO t FORMAT TabSeparated -11 Hello, world! -22 Qwerty -``` - -С помощью консольного клиента или HTTP интерфейса можно вставлять данные отдельно от запроса. Как это сделать, читайте в разделе "[Интерфейсы](../interfaces/index.md#interfaces)". - -### Вставка результатов `SELECT` - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] SELECT ... -``` - -Соответствие столбцов определяется их позицией в секции SELECT. При этом, их имена в выражении SELECT и в таблице для INSERT, могут отличаться. При необходимости выполняется приведение типов данных, эквивалентное соответствующему оператору CAST. - -Все форматы данных кроме Values не позволяют использовать в качестве значений выражения, такие как `now()`, `1 + 2` и подобные. Формат Values позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода. - -Не поддерживаются другие запросы на модификацию части данных: `UPDATE`, `DELETE`, `REPLACE`, `MERGE`, `UPSERT`, `INSERT UPDATE`. -Вы можете удалять старые данные с помощью запроса `ALTER TABLE ... DROP PARTITION`. - -### Замечания о производительности - -`INSERT` сортирует входящие данные по первичному ключу и разбивает их на партиции по месяцам. Если вы вставляете данные за разные месяцы вперемешку, то это может значительно снизить производительность запроса `INSERT`. Чтобы избежать этого: - -- Добавляйте данные достаточно большими пачками. Например, по 100 000 строк. -- Группируйте данные по месацам самостоятельно перед загрузкой в ClickHouse. - -Снижения производительности не будет, если: - -- Данные поступают в режиме реального времени. -- Вы загружаете данные, которые как правило отсортированы по времени. - -## SELECT - -Выборка данных. - -```sql -SELECT [DISTINCT] expr_list - [FROM [db.]table | (subquery) | table_function] [FINAL] - [SAMPLE sample_coeff] - [ARRAY JOIN ...] - [GLOBAL] ANY|ALL INNER|LEFT JOIN (subquery)|table USING columns_list - [PREWHERE expr] - [WHERE expr] - [GROUP BY expr_list] [WITH TOTALS] - [HAVING expr] - [ORDER BY expr_list] - [LIMIT [n, ]m] - [UNION ALL ...] - [INTO OUTFILE filename] - [FORMAT format] - [LIMIT n BY columns] -``` - -Все секции, кроме списка выражений сразу после SELECT, являются необязательными. -Ниже секции будут описаны в порядке, почти соответствующем конвейеру выполнения запроса. - -Если в запросе отсутствуют секции `DISTINCT`, `GROUP BY`, `ORDER BY`, подзапросы в `IN` и `JOIN`, то запрос будет обработан полностью потоково, с использованием O(1) количества оперативки. -Иначе запрос может съесть много оперативки, если не указаны подходящие ограничения `max_memory_usage`, `max_rows_to_group_by`, `max_rows_to_sort`, `max_rows_in_distinct`, `max_bytes_in_distinct`, `max_rows_in_set`, `max_bytes_in_set`, `max_rows_in_join`, `max_bytes_in_join`, `max_bytes_before_external_sort`, `max_bytes_before_external_group_by`. Подробнее смотрите в разделе "Настройки". Присутствует возможность использовать внешнюю сортировку (с сохранением временных данных на диск) и внешнюю агрегацию. `Merge join` в системе нет. - -### Секция FROM - -Если секция FROM отсутствует, то данные будут читаться из таблицы `system.one`. -Таблица system.one содержит ровно одну строку (то есть, эта таблица выполняет такую же роль, как таблица DUAL, которую можно найти в других СУБД). - -В секции FROM указывается таблица, из которой будут читаться данные, либо подзапрос, либо табличная функция; дополнительно могут присутствовать ARRAY JOIN и обычный JOIN (смотрите ниже). - -Вместо таблицы, может быть указан подзапрос SELECT в скобках. -В этом случае, конвейер обработки подзапроса будет встроен в конвейер обработки внешнего запроса. -В отличие от стандартного SQL, после подзапроса не нужно указывать его синоним. Для совместимости, присутствует возможность написать AS name после подзапроса, но указанное имя нигде не используется. - -Вместо таблицы, может быть указана табличная функция. Подробнее смотрите раздел "Табличные функции". - -Для выполнения запроса, из соответствующей таблицы, вынимаются все столбцы, перечисленные в запросе. Из подзапросов выкидываются столбцы, не нужные для внешнего запроса. -Если в запросе не перечислено ни одного столбца (например, SELECT count() FROM t), то из таблицы всё равно вынимается один какой-нибудь столбец (предпочитается самый маленький), для того, чтобы можно было хотя бы посчитать количество строк. - -Модификатор FINAL может быть использован только при SELECT-е из таблицы типа CollapsingMergeTree. При указании FINAL, данные будут выбираться полностью "сколлапсированными". Стоит учитывать, что использование FINAL приводит к выбору кроме указанных в SELECT-е столбцов также столбцов, относящихся к первичному ключу. Также, запрос будет выполняться в один поток, и при выполнении запроса будет выполняться слияние данных. Это приводит к тому, что при использовании FINAL, запрос выполняется медленнее. В большинстве случаев, следует избегать использования FINAL. Подробнее смотрите раздел "Движок CollapsingMergeTree". - -### Секция SAMPLE - -Секция SAMPLE позволяет выполнить запрос приближённо. Приближённое выполнение запроса поддерживается только таблицами типа MergeTree\* и только если при создании таблицы было указано выражение, по которому производится выборка (смотрите раздел "Движок MergeTree"). - -`SAMPLE` имеет вид `SAMPLE k`, где `k` - дробное число в интервале от 0 до 1, или `SAMPLE n`, где n - достаточно большое целое число. - -В первом случае, запрос будет выполнен по k-доле данных. Например, если указано `SAMPLE 0.1`, то запрос будет выполнен по 10% данных. -Во втором случае, запрос будет выполнен по выборке из не более n строк. Например, если указано `SAMPLE 10000000`, то запрос будет выполнен по не более чем 10 000 000 строкам. - -Пример: - -```sql -SELECT - Title, - count() * 10 AS PageViews -FROM hits_distributed -SAMPLE 0.1 -WHERE - CounterID = 34 - AND toDate(EventDate) >= toDate('2013-01-29') - AND toDate(EventDate) <= toDate('2013-02-04') - AND NOT DontCountHits - AND NOT Refresh - AND Title != '' -GROUP BY Title -ORDER BY PageViews DESC LIMIT 1000 -``` - -В этом примере, запрос выполняется по выборке из 0.1 (10%) данных. Значения агрегатных функций не корректируются автоматически, поэтому для получения приближённого результата, значение count() вручную домножается на 10. - -При использовании варианта вида `SAMPLE 10000000`, нет информации, какая относительная доля данных была обработана, и на что следует домножить агрегатные функции, поэтому такой способ записи подходит не для всех случаев. - -Выборка с указанием относительного коэффициента является "согласованной": если рассмотреть все возможные данные, которые могли бы быть в таблице, то выборка (при использовании одного выражения сэмплирования, указанного при создании таблицы), с одинаковым коэффициентом, выбирает всегда одно и то же подмножество этих всевозможных данных. То есть, выборка из разных таблиц, на разных серверах, в разное время, делается одинаковым образом. - -Например, выборка по идентификаторам посетителей, выберет из разных таблиц строки с одинаковым подмножеством всех возможных идентификаторов посетителей. Это позволяет использовать выборку в подзапросах в секции IN, а также при ручном сопоставлении результатов разных запросов с выборками. - -### Секция ARRAY JOIN - -Позволяет выполнить JOIN с массивом или вложенной структурой данных. Смысл похож на функцию arrayJoin, но функциональность более широкая. - -`ARRAY JOIN` - это, по сути, `INNER JOIN` с массивом. Пример: - -```text -:) CREATE TABLE arrays_test (s String, arr Array(UInt8)) ENGINE = Memory - -CREATE TABLE arrays_test -( - s String, - arr Array(UInt8) -) ENGINE = Memory - -Ok. - -0 rows in set. Elapsed: 0.001 sec. - -:) INSERT INTO arrays_test VALUES ('Hello', [1,2]), ('World', [3,4,5]), ('Goodbye', []) - -INSERT INTO arrays_test VALUES - -Ok. - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT * FROM arrays_test - -SELECT * -FROM arrays_test - -┌─s───────┬─arr─────┐ -│ Hello │ [1,2] │ -│ World │ [3,4,5] │ -│ Goodbye │ [] │ -└─────────┴─────────┘ - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT s, arr FROM arrays_test ARRAY JOIN arr - -SELECT s, arr -FROM arrays_test -ARRAY JOIN arr - -┌─s─────┬─arr─┐ -│ Hello │ 1 │ -│ Hello │ 2 │ -│ World │ 3 │ -│ World │ 4 │ -│ World │ 5 │ -└───────┴─────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -Для массива в секции ARRAY JOIN может быть указан алиас. В этом случае, элемент массива будет доступен под этим алиасом, а сам массив - под исходным именем. Пример: - -```text -:) SELECT s, arr, a FROM arrays_test ARRAY JOIN arr AS a - -SELECT s, arr, a -FROM arrays_test -ARRAY JOIN arr AS a - -┌─s─────┬─arr─────┬─a─┐ -│ Hello │ [1,2] │ 1 │ -│ Hello │ [1,2] │ 2 │ -│ World │ [3,4,5] │ 3 │ -│ World │ [3,4,5] │ 4 │ -│ World │ [3,4,5] │ 5 │ -└───────┴─────────┴───┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -В секции ARRAY JOIN может быть указано несколько массивов одинаковых размеров через запятую. В этом случае, JOIN делается с ними одновременно (прямая сумма, а не прямое произведение). Пример: - -```text -:) SELECT s, arr, a, num, mapped FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(x -> x + 1, arr) AS mapped - -SELECT s, arr, a, num, mapped -FROM arrays_test -ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(lambda(tuple(x), plus(x, 1)), arr) AS mapped - -┌─s─────┬─arr─────┬─a─┬─num─┬─mapped─┐ -│ Hello │ [1,2] │ 1 │ 1 │ 2 │ -│ Hello │ [1,2] │ 2 │ 2 │ 3 │ -│ World │ [3,4,5] │ 3 │ 1 │ 4 │ -│ World │ [3,4,5] │ 4 │ 2 │ 5 │ -│ World │ [3,4,5] │ 5 │ 3 │ 6 │ -└───────┴─────────┴───┴─────┴────────┘ - -5 rows in set. Elapsed: 0.002 sec. - -:) SELECT s, arr, a, num, arrayEnumerate(arr) FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num - -SELECT s, arr, a, num, arrayEnumerate(arr) -FROM arrays_test -ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num - -┌─s─────┬─arr─────┬─a─┬─num─┬─arrayEnumerate(arr)─┐ -│ Hello │ [1,2] │ 1 │ 1 │ [1,2] │ -│ Hello │ [1,2] │ 2 │ 2 │ [1,2] │ -│ World │ [3,4,5] │ 3 │ 1 │ [1,2,3] │ -│ World │ [3,4,5] │ 4 │ 2 │ [1,2,3] │ -│ World │ [3,4,5] │ 5 │ 3 │ [1,2,3] │ -└───────┴─────────┴───┴─────┴─────────────────────┘ - -5 rows in set. Elapsed: 0.002 sec. -``` - -ARRAY JOIN также работает с вложенными структурами данных. Пример: - -```text -:) CREATE TABLE nested_test (s String, nest Nested(x UInt8, y UInt32)) ENGINE = Memory - -CREATE TABLE nested_test -( - s String, - nest Nested( - x UInt8, - y UInt32) -) ENGINE = Memory - -Ok. - -0 rows in set. Elapsed: 0.006 sec. - -:) INSERT INTO nested_test VALUES ('Hello', [1,2], [10,20]), ('World', [3,4,5], [30,40,50]), ('Goodbye', [], []) - -INSERT INTO nested_test VALUES - -Ok. - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT * FROM nested_test - -SELECT * -FROM nested_test - -┌─s───────┬─nest.x──┬─nest.y─────┐ -│ Hello │ [1,2] │ [10,20] │ -│ World │ [3,4,5] │ [30,40,50] │ -│ Goodbye │ [] │ [] │ -└─────────┴─────────┴────────────┘ - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest - -SELECT s, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN nest - -┌─s─────┬─nest.x─┬─nest.y─┐ -│ Hello │ 1 │ 10 │ -│ Hello │ 2 │ 20 │ -│ World │ 3 │ 30 │ -│ World │ 4 │ 40 │ -│ World │ 5 │ 50 │ -└───────┴────────┴────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -При указании имени вложенной структуры данных в ARRAY JOIN, смысл такой же, как ARRAY JOIN со всеми элементами-массивами, из которых она состоит. Пример: - -```text -:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x, nest.y - -SELECT s, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN `nest.x`, `nest.y` - -┌─s─────┬─nest.x─┬─nest.y─┐ -│ Hello │ 1 │ 10 │ -│ Hello │ 2 │ 20 │ -│ World │ 3 │ 30 │ -│ World │ 4 │ 40 │ -│ World │ 5 │ 50 │ -└───────┴────────┴────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -Такой вариант тоже имеет смысл: - -```text -:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x - -SELECT s, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN `nest.x` - -┌─s─────┬─nest.x─┬─nest.y─────┐ -│ Hello │ 1 │ [10,20] │ -│ Hello │ 2 │ [10,20] │ -│ World │ 3 │ [30,40,50] │ -│ World │ 4 │ [30,40,50] │ -│ World │ 5 │ [30,40,50] │ -└───────┴────────┴────────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -Алиас для вложенной структуры данных можно использовать, чтобы выбрать как результат JOIN-а, так и исходный массив. Пример: - -```text -:) SELECT s, n.x, n.y, nest.x, nest.y FROM nested_test ARRAY JOIN nest AS n - -SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN nest AS n - -┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┐ -│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ -│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ -│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ -│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ -│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ -└───────┴─────┴─────┴─────────┴────────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -Пример использования функции arrayEnumerate: - -```text -:) SELECT s, n.x, n.y, nest.x, nest.y, num FROM nested_test ARRAY JOIN nest AS n, arrayEnumerate(nest.x) AS num - -SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y`, num -FROM nested_test -ARRAY JOIN nest AS n, arrayEnumerate(`nest.x`) AS num - -┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┬─num─┐ -│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ 1 │ -│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ 2 │ -│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ 1 │ -│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ 2 │ -│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ 3 │ -└───────┴─────┴─────┴─────────┴────────────┴─────┘ - -5 rows in set. Elapsed: 0.002 sec. -``` - -В запросе может быть указано не более одной секции ARRAY JOIN. - -Соответствующее преобразование может выполняться как до секции WHERE/PREWHERE (если его результат нужен в этой секции), так и после выполнения WHERE/PREWHERE (чтобы уменьшить объём вычислений). - -### Секция JOIN - -Обычный JOIN, не имеет отношения к ARRAY JOIN, который описан выше. - -```sql -[GLOBAL] ANY|ALL INNER|LEFT [OUTER] JOIN (subquery)|table USING columns_list -``` - -Выполняет соединение с данными из подзапроса. В начале выполнения запроса, выполняется подзапрос, указанный после JOIN, и его результат сохраняется в память. Затем производится чтение из "левой" таблицы, указанной в секции FROM, и во время этого чтения, для каждой прочитанной строчки из "левой" таблицы, из таблицы-результата подзапроса ("правой" таблицы) выбираются строчки, соответствующие условию на совпадение значений столбцов, указанных в USING. - -Вместо подзапроса может быть указано имя таблицы. Это эквивалентно подзапросу `SELECT * FROM table`, кроме особого случая, когда таблица имеет движок Join - подготовленное множество для соединения. - -Из подзапроса удаляются все ненужные для JOIN-а столбцы. - -JOIN-ы бывают нескольких видов: - -`INNER` или `LEFT` - тип: -Если указано INNER, то в результат попадают только строки, для которых найдена соответствующая строка в "правой" таблице. -Если указано LEFT, то для строчек "левой" таблицы, для которых нет соответствующих в "правой" таблице, будут присоединены значения "по умолчанию" - нули, пустые строки. Вместо LEFT может быть написано LEFT OUTER - слово OUTER ни на что не влияет. - -`ANY` или `ALL` - строгость: -Если указано `ANY`, то при наличии в "правой" таблице нескольких соответствующих строк, будет присоединена только первая попавшаяся. -Если указано `ALL`, то при наличии в "правой" таблице нескольких соответствующих строк, данные будут размножены по количеству этих строк. - -Использование ALL соответствует обычной семантике JOIN-а из стандартного SQL. -Использование ANY является более оптимальным. Если известно, что в "правой" таблице есть не более одной подходящей строки, то результаты ANY и ALL совпадают. Обязательно необходимо указать ANY или ALL (ни один из этих вариантов не выбран по умолчанию). - -`GLOBAL` - распределённость: - -При использовании обычного JOIN-а, запрос отправляется на удалённые серверы, и на каждом из них выполняются подзапросы для формирования "правой" таблицы, и с этой таблицей выполняется соединение. То есть, "правая" таблица формируется на каждом сервере отдельно. - -При использовании `GLOBAL ... JOIN-а`, сначала, на сервере-инициаторе запроса, выполняется подзапрос для вычисления "правой" таблицы, и затем эта временная таблица передаётся на каждый удалённый сервер, и на них выполняются запросы, с использованием этих переданных временных данных. - -Следует быть аккуратным при использовании GLOBAL JOIN-ов. Подробнее читайте в разделе "Распределённые подзапросы" ниже. - -Возможны все комбинации JOIN-ов. Например, `GLOBAL ANY LEFT OUTER JOIN`. - -При выполнении JOIN-а отсутствует оптимизация порядка выполнения по отношению к другим стадиям запроса: соединение (поиск в "правой" таблице) выполняется до фильтрации в WHERE, до агрегации. Поэтому, чтобы явно задать порядок вычислений, рекомендуется выполнять JOIN подзапроса с подзапросом. - -Пример: - -```sql -SELECT - CounterID, - hits, - visits -FROM -( - SELECT - CounterID, - count() AS hits - FROM test.hits - GROUP BY CounterID -) ANY LEFT JOIN -( - SELECT - CounterID, - sum(Sign) AS visits - FROM test.visits - GROUP BY CounterID -) USING CounterID -ORDER BY hits DESC -LIMIT 10 -``` - -```text -┌─CounterID─┬───hits─┬─visits─┐ -│ 1143050 │ 523264 │ 13665 │ -│ 731962 │ 475698 │ 102716 │ -│ 722545 │ 337212 │ 108187 │ -│ 722889 │ 252197 │ 10547 │ -│ 2237260 │ 196036 │ 9522 │ -│ 23057320 │ 147211 │ 7689 │ -│ 722818 │ 90109 │ 17847 │ -│ 48221 │ 85379 │ 4652 │ -│ 19762435 │ 77807 │ 7026 │ -│ 722884 │ 77492 │ 11056 │ -└───────────┴────────┴────────┘ -``` - -У подзапросов нет возможности задать имена и нет возможности их использовать для того, чтобы сослаться на столбец из конкретного подзапроса. -Требуется, чтобы столбцы, указанные в USING, назывались одинаково в обоих подзапросах, а остальные столбцы - по-разному. Изменить имена столбцов в подзапросах можно с помощью алиасов (в примере используются алиасы hits и visits). - -В секции USING указывается один или несколько столбцов для соединения, что обозначает условие на равенство этих столбцов. Список столбцов задаётся без скобок. Более сложные условия соединения не поддерживаются. - -"Правая" таблица (результат подзапроса) располагается в оперативке. Если оперативки не хватает, вы не сможете выполнить JOIN. - -В запросе (на одном уровне) можно указать только один JOIN. Чтобы выполнить несколько JOIN-ов, вы можете разместить их в подзапросах. - -Каждый раз для выполнения запроса с одинаковым JOIN-ом, подзапрос выполняется заново - результат не кэшируется. Это можно избежать, используя специальный движок таблиц Join, представляющий собой подготовленное множество для соединения, которое всегда находится в оперативке. Подробнее смотрите в разделе "Движки таблиц, Join". - -В некоторых случаях, вместо использования JOIN достаточно использовать IN - это более эффективно. -Среди разных типов JOIN-ов, наиболее эффективен ANY LEFT JOIN, затем ANY INNER JOIN; наименее эффективны ALL LEFT JOIN и ALL INNER JOIN. - -Если JOIN необходим для соединения с таблицами измерений (dimension tables - сравнительно небольшие таблицы, которые содержат свойства измерений - например, имена для рекламных кампаний), то использование JOIN может быть не очень удобным из-за громоздкости синтаксиса, а также из-за того, что правая таблица читается заново при каждом запросе. Специально для таких случаев существует функциональность "Внешние словари", которую следует использовать вместо JOIN. Подробнее смотрите раздел "Внешние словари". - -### Секция WHERE - -Секция WHERE, если есть, должна содержать выражение, имеющее тип UInt8. Обычно это какое-либо выражение с операторами сравнения и логическими операторами. -Это выражение будет использовано для фильтрации данных перед всеми остальными преобразованиями. - -Выражение анализируется на возможность использования индексов, если индексы поддерживаются движком таблицы. - -### Секция PREWHERE - -Имеет такой же смысл, как и секция WHERE. Отличие состоит в том, какие данные читаются из таблицы. -При использовании PREWHERE, из таблицы сначала читаются только столбцы, необходимые для выполнения PREWHERE. Затем читаются остальные столбцы, нужные для выполнения запроса, но из них только те блоки, в которых выражение в PREWHERE истинное. - -PREWHERE имеет смысл использовать, если есть условия фильтрации, не подходящие под индексы, которые использует меньшинство столбцов из тех, что есть в запросе, но достаточно сильно фильтрует данные. Таким образом, сокращается количество читаемых данных. - -Например, полезно писать PREWHERE для запросов, которые вынимают много столбцов, но в которых фильтрация производится лишь по нескольким столбцам. - -PREWHERE поддерживается только таблицами семейства `*MergeTree`. - -В запросе могут быть одновременно указаны секции PREWHERE и WHERE. В этом случае, PREWHERE идёт перед WHERE. - -Следует иметь ввиду, что указывать в PREWHERE только столбцы, по которым существует индекс, имеет мало смысла, так как при использовании индекса и так читаются лишь блоки данных, соответствующие индексу. - -Если настройка optimize_move_to_prewhere выставлена в 1, то при отсутствии PREWHERE, система будет автоматически переносить части выражений из WHERE в PREWHERE согласно некоторой эвристике. - -### Секция GROUP BY - -Это одна из наиболее важных частей СУБД. - -Секция GROUP BY, если есть, должна содержать список выражений. Каждое выражение далее будем называть "ключом". -При этом, все выражения в секциях SELECT, HAVING, ORDER BY, должны вычисляться из ключей или из агрегатных функций. То есть, каждый выбираемый из таблицы столбец, должен использоваться либо в ключах, либо внутри агрегатных функций. - -Если запрос содержит столбцы таблицы только внутри агрегатных функций, то секция GROUP BY может не указываться, и подразумевается агрегация по пустому набору ключей. - -Пример: - -```sql -SELECT - count(), - median(FetchTiming > 60 ? 60 : FetchTiming), - count() - sum(Refresh) -FROM hits -``` - -Но, в отличие от стандартного SQL, если в таблице нет строк (вообще нет или после фильтрации с помощью WHERE), в качестве результата возвращается пустой результат, а не результат из одной строки, содержащий "начальные" значения агрегатных функций. - -В отличие от MySQL (и в соответствии со стандартом SQL), вы не можете получить какое-нибудь значение некоторого столбца, не входящего в ключ или агрегатную функцию (за исключением константных выражений). Для обхода этого вы можете воспользоваться агрегатной функцией any (получить первое попавшееся значение) или min/max. - -Пример: - -```sql -SELECT - domainWithoutWWW(URL) AS domain, - count(), - any(Title) AS title -- getting the first occurred page header for each domain. -FROM hits -GROUP BY domain -``` - -GROUP BY вычисляет для каждого встретившегося различного значения ключей, набор значений агрегатных функций. - -Не поддерживается GROUP BY по столбцам-массивам. - -Не поддерживается указание констант в качестве аргументов агрегатных функций. Пример: sum(1). Вместо этого, вы можете избавиться от констант. Пример: `count()`. - -#### Модификатор WITH TOTALS - -Если указан модификатор WITH TOTALS, то будет посчитана ещё одна строчка, в которой в столбцах-ключах будут содержаться значения по умолчанию (нули, пустые строки), а в столбцах агрегатных функций - значения, посчитанные по всем строкам ("тотальные" значения). - -Эта дополнительная строчка выводится в форматах JSON\*, TabSeparated\*, Pretty\* отдельно от остальных строчек. В остальных форматах эта строчка не выводится. - -В форматах JSON\* строчка выводится отдельным полем totals. В форматах TabSeparated\* строчка выводится после основного результата, и перед ней (после остальных данных) вставляется пустая строка. В форматах Pretty\* строчка выводится отдельной табличкой после основного результата. - -`WITH TOTALS` может выполняться по-разному при наличии HAVING. Поведение зависит от настройки totals_mode. -По умолчанию `totals_mode = 'before_having'`. В этом случае totals считается по всем строчкам, включая непрошедших через HAVING и max_rows_to_group_by. - -Остальные варианты учитывают в totals только строчки, прошедшие через HAVING, и имеют разное поведение при наличии настройки `max_rows_to_group_by` и `group_by_overflow_mode = 'any'`. - -`after_having_exclusive` - не учитывать строчки, не прошедшие `max_rows_to_group_by`. То есть в totals попадёт меньше или столько же строчек, чем если бы `max_rows_to_group_by` не было. - -`after_having_inclusive` - учитывать в totals все строчки, не прошедшие max_rows_to_group_by. То есть в totals попадёт больше или столько же строчек, чем если бы `max_rows_to_group_by` не было. - -`after_having_auto` - считать долю строчек, прошедших через HAVING. Если она больше некоторого значения (по умолчанию - 50%), то включить все строчки, не прошедшие max_rows_to_group_by в totals, иначе - не включить. - -`totals_auto_threshold` - по умолчанию 0.5. Коэффициент для работы `after_having_auto`. - -Если `max_rows_to_group_by` и `group_by_overflow_mode = 'any'` не используются, то все варианты вида `after_having` не отличаются, и вы можете использовать любой из них, например, `after_having_auto`. - -Вы можете использовать WITH TOTALS в подзапросах, включая подзапросы в секции JOIN (в этом случае соответствующие тотальные значения будут соединены). - -#### GROUP BY во внешней памяти - -Существует возможность включить сброс временных данных на диск для ограничения потребления оперативной памяти при GROUP BY. -Настройка `max_bytes_before_external_group_by` - потребление оперативки, при котором временные данные GROUP BY сбрасываются в файловую систему. Если равно 0 (по умолчанию) - значит выключено. - -При использовании `max_bytes_before_external_group_by` рекомендуется выставить max_memory_usage примерно в два раза больше. Это следует сделать, потому что агрегация выполняется в две стадии: чтение и формирование промежуточных данных (1) и слияние промежуточных данных (2). Сброс данных на файловую систему может производиться только на стадии 1. Если сброса временных данных не было, то на стадии 2 может потребляться до такого же объёма памяти, как на стадии 1. - -Например, если у вас `max_memory_usage` было выставлено в 10000000000, и вы хотите использовать внешнюю агрегацию, то имеет смысл выставить `max_bytes_before_external_group_by` в 10000000000, а max_memory_usage в 20000000000. При срабатывании внешней агрегации (если был хотя бы один сброс временных данных в файловую систему) максимальное потребление оперативки будет лишь чуть-чуть больше `max_bytes_before_external_group_by`. - -При распределённой обработке запроса внешняя агрегация производится на удалённых серверах. Для того чтобы на сервере-инициаторе запроса использовалось немного оперативки, нужно выставить настройку `distributed_aggregation_memory_efficient` в 1. - -При слиянии данных, сброшенных на диск, а также при слиянии результатов с удалённых серверов, при включенной настройке `distributed_aggregation_memory_efficient`, потребляется до 1/256 \* количество потоков от общего объёма оперативки. - -При включенной внешней агрегации, если данных было меньше `max_bytes_before_external_group_by` (то есть сброса данных не было), то запрос работает так же быстро, как без внешней агрегации. Если же какие-то временные данные были сброшены, то время выполнения будет в несколько раз больше (примерно в три раза). - -Если после GROUP BY у вас есть ORDER BY с небольшим LIMIT, то на ORDER BY не будет тратиться существенного количества оперативки. -Но если есть ORDER BY без LIMIT, то не забудьте включить внешнюю сортировку (`max_bytes_before_external_sort`). - -### Секция LIMIT N BY - -LIMIT N BY COLUMNS выбирает топ N строк для каждой группы COLUMNS. LIMIT N BY не связан с LIMIT и они могут использоваться в одном запросе. Ключ для LIMIT N BY может содержать произвольное число колонок или выражений. - -Пример: - -```sql -SELECT - domainWithoutWWW(URL) AS domain, - domainWithoutWWW(REFERRER_URL) AS referrer, - device_type, - count() cnt -FROM hits -GROUP BY domain, referrer, device_type -ORDER BY cnt DESC -LIMIT 5 BY domain, device_type -LIMIT 100 -``` - -Запрос выберет топ 5 рефереров для каждой пары `domain, device_type`, но не более 100 строк (`LIMIT n BY + LIMIT`). - -### Секция HAVING - -Позволяет отфильтровать результат, полученный после GROUP BY, аналогично секции WHERE. -WHERE и HAVING отличаются тем, что WHERE выполняется до агрегации (GROUP BY), а HAVING - после. -Если агрегации не производится, то HAVING использовать нельзя. - - - -### Секция ORDER BY - -Секция ORDER BY содержит список выражений, к каждому из которых также может быть приписано DESC или ASC (направление сортировки). Если ничего не приписано - это аналогично приписыванию ASC. ASC - сортировка по возрастанию, DESC - сортировка по убыванию. Обозначение направления сортировки действует на одно выражение, а не на весь список. Пример: `ORDER BY Visits DESC, SearchPhrase` - -Для сортировки по значениям типа String есть возможность указать collation (сравнение). Пример: `ORDER BY SearchPhrase COLLATE 'tr'` - для сортировки по поисковой фразе, по возрастанию, с учётом турецкого алфавита, регистронезависимо, при допущении, что строки в кодировке UTF-8. COLLATE может быть указан или не указан для каждого выражения в ORDER BY независимо. Если есть ASC или DESC, то COLLATE указывается после них. При использовании COLLATE сортировка всегда регистронезависима. - -Рекомендуется использовать COLLATE только для окончательной сортировки небольшого количества строк, так как производительность сортировки с указанием COLLATE меньше, чем обычной сортировки по байтам. - -Строки, для которых список выражений, по которым производится сортировка, принимает одинаковые значения, выводятся в произвольном порядке, который может быть также недетерминированным (каждый раз разным). -Если секция ORDER BY отсутствует, то, аналогично, порядок, в котором идут строки, не определён, и может быть недетерминированным. - -При сортировке чисел с плавающей запятой, NaN-ы идут отдельно от остальных значений. Вне зависимости от порядка сортировки, NaN-ы помещаются в конец. То есть, при сортировке по возрастанию, они как будто больше всех чисел, а при сортировке по убыванию - как будто меньше всех. - -Если кроме 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 оперативки, и вам нужно выполнить один запрос, то выставите max_memory_usage в 100 GB, а max_bytes_before_external_sort в 80 GB. - -Внешняя сортировка работает существенно менее эффективно, чем сортировка в оперативке. - -### Секция SELECT - -После вычислений, соответствующих всем перечисленным выше секциям, производится вычисление выражений, указанных в секции SELECT. -Вернее, вычисляются выражения, стоящие над агрегатными функциями, если есть агрегатные функции. -Сами агрегатные функции и то, что под ними, вычисляются при агрегации (GROUP BY). -Эти выражения работают так, как будто применяются к отдельным строкам результата. - -### Секция DISTINCT - -Если указано DISTINCT, то из всех множеств полностью совпадающих строк результата, будет оставляться только одна строка. -Результат выполнения будет таким же, как если указано GROUP BY по всем указанным полям в SELECT-е и не указаны агрегатные функции. Но имеется несколько отличий от GROUP BY: - -- DISTINCT может применяться совместно с GROUP BY; -- при отсутствии ORDER BY и наличии LIMIT, запрос прекратит выполнение сразу после того, как будет прочитано необходимое количество различных строк - в этом случае использование DISTINCT существенно более оптимально; -- блоки данных будут выдаваться по мере их обработки, не дожидаясь выполнения всего запроса. - -DISTINCT не поддерживается, если в SELECT-е присутствует хотя бы один столбец типа массив. - -### Секция LIMIT - -LIMIT m позволяет выбрать из результата первые m строк. -LIMIT n, m позволяет выбрать из результата первые m строк после пропуска первых n строк. - -n и m должны быть неотрицательными целыми числами. - -При отсутствии секции ORDER BY, однозначно сортирующей результат, результат может быть произвольным и может являться недетерминированным. - -### Секция UNION ALL - -Произвольное количество запросов может быть объединено с помощью UNION ALL. Пример: - -```sql -SELECT CounterID, 1 AS table, toInt64(count()) AS c - FROM test.hits - GROUP BY CounterID - -UNION ALL - -SELECT CounterID, 2 AS table, sum(Sign) AS c - FROM test.visits - GROUP BY CounterID - HAVING c > 0 -``` - -Поддерживается только UNION ALL. Обычный UNION (UNION DISTINCT) не поддерживается. Если вам нужен UNION DISTINCT, то вы можете написать SELECT DISTINCT из подзапроса, содержащего UNION ALL. - -Запросы - части UNION ALL могут выполняться параллельно, и их результаты могут возвращаться вперемешку. - -Структура результатов (количество и типы столбцов) у запросов должна совпадать. Но имена столбцов могут отличаться. В этом случае, имена столбцов для общего результата будут взяты из первого запроса. - -Запросы - части UNION ALL нельзя заключить в скобки. ORDER BY и LIMIT применяются к отдельным запросам, а не к общему результату. Если вам нужно применить какое-либо преобразование к общему результату, то вы можете разместить все запросы с UNION ALL в подзапросе в секции FROM. - -### Секция INTO OUTFILE - -При указании `INTO OUTFILE filename` (где filename - строковый литерал), результат запроса будет сохранён в файл filename. -В отличие от MySQL, файл создаётся на стороне клиента. Если файл с таким именем уже существует, это приведёт к ошибке. -Функциональность доступна в клиенте командной строки и clickhouse-local (попытка выполнить запрос с INTO OUTFILE через HTTP интерфейс приведёт к ошибке). - -Формат вывода по умолчанию - TabSeparated, как и в неинтерактивном режиме клиента командной строки. - -### Секция FORMAT - -При указании FORMAT format вы можете получить данные в любом указанном формате. -Это может использоваться для удобства или для создания дампов. -Подробнее смотрите раздел "Форматы". -Если секция FORMAT отсутствует, то используется формат по умолчанию, который зависит от используемого интерфейса для доступа к БД и от настроек. Для HTTP интерфейса, а также для клиента командной строки, используемого в batch-режиме, по умолчанию используется формат TabSeparated. Для клиента командной строки, используемого в интерактивном режиме, по умолчанию используется формат PrettyCompact (прикольные таблички, компактные). - -При использовании клиента командной строки данные на клиент передаются во внутреннем эффективном формате. При этом клиент самостоятельно интерпретирует секцию FORMAT запроса и форматирует данные на своей стороне (снимая нагрузку на сеть и сервер). - -### Операторы IN - -Операторы `IN`, `NOT IN`, `GLOBAL IN`, `GLOBAL NOT IN` рассматриваются отдельно, так как их функциональность достаточно богатая. - -В качестве левой части оператора, может присутствовать как один столбец, так и кортеж. - -Примеры: - -```sql -SELECT UserID IN (123, 456) FROM ... -SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ... -``` - -Если слева стоит один столбец, входящий в индекс, а справа - множество констант, то при выполнении запроса, система воспользуется индексом. - -Не перечисляйте слишком большое количество значений (миллионы) явно. Если множество большое - лучше загрузить его во временную таблицу (например, смотрите раздел "Внешние данные для обработки запроса"), и затем воспользоваться подзапросом. - -В качестве правой части оператора может быть множество константных выражений, множество кортежей с константными выражениями (показано в примерах выше), а также имя таблицы или подзапрос SELECT в скобках. - -Если в качестве правой части оператора указано имя таблицы (например, `UserID IN users`), то это эквивалентно подзапросу `UserID IN (SELECT * FROM users)`. Это используется при работе с внешними данными, отправляемым вместе с запросом. Например, вместе с запросом может быть отправлено множество идентификаторов посетителей, загруженное во временную таблицу users, по которому следует выполнить фильтрацию. - -Если качестве правой части оператора, указано имя таблицы, имеющий движок Set (подготовленное множество, постоянно находящееся в оперативке), то множество не будет создаваться заново при каждом запросе. - -В подзапросе может быть указано более одного столбца для фильтрации кортежей. -Пример: - -```sql -SELECT (CounterID, UserID) IN (SELECT CounterID, UserID FROM ...) FROM ... -``` - -Типы столбцов слева и справа оператора IN, должны совпадать. - -Оператор IN и подзапрос могут встречаться в любой части запроса, в том числе в агрегатных и лямбда функциях. -Пример: - -```sql -SELECT - EventDate, - avg(UserID IN - ( - SELECT UserID - FROM test.hits - WHERE EventDate = toDate('2014-03-17') - )) AS ratio -FROM test.hits -GROUP BY EventDate -ORDER BY EventDate ASC -``` - -```text -┌──EventDate─┬────ratio─┐ -│ 2014-03-17 │ 1 │ -│ 2014-03-18 │ 0.807696 │ -│ 2014-03-19 │ 0.755406 │ -│ 2014-03-20 │ 0.723218 │ -│ 2014-03-21 │ 0.697021 │ -│ 2014-03-22 │ 0.647851 │ -│ 2014-03-23 │ 0.648416 │ -└────────────┴──────────┘ -``` - -за каждый день после 17 марта считаем долю хитов, сделанных посетителями, которые заходили на сайт 17 марта. -Подзапрос в секции IN на одном сервере всегда выполняется только один раз. Зависимых подзапросов не существует. - - - -#### Распределённые подзапросы - -Существует два варианта IN-ов с подзапросами (аналогично для JOIN-ов): обычный `IN` / `JOIN` и `GLOBAL IN` / `GLOBAL JOIN`. Они отличаются способом выполнения при распределённой обработке запроса. - -
- -Помните, что алгоритмы, описанные ниже, могут работать иначе в зависимости от [настройки](../operations/settings/settings.md#settings-distributed_product_mode) `distributed_product_mode`. - -
- -При использовании обычного IN-а, запрос отправляется на удалённые серверы, и на каждом из них выполняются подзапросы в секциях `IN` / `JOIN`. - -При использовании `GLOBAL IN` / `GLOBAL JOIN-а`, сначала выполняются все подзапросы для `GLOBAL IN` / `GLOBAL JOIN-ов`, и результаты складываются во временные таблицы. Затем эти временные таблицы передаются на каждый удалённый сервер, и на них выполняются запросы, с использованием этих переданных временных данных. - -Если запрос не распределённый, используйте обычный `IN` / `JOIN`. - -Следует быть внимательным при использовании подзапросов в секции `IN` / `JOIN` в случае распределённой обработки запроса. - -Рассмотрим это на примерах. Пусть на каждом сервере кластера есть обычная таблица **local_table**. Пусть также есть таблица **distributed_table** типа **Distributed**, которая смотрит на все серверы кластера. - -При запросе к распределённой таблице **distributed_table**, запрос будет отправлен на все удалённые серверы, и на них будет выполнен с использованием таблицы **local_table**. - -Например, запрос - -```sql -SELECT uniq(UserID) FROM distributed_table -``` - -будет отправлен на все удалённые серверы в виде - -```sql -SELECT uniq(UserID) FROM local_table -``` - -, выполнен параллельно на каждом из них до стадии, позволяющей объединить промежуточные результаты; затем промежуточные результаты вернутся на сервер-инициатор запроса, будут на нём объединены, и финальный результат будет отправлен клиенту. - -Теперь рассмотрим запрос с IN-ом: - -```sql -SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) -``` - -- расчёт пересечения аудиторий двух сайтов. - -Этот запрос будет отправлен на все удалённые серверы в виде - -```sql -SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) -``` - -То есть, множество в секции IN будет собрано на каждом сервере независимо, только по тем данным, которые есть локально на каждом из серверов. - -Это будет работать правильно и оптимально, если вы предусмотрели такой случай, и раскладываете данные по серверам кластера таким образом, чтобы данные одного UserID-а лежали только на одном сервере. В таком случае все необходимые данные будут присутствовать на каждом сервере локально. В противном случае результат будет посчитан неточно. Назовём этот вариант запроса "локальный IN". - -Чтобы исправить работу запроса, когда данные размазаны по серверам кластера произвольным образом, можно было бы указать **distributed_table** внутри подзапроса. Запрос будет выглядеть так: - -```sql -SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) -``` - -Этот запрос будет отправлен на все удалённые серверы в виде - -```sql -SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) -``` - -На каждом удалённом сервере начнёт выполняться подзапрос. Так как в подзапросе используется распределённая таблица, то подзапрос будет, на каждом удалённом сервере, снова отправлен на каждый удалённый сервер, в виде - -```sql -SELECT UserID FROM local_table WHERE CounterID = 34 -``` - -Например, если у вас кластер из 100 серверов, то выполнение всего запроса потребует 10 000 элементарных запросов, что, как правило, является неприемлемым. - -В таких случаях всегда следует использовать GLOBAL IN вместо IN. Рассмотрим его работу для запроса - -```sql -SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID GLOBAL IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) -``` - -На сервере-инициаторе запроса будет выполнен подзапрос - -```sql -SELECT UserID FROM distributed_table WHERE CounterID = 34 -``` - -, и результат будет сложен во временную таблицу в оперативке. Затем запрос будет отправлен на каждый удалённый сервер в виде - -```sql -SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID GLOBAL IN _data1 -``` - -, и вместе с запросом, на каждый удалённый сервер будет отправлена временная таблица `_data1` (имя временной таблицы - implementation defined). - -Это гораздо более оптимально, чем при использовании обычного IN. Но при этом, следует помнить о нескольких вещах: - -1. При создании временной таблицы данные не уникализируются. Чтобы уменьшить объём передаваемых по сети данных, укажите в подзапросе DISTINCT (для обычного IN-а этого делать не нужно). -2. Временная таблица будет передана на все удалённые серверы. Передача не учитывает топологию сети. Например, если 10 удалённых серверов расположены в удалённом относительно сервера-инициатора запроса датацентре, то по каналу в удалённый датацентр данные будет переданы 10 раз. Старайтесь не использовать большие множества при использовании GLOBAL IN. -3. При передаче данных на удалённые серверы не настраивается ограничение использования сетевой полосы. Вы можете перегрузить сеть. -4. Старайтесь распределять данные по серверам так, чтобы в GLOBAL IN-ах не было частой необходимости. -5. Если в GLOBAL IN есть частая необходимость, то спланируйте размещение кластера ClickHouse таким образом, чтобы в каждом датацентре была хотя бы одна реплика каждого шарда, и среди них была быстрая сеть - чтобы запрос целиком можно было бы выполнить, передавая данные в пределах одного датацентра. - -В секции `GLOBAL IN` также имеет смысл указывать локальную таблицу - в случае, если эта локальная таблица есть только на сервере-инициаторе запроса, и вы хотите воспользоваться данными из неё на удалённых серверах. - -### Экстремальные значения - -Вы можете получить в дополнение к результату также минимальные и максимальные значения по столбцам результата. Для этого выставите настройку **extremes** в 1. Минимумы и максимумы считаются для числовых типов, дат, дат-с-временем. Для остальных столбцов будут выведены значения по умолчанию. - -Вычисляются дополнительные две строчки - минимумы и максимумы, соответственно. Эти дополнительные две строчки выводятся в форматах JSON\*, TabSeparated\*, Pretty\* отдельно от остальных строчек. В остальных форматах они не выводится. - -В форматах JSON\* экстремальные значения выводятся отдельным полем extremes. В форматах TabSeparated\* строчка выводится после основного результата и после totals, если есть. Перед ней (после остальных данных) вставляется пустая строка. В форматах Pretty\* строчка выводится отдельной табличкой после основного результата и после totals, если есть. - -Экстремальные значения считаются по строчкам, прошедшим через LIMIT. Но при этом, при использовании LIMIT offset, size, строчки до offset учитываются в extremes. В потоковых запросах, в результате может учитываться также небольшое количество строчек, прошедших LIMIT. - -### Замечания - -В секциях `GROUP BY`, `ORDER BY`, в отличие от диалекта MySQL, и в соответствии со стандартным SQL, не поддерживаются позиционные аргументы. -Например, если вы напишите `GROUP BY 1, 2` - то это будет воспринято, как группировка по константам (то есть, агрегация всех строк в одну). - -Вы можете использовать синонимы (алиасы `AS`) в любом месте запроса. - -В любом месте запроса, вместо выражения, может стоять звёздочка. При анализе запроса звёздочка раскрывается в список всех столбцов таблицы (за исключением `MATERIALIZED` и `ALIAS` столбцов). Есть лишь немного случаев, когда оправдано использовать звёздочку: - -- при создании дампа таблицы; -- для таблиц, содержащих всего несколько столбцов - например, системных таблиц; -- для получения информации о том, какие столбцы есть в таблице; в этом случае, укажите `LIMIT 1`. Но лучше используйте запрос `DESC TABLE`; -- при наличии сильной фильтрации по небольшому количеству столбцов с помощью `PREWHERE`; -- в подзапросах (так как из подзапросов выкидываются столбцы, не нужные для внешнего запроса). - -В других случаях использование звёздочки является издевательством над системой, так как вместо преимуществ столбцовой СУБД вы получаете недостатки. То есть использовать звёздочку не рекомендуется. - -## KILL QUERY - -```sql -KILL QUERY - WHERE - [SYNC|ASYNC|TEST] - [FORMAT format] -``` - -Пытается принудительно остановить исполняющиеся в данный момент запросы. -Запросы для принудительной остановки выбираются из таблицы system.processes с помощью условия, указанного в секции `WHERE` запроса `KILL`. - -Примеры: -```sql --- Принудительно останавливает все запросы с указанным query_id: -KILL QUERY WHERE query_id='2-857d-4a57-9ee0-327da5d60a90' - --- Синхронно останавливает все запросы пользователя 'username': -KILL QUERY WHERE user='username' SYNC -``` - -Readonly-пользователи могут останавливать только свои запросы. - -По-умолчанию используется асинхронный вариант запроса (`ASYNC`), который не дожидается подтверждения остановки запросов. - -Синхронный вариант (`SYNC`) ожидает остановки всех запросов и построчно выводит информацию о процессах по ходу их остановки. -Ответ содержит колонку `kill_status`, которая может принимать следующие значения: - -1. 'finished' - запрос был успешно остановлен; -2. 'waiting' - запросу отправлен сигнал завершения, ожидается его остановка; -3. остальные значения описывают причину невозможности остановки запроса. - -Тестовый вариант запроса (`TEST`) только проверяет права пользователя и выводит список запросов для остановки. From 5a6a0ad00a8980b485dd574e75e145235fc6fc85 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 11:36:02 +0300 Subject: [PATCH 031/425] Fix weird translation --- docs/mkdocs_en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 1dd72a2b570..90f55fb7e32 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -11,7 +11,7 @@ pages: - 'Getting started': - 'Deploying and running': 'getting_started/index.md' - - 'Testing data': + - 'Example datasets': - 'OnTime': 'getting_started/example_datasets/ontime.md' - 'New York Taxi data': 'getting_started/example_datasets/nyc_taxi.md' - 'AMPLab Big Data Benchmark': 'getting_started/example_datasets/amplab_benchmark.md' From 129a376c3c37f28351a6ba711312e8fe69beb4cd Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 12:10:11 +0300 Subject: [PATCH 032/425] Fix a bunch of links --- docs/en/data_types/float.md | 2 +- .../en/operations/server_settings/settings.md | 2 +- docs/en/operations/settings/settings.md | 2 +- docs/en/operations/system_tables.md | 2 +- docs/en/operations/table_engines/file.md | 2 +- .../table_engines/materializedview.md | 2 +- .../operations/table_engines/replication.md | 2 +- docs/en/operations/utils/clickhouse-local.md | 2 +- docs/en/query_language/attach_detach.md | 1551 ----------------- docs/en/query_language/index.md | 10 +- docs/ru/data_types/float.md | 2 +- .../ru/operations/server_settings/settings.md | 2 +- docs/ru/operations/settings/settings.md | 2 +- docs/ru/operations/system_tables.md | 2 +- docs/ru/operations/table_engines/file.md | 2 +- .../table_engines/materializedview.md | 2 +- .../operations/table_engines/replication.md | 2 +- docs/ru/operations/utils/clickhouse-local.md | 2 +- docs/ru/query_language/index.md | 10 +- 19 files changed, 26 insertions(+), 1577 deletions(-) delete mode 100644 docs/en/query_language/attach_detach.md diff --git a/docs/en/data_types/float.md b/docs/en/data_types/float.md index 031a7b63436..aa047e305dd 100644 --- a/docs/en/data_types/float.md +++ b/docs/en/data_types/float.md @@ -66,5 +66,5 @@ SELECT 0 / 0 └──────────────┘ ``` -See the rules for ` NaN` sorting in the section [ORDER BY clause](../query_language/queries.md#query_language-queries-order_by). +See the rules for ` NaN` sorting in the section [ORDER BY clause](../query_language/select.md#query_language-queries-order_by). diff --git a/docs/en/operations/server_settings/settings.md b/docs/en/operations/server_settings/settings.md index 63933362472..7745f226128 100644 --- a/docs/en/operations/server_settings/settings.md +++ b/docs/en/operations/server_settings/settings.md @@ -67,7 +67,7 @@ ClickHouse checks ` min_part_size` and ` min_part_size_ratio` and processes th The default database. -To get a list of databases, use the [SHOW DATABASES](../../query_language/queries.md#query_language_queries_show_databases). +To get a list of databases, use the [SHOW DATABASES](../../query_language/misc.md#query_language_queries_show_databases). **Example** diff --git a/docs/en/operations/settings/settings.md b/docs/en/operations/settings/settings.md index 39529fee8c1..25ed20fd5a3 100644 --- a/docs/en/operations/settings/settings.md +++ b/docs/en/operations/settings/settings.md @@ -4,7 +4,7 @@ ## distributed_product_mode -Changes the behavior of [distributed subqueries](../../query_language/queries.md#queries-distributed-subrequests), i.e. in cases when the query contains the product of distributed tables. +Changes the behavior of [distributed subqueries](../../query_language/select.md#queries-distributed-subrequests), i.e. in cases when the query contains the product of distributed tables. ClickHouse applies the configuration if the subqueries on any level have a distributed table that exists on the local server and has more than one shard. diff --git a/docs/en/operations/system_tables.md b/docs/en/operations/system_tables.md index 0f0fe6f05a0..5659700a0b6 100644 --- a/docs/en/operations/system_tables.md +++ b/docs/en/operations/system_tables.md @@ -133,7 +133,7 @@ Each row describes one part of the data. Columns: -- partition (String) – The partition name. It's in YYYYMM format in case of old-style partitioning and is arbitary serialized value in case of custom partitioning. To learn what a partition is, see the description of the [ALTER](../query_language/queries.md#query_language_queries_alter) query. +- partition (String) – The partition name. It's in YYYYMM format in case of old-style partitioning and is arbitary serialized value in case of custom partitioning. To learn what a partition is, see the description of the [ALTER](../query_language/alter.md#query_language_queries_alter) query. - name (String) – Name of the data part. - active (UInt8) – Indicates whether the part is active. If a part is active, it is used in a table; otherwise, it will be deleted. Inactive data parts remain after merging. - marks (UInt64) – The number of marks. To get the approximate number of rows in a data part, multiply ``marks`` by the index granularity (usually 8192). diff --git a/docs/en/operations/table_engines/file.md b/docs/en/operations/table_engines/file.md index 63c575997d2..400601c8d91 100644 --- a/docs/en/operations/table_engines/file.md +++ b/docs/en/operations/table_engines/file.md @@ -22,7 +22,7 @@ ClickHouse does not allow to specify filesystem path for`File`. It will use fold When creating table using `File(Format)` it creates empty subdirectory in that folder. When data is written to that table, it's put into `data.Format` file in that subdirectory. -You may manually create this subfolder and file in server filesystem and then [ATTACH](../../query_language/queries.md#queries-attach) it to table information with matching name, so you can query data from that file. +You may manually create this subfolder and file in server filesystem and then [ATTACH](../../query_language/misc.md#queries-attach) it to table information with matching name, so you can query data from that file.
Be careful with this funcionality, because ClickHouse does not keep track of external changes to such files. The result of simultaneous writes via ClickHouse and outside of ClickHouse is undefined. diff --git a/docs/en/operations/table_engines/materializedview.md b/docs/en/operations/table_engines/materializedview.md index 63e282295ec..5f46f5fe528 100644 --- a/docs/en/operations/table_engines/materializedview.md +++ b/docs/en/operations/table_engines/materializedview.md @@ -1,4 +1,4 @@ # MaterializedView -Used for implementing materialized views (for more information, see the [CREATE TABLE](../../query_language/queries.md#query_language-queries-create_table)) query. For storing data, it uses a different engine that was specified when creating the view. When reading from a table, it just uses this engine. +Used for implementing materialized views (for more information, see the [CREATE TABLE](../../query_language/create.md#query_language-queries-create_table)) query. For storing data, it uses a different engine that was specified when creating the view. When reading from a table, it just uses this engine. diff --git a/docs/en/operations/table_engines/replication.md b/docs/en/operations/table_engines/replication.md index 5ced888b43d..97a1244784c 100644 --- a/docs/en/operations/table_engines/replication.md +++ b/docs/en/operations/table_engines/replication.md @@ -15,7 +15,7 @@ Replication works at the level of an individual table, not the entire server. A Replication does not depend on sharding. Each shard has its own independent replication. -Compressed data is replicated for `INSERT` and `ALTER` queries (see the description of the [ALTER](../../query_language/queries.md#query_language_queries_alter) query). +Compressed data is replicated for `INSERT` and `ALTER` queries (see the description of the [ALTER](../../query_language/alter.md#query_language_queries_alter) query). `CREATE`, `DROP`, `ATTACH`, `DETACH` and `RENAME` queries are executed on a single server and are not replicated: diff --git a/docs/en/operations/utils/clickhouse-local.md b/docs/en/operations/utils/clickhouse-local.md index dadc02f9d3e..1960263caaa 100644 --- a/docs/en/operations/utils/clickhouse-local.md +++ b/docs/en/operations/utils/clickhouse-local.md @@ -4,7 +4,7 @@ The `clickhouse-local` program enables you to perform fast processing on local files, without having to deploy and configure the ClickHouse server. -Accepts data that represent tables and queries them using [ClickHouse SQL dialect](../../query_language/queries.md#queries). +Accepts data that represent tables and queries them using [ClickHouse SQL dialect](../../query_language/index.md#queries). `clickhouse-local` uses the same core as ClickHouse server, so it supports most of the features and the same set of formats and table engines. diff --git a/docs/en/query_language/attach_detach.md b/docs/en/query_language/attach_detach.md deleted file mode 100644 index a7f7a7cbc32..00000000000 --- a/docs/en/query_language/attach_detach.md +++ /dev/null @@ -1,1551 +0,0 @@ -# Queries - -## CREATE DATABASE - -Creating db_name databases - -```sql -CREATE DATABASE [IF NOT EXISTS] db_name -``` - -`A database` is just a directory for tables. -If `IF NOT EXISTS` is included, the query won't return an error if the database already exists. - - - -## CREATE TABLE - -The `CREATE TABLE` query can have several forms. - -```sql -CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name [ON CLUSTER cluster] -( - name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], - name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2], - ... -) ENGINE = engine -``` - -Creates a table named 'name' in the 'db' database or the current database if 'db' is not set, with the structure specified in brackets and the 'engine' engine. -The structure of the table is a list of column descriptions. If indexes are supported by the engine, they are indicated as parameters for the table engine. - -A column description is `name type` in the simplest case. Example: `RegionID UInt32`. -Expressions can also be defined for default values (see below). - -```sql -CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine] -``` - -Creates a table with the same structure as another table. You can specify a different engine for the table. If the engine is not specified, the same engine will be used as for the `db2.name2` table. - -```sql -CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... -``` - -Creates a table with a structure like the result of the `SELECT` query, with the 'engine' engine, and fills it with data from SELECT. - -In all cases, if `IF NOT EXISTS` is specified, the query won't return an error if the table already exists. In this case, the query won't do anything. - -### Default values - -The column description can specify an expression for a default value, in one of the following ways:`DEFAULT expr`, `MATERIALIZED expr`, `ALIAS expr`. -Example: `URLDomain String DEFAULT domain(URL)`. - -If an expression for the default value is not defined, the default values will be set to zeros for numbers, empty strings for strings, empty arrays for arrays, and `0000-00-00` for dates or `0000-00-00 00:00:00` for dates with time. NULLs are not supported. - -If the default expression is defined, the column type is optional. If there isn't an explicitly defined type, the default expression type is used. Example: `EventDate DEFAULT toDate(EventTime)` – the 'Date' type will be used for the 'EventDate' column. - -If the data type and default expression are defined explicitly, this expression will be cast to the specified type using type casting functions. Example: `Hits UInt32 DEFAULT 0` means the same thing as `Hits UInt32 DEFAULT toUInt32(0)`. - -Default expressions may be defined as an arbitrary expression from table constants and columns. When creating and changing the table structure, it checks that expressions don't contain loops. For INSERT, it checks that expressions are resolvable – that all columns they can be calculated from have been passed. - -`DEFAULT expr` - -Normal default value. If the INSERT query doesn't specify the corresponding column, it will be filled in by computing the corresponding expression. - -`MATERIALIZED expr` - -Materialized expression. Such a column can't be specified for INSERT, because it is always calculated. -For an INSERT without a list of columns, these columns are not considered. -In addition, this column is not substituted when using an asterisk in a SELECT query. This is to preserve the invariant that the dump obtained using `SELECT *` can be inserted back into the table using INSERT without specifying the list of columns. - -`ALIAS expr` - -Synonym. Such a column isn't stored in the table at all. -Its values can't be inserted in a table, and it is not substituted when using an asterisk in a SELECT query. -It can be used in SELECTs if the alias is expanded during query parsing. - -When using the ALTER query to add new columns, old data for these columns is not written. Instead, when reading old data that does not have values for the new columns, expressions are computed on the fly by default. However, if running the expressions requires different columns that are not indicated in the query, these columns will additionally be read, but only for the blocks of data that need it. - -If you add a new column to a table but later change its default expression, the values used for old data will change (for data where values were not stored on the disk). Note that when running background merges, data for columns that are missing in one of the merging parts is written to the merged part. - -It is not possible to set default values for elements in nested data structures. - -### Temporary tables - -In all cases, if `TEMPORARY` is specified, a temporary table will be created. Temporary tables have the following characteristics: - -- Temporary tables disappear when the session ends, including if the connection is lost. -- A temporary table is created with the Memory engine. The other table engines are not supported. -- The DB can't be specified for a temporary table. It is created outside of databases. -- If a temporary table has the same name as another one and a query specifies the table name without specifying the DB, the temporary table will be used. -- For distributed query processing, temporary tables used in a query are passed to remote servers. - -In most cases, temporary tables are not created manually, but when using external data for a query, or for distributed `(GLOBAL) IN`. For more information, see the appropriate sections - -Distributed DDL queries (ON CLUSTER clause) ----------------------------------------------- - -The `CREATE`, `DROP`, `ALTER`, and `RENAME` queries support distributed execution on a cluster. -For example, the following query creates the `all_hits` `Distributed` table on each host in `cluster`: - -```sql -CREATE TABLE IF NOT EXISTS all_hits ON CLUSTER cluster (p Date, i Int32) ENGINE = Distributed(cluster, default, hits) -``` - -In order to run these queries correctly, each host must have the same cluster definition (to simplify syncing configs, you can use substitutions from ZooKeeper). They must also connect to the ZooKeeper servers. -The local version of the query will eventually be implemented on each host in the cluster, even if some hosts are currently not available. The order for executing queries within a single host is guaranteed. -` ALTER` queries are not yet supported for replicated tables. - -## CREATE VIEW - -```sql -CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT ... -``` - -Creates a view. There are two types of views: normal and MATERIALIZED. - -When creating a materialized view, you must specify ENGINE – the table engine for storing data. - -A materialized view works as follows: when inserting data to the table specified in SELECT, part of the inserted data is converted by this SELECT query, and the result is inserted in the view. - -Normal views don't store any data, but just perform a read from another table. In other words, a normal view is nothing more than a saved query. When reading from a view, this saved query is used as a subquery in the FROM clause. - -As an example, assume you've created a view: - -```sql -CREATE VIEW view AS SELECT ... -``` - -and written a query: - -```sql -SELECT a, b, c FROM view -``` - -This query is fully equivalent to using the subquery: - -```sql -SELECT a, b, c FROM (SELECT ...) -``` - -Materialized views store data transformed by the corresponding SELECT query. - -When creating a materialized view, you must specify ENGINE – the table engine for storing data. - -A materialized view is arranged as follows: when inserting data to the table specified in SELECT, part of the inserted data is converted by this SELECT query, and the result is inserted in the view. - -If you specify POPULATE, the existing table data is inserted in the view when creating it, as if making a `CREATE TABLE ... AS SELECT ...` . Otherwise, the query contains only the data inserted in the table after creating the view. We don't recommend using POPULATE, since data inserted in the table during the view creation will not be inserted in it. - -A `SELECT` query can contain `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`... Note that the corresponding conversions are performed independently on each block of inserted data. For example, if `GROUP BY` is set, data is aggregated during insertion, but only within a single packet of inserted data. The data won't be further aggregated. The exception is when using an ENGINE that independently performs data aggregation, such as `SummingMergeTree`. - -The execution of `ALTER` queries on materialized views has not been fully developed, so they might be inconvenient. If the materialized view uses the construction ``TO [db.]name``, you can ``DETACH`` the view, run ``ALTER`` for the target table, and then ``ATTACH`` the previously detached (``DETACH``) view. - -Views look the same as normal tables. For example, they are listed in the result of the `SHOW TABLES` query. - -There isn't a separate query for deleting views. To delete a view, use `DROP TABLE`. - -## ATTACH - -This query is exactly the same as `CREATE`, but - -- instead of the word `CREATE` it uses the word `ATTACH`. -- The query doesn't create data on the disk, but assumes that data is already in the appropriate places, and just adds information about the table to the server. -After executing an ATTACH query, the server will know about the existence of the table. - -If the table was previously detached (``DETACH``), meaning that its structure is known, you can use shorthand without defining the structure. - -```sql -ATTACH TABLE [IF NOT EXISTS] [db.]name -``` - -This query is used when starting the server. The server stores table metadata as files with `ATTACH` queries, which it simply runs at launch (with the exception of system tables, which are explicitly created on the server). - -## DROP - -This query has two types: `DROP DATABASE` and `DROP TABLE`. - -```sql -DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster] -``` - -Deletes all tables inside the 'db' database, then deletes the 'db' database itself. -If `IF EXISTS` is specified, it doesn't return an error if the database doesn't exist. - -```sql -DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster] -``` - -Deletes the table. -If `IF EXISTS` is specified, it doesn't return an error if the table doesn't exist or the database doesn't exist. - -## DETACH - -Deletes information about the 'name' table from the server. The server stops knowing about the table's existence. - -```sql -DETACH TABLE [IF EXISTS] [db.]name -``` - -This does not delete the table's data or metadata. On the next server launch, the server will read the metadata and find out about the table again. -Similarly, a "detached" table can be re-attached using the `ATTACH` query (with the exception of system tables, which do not have metadata stored for them). - -There is no `DETACH DATABASE` query. - -## RENAME - -Renames one or more tables. - -```sql -RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... [ON CLUSTER cluster] -``` - -All tables are renamed under global locking. Renaming tables is a light operation. If you indicated another database after TO, the table will be moved to this database. However, the directories with databases must reside in the same file system (otherwise, an error is returned). - - - -## ALTER - -The `ALTER` query is only supported for `*MergeTree` tables, as well as `Merge`and`Distributed`. The query has several variations. - -### Column manipulations - -Changing the table structure. - -```sql -ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|MODIFY COLUMN ... -``` - -In the query, specify a list of one or more comma-separated actions. -Each action is an operation on a column. - -The following actions are supported: - -```sql -ADD COLUMN name [type] [default_expr] [AFTER name_after] -``` - -Adds a new column to the table with the specified name, type, and `default_expr` (see the section "Default expressions"). If you specify `AFTER name_after` (the name of another column), the column is added after the specified one in the list of table columns. Otherwise, the column is added to the end of the table. Note that there is no way to add a column to the beginning of a table. For a chain of actions, 'name_after' can be the name of a column that is added in one of the previous actions. - -Adding a column just changes the table structure, without performing any actions with data. The data doesn't appear on the disk after ALTER. If the data is missing for a column when reading from the table, it is filled in with default values (by performing the default expression if there is one, or using zeros or empty strings). If the data is missing for a column when reading from the table, it is filled in with default values (by performing the default expression if there is one, or using zeros or empty strings). The column appears on the disk after merging data parts (see MergeTree). - -This approach allows us to complete the ALTER query instantly, without increasing the volume of old data. - -```sql -DROP COLUMN name -``` - -Deletes the column with the name 'name'. -Deletes data from the file system. Since this deletes entire files, the query is completed almost instantly. - -```sql -MODIFY COLUMN name [type] [default_expr] -``` - -Changes the 'name' column's type to 'type' and/or the default expression to 'default_expr'. When changing the type, values are converted as if the 'toType' function were applied to them. - -If only the default expression is changed, the query doesn't do anything complex, and is completed almost instantly. - -Changing the column type is the only complex action – it changes the contents of files with data. For large tables, this may take a long time. - -There are several processing stages: - -- Preparing temporary (new) files with modified data. -- Renaming old files. -- Renaming the temporary (new) files to the old names. -- Deleting the old files. - -Only the first stage takes time. If there is a failure at this stage, the data is not changed. -If there is a failure during one of the successive stages, data can be restored manually. The exception is if the old files were deleted from the file system but the data for the new files did not get written to the disk and was lost. - -There is no support for changing the column type in arrays and nested data structures. - -The `ALTER` query lets you create and delete separate elements (columns) in nested data structures, but not whole nested data structures. To add a nested data structure, you can add columns with a name like `name.nested_name` and the type `Array(T)`. A nested data structure is equivalent to multiple array columns with a name that has the same prefix before the dot. - -There is no support for deleting columns in the primary key or the sampling key (columns that are in the `ENGINE` expression). Changing the type for columns that are included in the primary key is only possible if this change does not cause the data to be modified (for example, it is allowed to add values to an Enum or change a type with `DateTime` to `UInt32`). - -If the `ALTER` query is not sufficient for making the table changes you need, you can create a new table, copy the data to it using the `INSERT SELECT` query, then switch the tables using the `RENAME` query and delete the old table. - -The `ALTER` query blocks all reads and writes for the table. In other words, if a long `SELECT` is running at the time of the `ALTER` query, the `ALTER` query will wait for it to complete. At the same time, all new queries to the same table will wait while this `ALTER` is running. - -For tables that don't store data themselves (such as `Merge` and `Distributed`), `ALTER` just changes the table structure, and does not change the structure of subordinate tables. For example, when running ALTER for a `Distributed` table, you will also need to run `ALTER` for the tables on all remote servers. - -The `ALTER` query for changing columns is replicated. The instructions are saved in ZooKeeper, then each replica applies them. All `ALTER` queries are run in the same order. The query waits for the appropriate actions to be completed on the other replicas. However, a query to change columns in a replicated table can be interrupted, and all actions will be performed asynchronously. - -### Manipulations with partitions and parts - -It only works for tables in the `MergeTree` family. The following operations are available: - -- `DETACH PARTITION` – Move a partition to the 'detached' directory and forget it. -- `DROP PARTITION` – Delete a partition. -- `ATTACH PART|PARTITION` – Add a new part or partition from the `detached` directory to the table. -- `FREEZE PARTITION` – Create a backup of a partition. -- `FETCH PARTITION` – Download a partition from another server. - -Each type of query is covered separately below. - -A partition in a table is data for a single calendar month. This is determined by the values of the date key specified in the table engine parameters. Each month's data is stored separately in order to simplify manipulations with this data. - -A "part" in the table is part of the data from a single partition, sorted by the primary key. - -You can use the `system.parts` table to view the set of table parts and partitions: - -```sql -SELECT * FROM system.parts WHERE active -``` - -`active` – Only count active parts. Inactive parts are, for example, source parts remaining after merging to a larger part – these parts are deleted approximately 10 minutes after merging. - -Another way to view a set of parts and partitions is to go into the directory with table data. -Data directory: `/var/lib/clickhouse/data/database/table/`,where `/var/lib/clickhouse/` is the path to the ClickHouse data, 'database' is the database name, and 'table' is the table name. Example: - -```bash -$ ls -l /var/lib/clickhouse/data/test/visits/ -total 48 -drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_2_2_0 -drwxrwxrwx 2 clickhouse clickhouse 20480 May 5 02:58 20140317_20140323_4_4_0 -drwxrwxrwx 2 clickhouse clickhouse 4096 May 5 02:55 detached --rw-rw-rw- 1 clickhouse clickhouse 2 May 5 02:58 increment.txt -``` - -Here, `20140317_20140323_2_2_0` and ` 20140317_20140323_4_4_0` are the directories of data parts. - -Let's break down the name of the first part: `20140317_20140323_2_2_0`. - -- `20140317` is the minimum date of the data in the chunk. -- `20140323` is the maximum date of the data in the chunk. -- `2` is the minimum number of the data block. -- `2` is the maximum number of the data block. -- `0` is the chunk level (the depth of the merge tree it is formed from). - -Each piece relates to a single partition and contains data for just one month. -`201403` is the name of the partition. A partition is a set of parts for a single month. - -On an operating server, you can't manually change the set of parts or their data on the file system, since the server won't know about it. -For non-replicated tables, you can do this when the server is stopped, but we don't recommended it. -For replicated tables, the set of parts can't be changed in any case. - -The `detached` directory contains parts that are not used by the server - detached from the table using the `ALTER ... DETACH` query. Parts that are damaged are also moved to this directory, instead of deleting them. You can add, delete, or modify the data in the 'detached' directory at any time – the server won't know about this until you make the `ALTER TABLE ... ATTACH` query. - -```sql -ALTER TABLE [db.]table DETACH PARTITION 'name' -``` - -Move all data for partitions named 'name' to the 'detached' directory and forget about them. -The partition name is specified in YYYYMM format. It can be indicated in single quotes or without them. - -After the query is executed, you can do whatever you want with the data in the 'detached' directory — delete it from the file system, or just leave it. - -The query is replicated – data will be moved to the 'detached' directory and forgotten on all replicas. The query can only be sent to a leader replica. To find out if a replica is a leader, perform SELECT to the 'system.replicas' system table. Alternatively, it is easier to make a query on all replicas, and all except one will throw an exception. - -```sql -ALTER TABLE [db.]table DROP PARTITION 'name' -``` - -The same as the `DETACH` operation. Deletes data from the table. Data parts will be tagged as inactive and will be completely deleted in approximately 10 minutes. The query is replicated – data will be deleted on all replicas. - -```sql -ALTER TABLE [db.]table ATTACH PARTITION|PART 'name' -``` - -Adds data to the table from the 'detached' directory. - -It is possible to add data for an entire partition or a separate part. For a part, specify the full name of the part in single quotes. - -The query is replicated. Each replica checks whether there is data in the 'detached' directory. If there is data, it checks the integrity, verifies that it matches the data on the server that initiated the query, and then adds it if everything is correct. If not, it downloads data from the query requestor replica, or from another replica where the data has already been added. - -So you can put data in the 'detached' directory on one replica, and use the ALTER ... ATTACH query to add it to the table on all replicas. - -```sql -ALTER TABLE [db.]table FREEZE PARTITION 'name' -``` - -Creates a local backup of one or multiple partitions. The name can be the full name of the partition (for example, 201403), or its prefix (for example, 2014): then the backup will be created for all the corresponding partitions. - -The query does the following: for a data snapshot at the time of execution, it creates hardlinks to table data in the directory `/var/lib/clickhouse/shadow/N/...` - -`/var/lib/clickhouse/` is the working ClickHouse directory from the config. -`N` is the incremental number of the backup. - -The same structure of directories is created inside the backup as inside `/var/lib/clickhouse/`. -It also performs 'chmod' for all files, forbidding writes to them. - -The backup is created almost instantly (but first it waits for current queries to the corresponding table to finish running). At first, the backup doesn't take any space on the disk. As the system works, the backup can take disk space, as data is modified. If the backup is made for old enough data, it won't take space on the disk. - -After creating the backup, data from `/var/lib/clickhouse/shadow/` can be copied to the remote server and then deleted on the local server. -The entire backup process is performed without stopping the server. - -The `ALTER ... FREEZE PARTITION` query is not replicated. A local backup is only created on the local server. - -As an alternative, you can manually copy data from the `/var/lib/clickhouse/data/database/table` directory. -But if you do this while the server is running, race conditions are possible when copying directories with files being added or changed, and the backup may be inconsistent. You can do this if the server isn't running – then the resulting data will be the same as after the `ALTER TABLE t FREEZE PARTITION` query. - -`ALTER TABLE ... FREEZE PARTITION` only copies data, not table metadata. To make a backup of table metadata, copy the file `/var/lib/clickhouse/metadata/database/table.sql` - -To restore from a backup: - -> - Use the CREATE query to create the table if it doesn't exist. The query can be taken from an .sql file (replace `ATTACH` in it with `CREATE`). -- Copy the data from the data/database/table/ directory inside the backup to the `/var/lib/clickhouse/data/database/table/detached/ directory.` -- Run `ALTER TABLE ... ATTACH PARTITION YYYYMM` queries, where `YYYYMM` is the month, for every month. - -In this way, data from the backup will be added to the table. -Restoring from a backup doesn't require stopping the server. - -### Backups and replication - -Replication provides protection from device failures. If all data disappeared on one of your replicas, follow the instructions in the "Restoration after failure" section to restore it. - -For protection from device failures, you must use replication. For more information about replication, see the section "Data replication". - -Backups protect against human error (accidentally deleting data, deleting the wrong data or in the wrong cluster, or corrupting data). -For high-volume databases, it can be difficult to copy backups to remote servers. In such cases, to protect from human error, you can keep a backup on the same server (it will reside in `/var/lib/clickhouse/shadow/`). - -```sql -ALTER TABLE [db.]table FETCH PARTITION 'name' FROM 'path-in-zookeeper' -``` - -This query only works for replicatable tables. - -It downloads the specified partition from the shard that has its `ZooKeeper path` specified in the `FROM` clause, then puts it in the `detached` directory for the specified table. - -Although the query is called `ALTER TABLE`, it does not change the table structure, and does not immediately change the data available in the table. - -Data is placed in the `detached` directory. You can use the `ALTER TABLE ... ATTACH` query to attach the data. - -The ` FROM` clause specifies the path in ` ZooKeeper`. For example, `/clickhouse/tables/01-01/visits`. -Before downloading, the system checks that the partition exists and the table structure matches. The most appropriate replica is selected automatically from the healthy replicas. - -The `ALTER ... FETCH PARTITION` query is not replicated. The partition will be downloaded to the 'detached' directory only on the local server. Note that if after this you use the `ALTER TABLE ... ATTACH` query to add data to the table, the data will be added on all replicas (on one of the replicas it will be added from the 'detached' directory, and on the rest it will be loaded from neighboring replicas). - -### Synchronicity of ALTER queries - -For non-replicatable tables, all `ALTER` queries are performed synchronously. For replicatable tables, the query just adds instructions for the appropriate actions to `ZooKeeper`, and the actions themselves are performed as soon as possible. However, the query can wait for these actions to be completed on all the replicas. - -For `ALTER ... ATTACH|DETACH|DROP` queries, you can use the `replication_alter_partitions_sync` setting to set up waiting. -Possible values: `0` – do not wait; `1` – only wait for own execution (default); `2` – wait for all. - - - -### Mutations - -Mutations are an ALTER query variant that allows changing or deleting rows in a table. In contrast to standard `UPDATE` and `DELETE` queries that are intended for point data changes, mutations are intended for heavy operations that change a lot of rows in a table. - -The functionality is in beta stage and is available starting with the 1.1.54388 version. Currently *MergeTree table engines are supported (both replicated and unreplicated). - -Existing tables are ready for mutations as-is (no conversion necessary), but after the first mutation is applied to a table, its metadata format becomes incompatible with previous server versions and falling back to a previous version becomes impossible. - -At the moment the `ALTER DELETE` command is available: - -```sql -ALTER TABLE [db.]table DELETE WHERE expr -``` - -The expression `expr` must be of UInt8 type. The query deletes rows for which this expression evaluates to a non-zero value. - -One query can contain several commands separated by commas. - -For *MergeTree tables mutations execute by rewriting whole data parts. There is no atomicity - parts are substituted for mutated parts as soon as they are ready and a `SELECT` query that started executing during a mutation will see data from parts that have already been mutated along with data from parts that have not been mutated yet. - -Mutations are totally ordered by their creation order and are applied to each part in that order. Mutations are also partially ordered with INSERTs - data that was inserted into the table before the mutation was submitted will be mutated and data that was inserted after that will not be mutated. Note that mutations do not block INSERTs in any way. - -A mutation query returns immediately after the mutation entry is added (in case of replicated tables to ZooKeeper, for nonreplicated tables - to the filesystem). The mutation itself executes asynchronously using the system profile settings. To track the progress of mutations you can use the `system.mutations` table. A mutation that was successfully submitted will continue to execute even if ClickHouse servers are restarted. There is no way to roll back the mutation once it is submitted. - -#### system.mutations table - -The table contains information about mutations of MergeTree tables and their progress. Each mutation command is represented by a single row. The table has the following columns: - -**database**, **table** - The name of the database and table to which the mutation was applied. - -**mutation_id** - The ID of the mutation. For replicated tables these IDs correspond to znode names in the `/mutations/` directory in ZooKeeper. For unreplicated tables the IDs correspond to file names in the data directory of the table. - -**command** - The mutation command string (the part of the query after `ALTER TABLE [db.]table`). - -**create_time** - When this mutation command was submitted for execution. - -**block_numbers.partition_id**, **block_numbers.number** - A Nested column. For mutations of replicated tables contains one record for each partition: the partition ID and the block number that was acquired by the mutation (in each partition only parts that contain blocks with numbers less than the block number acquired by the mutation in that partition will be mutated). Because in non-replicated tables blocks numbers in all partitions form a single sequence, for mutatations of non-replicated tables the column will contain one record with a single block number acquired by the mutation. - -**parts_to_do** - The number of data parts that need to be mutated for the mutation to finish. - -**is_done** - Is the mutation done? Note that even if `parts_to_do = 0` it is possible that a mutation of a replicated table is not done yet because of a long-running INSERT that will create a new data part that will need to be mutated. - -## SHOW DATABASES - -```sql -SHOW DATABASES [INTO OUTFILE filename] [FORMAT format] -``` - -Prints a list of all databases. -This query is identical to `SELECT name FROM system.databases [INTO OUTFILE filename] [FORMAT format]`. - -See also the section "Formats". - -## SHOW TABLES - -```sql -SHOW [TEMPORARY] TABLES [FROM db] [LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format] -``` - -Displays a list of tables - -- tables from the current database, or from the 'db' database if "FROM db" is specified. -- all tables, or tables whose name matches the pattern, if "LIKE 'pattern'" is specified. - -This query is identical to: `SELECT name FROM system.tables WHERE database = 'db' [AND name LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]`. - -See also the section "LIKE operator". - -## SHOW PROCESSLIST - -```sql -SHOW PROCESSLIST [INTO OUTFILE filename] [FORMAT format] -``` - -Outputs a list of queries currently being processed, other than `SHOW PROCESSLIST` queries. - -Prints a table containing the columns: - -**user** – The user who made the query. Keep in mind that for distributed processing, queries are sent to remote servers under the 'default' user. SHOW PROCESSLIST shows the username for a specific query, not for a query that this query initiated. - -**address** – The name of the host that the query was sent from. For distributed processing, on remote servers, this is the name of the query requestor host. To track where a distributed query was originally made from, look at SHOW PROCESSLIST on the query requestor server. - -**elapsed** – The execution time, in seconds. Queries are output in order of decreasing execution time. - -**rows_read**, **bytes_read** – How many rows and bytes of uncompressed data were read when processing the query. For distributed processing, data is totaled from all the remote servers. This is the data used for restrictions and quotas. - -**memory_usage** – Current RAM usage in bytes. See the setting 'max_memory_usage'. - -**query** – The query itself. In INSERT queries, the data for insertion is not output. - -**query_id** – The query identifier. Non-empty only if it was explicitly defined by the user. For distributed processing, the query ID is not passed to remote servers. - -This query is identical to: `SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]`. - -Tip (execute in the console): - -```bash -watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'" -``` - -## SHOW CREATE TABLE - -```sql -SHOW CREATE [TEMPORARY] TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] -``` - -Returns a single `String`-type 'statement' column, which contains a single value – the `CREATE` query used for creating the specified table. - -## DESCRIBE TABLE - -```sql -DESC|DESCRIBE TABLE [db.]table [INTO OUTFILE filename] [FORMAT format] -``` - -Returns two `String`-type columns: `name` and `type`, which indicate the names and types of columns in the specified table. - -Nested data structures are output in "expanded" format. Each column is shown separately, with the name after a dot. - -## EXISTS - -```sql -EXISTS [TEMPORARY] TABLE [db.]name [INTO OUTFILE filename] [FORMAT format] -``` - -Returns a single `UInt8`-type column, which contains the single value `0` if the table or database doesn't exist, or `1` if the table exists in the specified database. - -## USE - -```sql -USE db -``` - -Lets you set the current database for the session. -The current database is used for searching for tables if the database is not explicitly defined in the query with a dot before the table name. -This query can't be made when using the HTTP protocol, since there is no concept of a session. - -## SET - -```sql -SET param = value -``` - -Allows you to set `param` to `value`. You can also make all the settings from the specified settings profile in a single query. To do this, specify 'profile' as the setting name. For more information, see the section "Settings". -The setting is made for the session, or for the server (globally) if `GLOBAL` is specified. -When making a global setting, the setting is not applied to sessions already running, including the current session. It will only be used for new sessions. - -When the server is restarted, global settings made using `SET` are lost. -To make settings that persist after a server restart, you can only use the server's config file. - -## OPTIMIZE - -```sql -OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] -``` - -Asks the table engine to do something for optimization. -Supported only by `*MergeTree` engines, in which this query initializes a non-scheduled merge of data parts. -If you specify a `PARTITION`, only the specified partition will be optimized. -If you specify `FINAL`, optimization will be performed even when all the data is already in one part. - - - -## INSERT - -Adding data. - -Basic query format: - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ... -``` - -The query can specify a list of columns to insert `[(c1, c2, c3)]`. In this case, the rest of the columns are filled with: - -- The values calculated from the `DEFAULT` expressions specified in the table definition. -- Zeros and empty strings, if `DEFAULT` expressions are not defined. - -If [strict_insert_defaults=1](../operations/settings/settings.md#settings-strict_insert_defaults), columns that do not have `DEFAULT` defined must be listed in the query. - -Data can be passed to the INSERT in any [format](../interfaces/formats.md#formats) supported by ClickHouse. The format must be specified explicitly in the query: - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set -``` - -For example, the following query format is identical to the basic version of INSERT ... VALUES: - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ... -``` - -ClickHouse removes all spaces and one line feed (if there is one) before the data. When forming a query, we recommend putting the data on a new line after the query operators (this is important if the data begins with spaces). - -Example: - -```sql -INSERT INTO t FORMAT TabSeparated -11 Hello, world! -22 Qwerty -``` - -You can insert data separately from the query by using the command-line client or the HTTP interface. For more information, see the section "[Interfaces](../interfaces/index.md#interfaces)". - -### Inserting the results of `SELECT` - -```sql -INSERT INTO [db.]table [(c1, c2, c3)] SELECT ... -``` - -Columns are mapped according to their position in the SELECT clause. However, their names in the SELECT expression and the table for INSERT may differ. If necessary, type casting is performed. - -None of the data formats except Values allow setting values to expressions such as `now()`, `1 + 2`, and so on. The Values format allows limited use of expressions, but this is not recommended, because in this case inefficient code is used for their execution. - -Other queries for modifying data parts are not supported: `UPDATE`, `DELETE`, `REPLACE`, `MERGE`, `UPSERT`, `INSERT UPDATE`. -However, you can delete old data using `ALTER TABLE ... DROP PARTITION`. - -### Performance considerations - -`INSERT` sorts the input data by primary key and splits them into partitions by month. If you insert data for mixed months, it can significantly reduce the performance of the `INSERT` query. To avoid this: - -- Add data in fairly large batches, such as 100,000 rows at a time. -- Group data by month before uploading it to ClickHouse. - -Performance will not decrease if: - -- Data is added in real time. -- You upload data that is usually sorted by time. - -## SELECT - -Data sampling. - -```sql -SELECT [DISTINCT] expr_list - [FROM [db.]table | (subquery) | table_function] [FINAL] - [SAMPLE sample_coeff] - [ARRAY JOIN ...] - [GLOBAL] ANY|ALL INNER|LEFT JOIN (subquery)|table USING columns_list - [PREWHERE expr] - [WHERE expr] - [GROUP BY expr_list] [WITH TOTALS] - [HAVING expr] - [ORDER BY expr_list] - [LIMIT [n, ]m] - [UNION ALL ...] - [INTO OUTFILE filename] - [FORMAT format] - [LIMIT n BY columns] -``` - -All the clauses are optional, except for the required list of expressions immediately after SELECT. -The clauses below are described in almost the same order as in the query execution conveyor. - -If the query omits the `DISTINCT`, `GROUP BY` and `ORDER BY` clauses and the `IN` and `JOIN` subqueries, the query will be completely stream processed, using O(1) amount of RAM. -Otherwise, the query might consume a lot of RAM if the appropriate restrictions are not specified: `max_memory_usage`, `max_rows_to_group_by`, `max_rows_to_sort`, `max_rows_in_distinct`, `max_bytes_in_distinct`, `max_rows_in_set`, `max_bytes_in_set`, `max_rows_in_join`, `max_bytes_in_join`, `max_bytes_before_external_sort`, `max_bytes_before_external_group_by`. For more information, see the section "Settings". It is possible to use external sorting (saving temporary tables to a disk) and external aggregation. `The system does not have "merge join"`. - -### FROM clause - -If the FROM clause is omitted, data will be read from the `system.one` table. -The 'system.one' table contains exactly one row (this table fulfills the same purpose as the DUAL table found in other DBMSs). - -The FROM clause specifies the table to read data from, or a subquery, or a table function; ARRAY JOIN and the regular JOIN may also be included (see below). - -Instead of a table, the SELECT subquery may be specified in brackets. -In this case, the subquery processing pipeline will be built into the processing pipeline of an external query. -In contrast to standard SQL, a synonym does not need to be specified after a subquery. For compatibility, it is possible to write 'AS name' after a subquery, but the specified name isn't used anywhere. - -A table function may be specified instead of a table. For more information, see the section "Table functions". - -To execute a query, all the columns listed in the query are extracted from the appropriate table. Any columns not needed for the external query are thrown out of the subqueries. -If a query does not list any columns (for example, SELECT count() FROM t), some column is extracted from the table anyway (the smallest one is preferred), in order to calculate the number of rows. - -The FINAL modifier can be used only for a SELECT from a CollapsingMergeTree table. When you specify FINAL, data is selected fully "collapsed". Keep in mind that using FINAL leads to a selection that includes columns related to the primary key, in addition to the columns specified in the SELECT. Additionally, the query will be executed in a single stream, and data will be merged during query execution. This means that when using FINAL, the query is processed more slowly. In most cases, you should avoid using FINAL. For more information, see the section "CollapsingMergeTree engine". - -### SAMPLE clause - -The SAMPLE clause allows for approximated query processing. Approximated query processing is only supported by MergeTree\* type tables, and only if the sampling expression was specified during table creation (see the section "MergeTree engine"). - -`SAMPLE` has the `format SAMPLE k`, where `k` is a decimal number from 0 to 1, or `SAMPLE n`, where 'n' is a sufficiently large integer. - -In the first case, the query will be executed on 'k' percent of data. For example, `SAMPLE 0.1` runs the query on 10% of data. -In the second case, the query will be executed on a sample of no more than 'n' rows. For example, `SAMPLE 10000000` runs the query on a maximum of 10,000,000 rows. - -Example: - -```sql -SELECT - Title, - count() * 10 AS PageViews -FROM hits_distributed -SAMPLE 0.1 -WHERE - CounterID = 34 - AND toDate(EventDate) >= toDate('2013-01-29') - AND toDate(EventDate) <= toDate('2013-02-04') - AND NOT DontCountHits - AND NOT Refresh - AND Title != '' -GROUP BY Title -ORDER BY PageViews DESC LIMIT 1000 -``` - -In this example, the query is executed on a sample from 0.1 (10%) of data. Values of aggregate functions are not corrected automatically, so to get an approximate result, the value 'count()' is manually multiplied by 10. - -When using something like `SAMPLE 10000000`, there isn't any information about which relative percent of data was processed or what the aggregate functions should be multiplied by, so this method of writing is not always appropriate to the situation. - -A sample with a relative coefficient is "consistent": if we look at all possible data that could be in the table, a sample (when using a single sampling expression specified during table creation) with the same coefficient always selects the same subset of possible data. In other words, a sample from different tables on different servers at different times is made the same way. - -For example, a sample of user IDs takes rows with the same subset of all the possible user IDs from different tables. This allows using the sample in subqueries in the IN clause, as well as for manually correlating results of different queries with samples. - -### ARRAY JOIN clause - -Allows executing JOIN with an array or nested data structure. The intent is similar to the 'arrayJoin' function, but its functionality is broader. - -`ARRAY JOIN` is essentially `INNER JOIN` with an array. Example: - -```text -:) CREATE TABLE arrays_test (s String, arr Array(UInt8)) ENGINE = Memory - -CREATE TABLE arrays_test -( - s String, - arr Array(UInt8) -) ENGINE = Memory - -Ok. - -0 rows in set. Elapsed: 0.001 sec. - -:) INSERT INTO arrays_test VALUES ('Hello', [1,2]), ('World', [3,4,5]), ('Goodbye', []) - -INSERT INTO arrays_test VALUES - -Ok. - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT * FROM arrays_test - -SELECT * -FROM arrays_test - -┌─s───────┬─arr─────┐ -│ Hello │ [1,2] │ -│ World │ [3,4,5] │ -│ Goodbye │ [] │ -└─────────┴─────────┘ - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT s, arr FROM arrays_test ARRAY JOIN arr - -SELECT s, arr -FROM arrays_test -ARRAY JOIN arr - -┌─s─────┬─arr─┐ -│ Hello │ 1 │ -│ Hello │ 2 │ -│ World │ 3 │ -│ World │ 4 │ -│ World │ 5 │ -└───────┴─────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -An alias can be specified for an array in the ARRAY JOIN clause. In this case, an array item can be accessed by this alias, but the array itself by the original name. Example: - -```text -:) SELECT s, arr, a FROM arrays_test ARRAY JOIN arr AS a - -SELECT s, arr, a -FROM arrays_test -ARRAY JOIN arr AS a - -┌─s─────┬─arr─────┬─a─┐ -│ Hello │ [1,2] │ 1 │ -│ Hello │ [1,2] │ 2 │ -│ World │ [3,4,5] │ 3 │ -│ World │ [3,4,5] │ 4 │ -│ World │ [3,4,5] │ 5 │ -└───────┴─────────┴───┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -Multiple arrays of the same size can be comma-separated in the ARRAY JOIN clause. In this case, JOIN is performed with them simultaneously (the direct sum, not the direct product). Example: - -```text -:) SELECT s, arr, a, num, mapped FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(x -> x + 1, arr) AS mapped - -SELECT s, arr, a, num, mapped -FROM arrays_test -ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(lambda(tuple(x), plus(x, 1)), arr) AS mapped - -┌─s─────┬─arr─────┬─a─┬─num─┬─mapped─┐ -│ Hello │ [1,2] │ 1 │ 1 │ 2 │ -│ Hello │ [1,2] │ 2 │ 2 │ 3 │ -│ World │ [3,4,5] │ 3 │ 1 │ 4 │ -│ World │ [3,4,5] │ 4 │ 2 │ 5 │ -│ World │ [3,4,5] │ 5 │ 3 │ 6 │ -└───────┴─────────┴───┴─────┴────────┘ - -5 rows in set. Elapsed: 0.002 sec. - -:) SELECT s, arr, a, num, arrayEnumerate(arr) FROM arrays_test ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num - -SELECT s, arr, a, num, arrayEnumerate(arr) -FROM arrays_test -ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num - -┌─s─────┬─arr─────┬─a─┬─num─┬─arrayEnumerate(arr)─┐ -│ Hello │ [1,2] │ 1 │ 1 │ [1,2] │ -│ Hello │ [1,2] │ 2 │ 2 │ [1,2] │ -│ World │ [3,4,5] │ 3 │ 1 │ [1,2,3] │ -│ World │ [3,4,5] │ 4 │ 2 │ [1,2,3] │ -│ World │ [3,4,5] │ 5 │ 3 │ [1,2,3] │ -└───────┴─────────┴───┴─────┴─────────────────────┘ - -5 rows in set. Elapsed: 0.002 sec. -``` - -ARRAY JOIN also works with nested data structures. Example: - -```text -:) CREATE TABLE nested_test (s String, nest Nested(x UInt8, y UInt32)) ENGINE = Memory - -CREATE TABLE nested_test -( - s String, - nest Nested( - x UInt8, - y UInt32) -) ENGINE = Memory - -Ok. - -0 rows in set. Elapsed: 0.006 sec. - -:) INSERT INTO nested_test VALUES ('Hello', [1,2], [10,20]), ('World', [3,4,5], [30,40,50]), ('Goodbye', [], []) - -INSERT INTO nested_test VALUES - -Ok. - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT * FROM nested_test - -SELECT * -FROM nested_test - -┌─s───────┬─nest.x──┬─nest.y─────┐ -│ Hello │ [1,2] │ [10,20] │ -│ World │ [3,4,5] │ [30,40,50] │ -│ Goodbye │ [] │ [] │ -└─────────┴─────────┴────────────┘ - -3 rows in set. Elapsed: 0.001 sec. - -:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest - -SELECT s, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN nest - -┌─s─────┬─nest.x─┬─nest.y─┐ -│ Hello │ 1 │ 10 │ -│ Hello │ 2 │ 20 │ -│ World │ 3 │ 30 │ -│ World │ 4 │ 40 │ -│ World │ 5 │ 50 │ -└───────┴────────┴────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -When specifying names of nested data structures in ARRAY JOIN, the meaning is the same as ARRAY JOIN with all the array elements that it consists of. Example: - -```text -:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x, nest.y - -SELECT s, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN `nest.x`, `nest.y` - -┌─s─────┬─nest.x─┬─nest.y─┐ -│ Hello │ 1 │ 10 │ -│ Hello │ 2 │ 20 │ -│ World │ 3 │ 30 │ -│ World │ 4 │ 40 │ -│ World │ 5 │ 50 │ -└───────┴────────┴────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -This variation also makes sense: - -```text -:) SELECT s, nest.x, nest.y FROM nested_test ARRAY JOIN nest.x - -SELECT s, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN `nest.x` - -┌─s─────┬─nest.x─┬─nest.y─────┐ -│ Hello │ 1 │ [10,20] │ -│ Hello │ 2 │ [10,20] │ -│ World │ 3 │ [30,40,50] │ -│ World │ 4 │ [30,40,50] │ -│ World │ 5 │ [30,40,50] │ -└───────┴────────┴────────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -An alias may be used for a nested data structure, in order to select either the JOIN result or the source array. Example: - -```text -:) SELECT s, n.x, n.y, nest.x, nest.y FROM nested_test ARRAY JOIN nest AS n - -SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y` -FROM nested_test -ARRAY JOIN nest AS n - -┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┐ -│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ -│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ -│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ -│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ -│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ -└───────┴─────┴─────┴─────────┴────────────┘ - -5 rows in set. Elapsed: 0.001 sec. -``` - -Example of using the arrayEnumerate function: - -```text -:) SELECT s, n.x, n.y, nest.x, nest.y, num FROM nested_test ARRAY JOIN nest AS n, arrayEnumerate(nest.x) AS num - -SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y`, num -FROM nested_test -ARRAY JOIN nest AS n, arrayEnumerate(`nest.x`) AS num - -┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┬─num─┐ -│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ 1 │ -│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ 2 │ -│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ 1 │ -│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ 2 │ -│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ 3 │ -└───────┴─────┴─────┴─────────┴────────────┴─────┘ - -5 rows in set. Elapsed: 0.002 sec. -``` - -The query can only specify a single ARRAY JOIN clause. - -The corresponding conversion can be performed before the WHERE/PREWHERE clause (if its result is needed in this clause), or after completing WHERE/PREWHERE (to reduce the volume of calculations). - -### JOIN clause - -The normal JOIN, which is not related to ARRAY JOIN described above. - -```sql -[GLOBAL] ANY|ALL INNER|LEFT [OUTER] JOIN (subquery)|table USING columns_list -``` - -Performs joins with data from the subquery. At the beginning of query processing, the subquery specified after JOIN is run, and its result is saved in memory. Then it is read from the "left" table specified in the FROM clause, and while it is being read, for each of the read rows from the "left" table, rows are selected from the subquery results table (the "right" table) that meet the condition for matching the values of the columns specified in USING. - -The table name can be specified instead of a subquery. This is equivalent to the `SELECT * FROM table` subquery, except in a special case when the table has the Join engine – an array prepared for joining. - -All columns that are not needed for the JOIN are deleted from the subquery. - -There are several types of JOINs: - -`INNER` or `LEFT` type:If INNER is specified, the result will contain only those rows that have a matching row in the right table. -If LEFT is specified, any rows in the left table that don't have matching rows in the right table will be assigned the default value - zeros or empty rows. LEFT OUTER may be written instead of LEFT; the word OUTER does not affect anything. - -`ANY` or `ALL` stringency:If `ANY` is specified and the right table has several matching rows, only the first one found is joined. -If `ALL` is specified and the right table has several matching rows, the data will be multiplied by the number of these rows. - -Using ALL corresponds to the normal JOIN semantic from standard SQL. -Using ANY is optimal. If the right table has only one matching row, the results of ANY and ALL are the same. You must specify either ANY or ALL (neither of them is selected by default). - -`GLOBAL` distribution: - -When using a normal JOIN, the query is sent to remote servers. Subqueries are run on each of them in order to make the right table, and the join is performed with this table. In other words, the right table is formed on each server separately. - -When using `GLOBAL ... JOIN`, first the requestor server runs a subquery to calculate the right table. This temporary table is passed to each remote server, and queries are run on them using the temporary data that was transmitted. - -Be careful when using GLOBAL JOINs. For more information, see the section "Distributed subqueries". - -Any combination of JOINs is possible. For example, `GLOBAL ANY LEFT OUTER JOIN`. - -When running a JOIN, there is no optimization of the order of execution in relation to other stages of the query. The join (a search in the right table) is run before filtering in WHERE and before aggregation. In order to explicitly set the processing order, we recommend running a JOIN subquery with a subquery. - -Example: - -```sql -SELECT - CounterID, - hits, - visits -FROM -( - SELECT - CounterID, - count() AS hits - FROM test.hits - GROUP BY CounterID -) ANY LEFT JOIN -( - SELECT - CounterID, - sum(Sign) AS visits - FROM test.visits - GROUP BY CounterID -) USING CounterID -ORDER BY hits DESC -LIMIT 10 -``` - -```text -┌─CounterID─┬───hits─┬─visits─┐ -│ 1143050 │ 523264 │ 13665 │ -│ 731962 │ 475698 │ 102716 │ -│ 722545 │ 337212 │ 108187 │ -│ 722889 │ 252197 │ 10547 │ -│ 2237260 │ 196036 │ 9522 │ -│ 23057320 │ 147211 │ 7689 │ -│ 722818 │ 90109 │ 17847 │ -│ 48221 │ 85379 │ 4652 │ -│ 19762435 │ 77807 │ 7026 │ -│ 722884 │ 77492 │ 11056 │ -└───────────┴────────┴────────┘ -``` - -Subqueries don't allow you to set names or use them for referencing a column from a specific subquery. -The columns specified in USING must have the same names in both subqueries, and the other columns must be named differently. You can use aliases to change the names of columns in subqueries (the example uses the aliases 'hits' and 'visits'). - -The USING clause specifies one or more columns to join, which establishes the equality of these columns. The list of columns is set without brackets. More complex join conditions are not supported. - -The right table (the subquery result) resides in RAM. If there isn't enough memory, you can't run a JOIN. - -Only one JOIN can be specified in a query (on a single level). To run multiple JOINs, you can put them in subqueries. - -Each time a query is run with the same JOIN, the subquery is run again – the result is not cached. To avoid this, use the special 'Join' table engine, which is a prepared array for joining that is always in RAM. For more information, see the section "Table engines, Join". - -In some cases, it is more efficient to use IN instead of JOIN. -Among the various types of JOINs, the most efficient is ANY LEFT JOIN, then ANY INNER JOIN. The least efficient are ALL LEFT JOIN and ALL INNER JOIN. - -If you need a JOIN for joining with dimension tables (these are relatively small tables that contain dimension properties, such as names for advertising campaigns), a JOIN might not be very convenient due to the bulky syntax and the fact that the right table is re-accessed for every query. For such cases, there is an "external dictionaries" feature that you should use instead of JOIN. For more information, see the section "External dictionaries". - -### WHERE clause - -If there is a WHERE clause, it must contain an expression with the UInt8 type. This is usually an expression with comparison and logical operators. -This expression will be used for filtering data before all other transformations. - -If indexes are supported by the database table engine, the expression is evaluated on the ability to use indexes. - -### PREWHERE clause - -This clause has the same meaning as the WHERE clause. The difference is in which data is read from the table. -When using PREWHERE, first only the columns necessary for executing PREWHERE are read. Then the other columns are read that are needed for running the query, but only those blocks where the PREWHERE expression is true. - -It makes sense to use PREWHERE if there are filtration conditions that are not suitable for indexes that are used by a minority of the columns in the query, but that provide strong data filtration. This reduces the volume of data to read. - -For example, it is useful to write PREWHERE for queries that extract a large number of columns, but that only have filtration for a few columns. - -PREWHERE is only supported by tables from the `*MergeTree` family. - -A query may simultaneously specify PREWHERE and WHERE. In this case, PREWHERE precedes WHERE. - -Keep in mind that it does not make much sense for PREWHERE to only specify those columns that have an index, because when using an index, only the data blocks that match the index are read. - -If the 'optimize_move_to_prewhere' setting is set to 1 and PREWHERE is omitted, the system uses heuristics to automatically move parts of expressions from WHERE to PREWHERE. - -### GROUP BY clause - -This is one of the most important parts of a column-oriented DBMS. - -If there is a GROUP BY clause, it must contain a list of expressions. Each expression will be referred to here as a "key". -All the expressions in the SELECT, HAVING, and ORDER BY clauses must be calculated from keys or from aggregate functions. In other words, each column selected from the table must be used either in keys or inside aggregate functions. - -If a query contains only table columns inside aggregate functions, the GROUP BY clause can be omitted, and aggregation by an empty set of keys is assumed. - -Example: - -```sql -SELECT - count(), - median(FetchTiming > 60 ? 60 : FetchTiming), - count() - sum(Refresh) -FROM hits -``` - -However, in contrast to standard SQL, if the table doesn't have any rows (either there aren't any at all, or there aren't any after using WHERE to filter), an empty result is returned, and not the result from one of the rows containing the initial values of aggregate functions. - -As opposed to MySQL (and conforming to standard SQL), you can't get some value of some column that is not in a key or aggregate function (except constant expressions). To work around this, you can use the 'any' aggregate function (get the first encountered value) or 'min/max'. - -Example: - -```sql -SELECT - domainWithoutWWW(URL) AS domain, - count(), - any(Title) AS title -- getting the first occurred page header for each domain. -FROM hits -GROUP BY domain -``` - -For every different key value encountered, GROUP BY calculates a set of aggregate function values. - -GROUP BY is not supported for array columns. - -A constant can't be specified as arguments for aggregate functions. Example: sum(1). Instead of this, you can get rid of the constant. Example: `count()`. - -#### WITH TOTALS modifier - -If the WITH TOTALS modifier is specified, another row will be calculated. This row will have key columns containing default values (zeros or empty lines), and columns of aggregate functions with the values calculated across all the rows (the "total" values). - -This extra row is output in JSON\*, TabSeparated\*, and Pretty\* formats, separately from the other rows. In the other formats, this row is not output. - -In JSON\* formats, this row is output as a separate 'totals' field. In TabSeparated\* formats, the row comes after the main result, preceded by an empty row (after the other data). In Pretty\* formats, the row is output as a separate table after the main result. - -`WITH TOTALS` can be run in different ways when HAVING is present. The behavior depends on the 'totals_mode' setting. -By default, `totals_mode = 'before_having'`. In this case, 'totals' is calculated across all rows, including the ones that don't pass through HAVING and 'max_rows_to_group_by'. - -The other alternatives include only the rows that pass through HAVING in 'totals', and behave differently with the setting `max_rows_to_group_by` and `group_by_overflow_mode = 'any'`. - -`after_having_exclusive` – Don't include rows that didn't pass through `max_rows_to_group_by`. In other words, 'totals' will have less than or the same number of rows as it would if `max_rows_to_group_by` were omitted. - -`after_having_inclusive` – Include all the rows that didn't pass through 'max_rows_to_group_by' in 'totals'. In other words, 'totals' will have more than or the same number of rows as it would if `max_rows_to_group_by` were omitted. - -`after_having_auto` – Count the number of rows that passed through HAVING. If it is more than a certain amount (by default, 50%), include all the rows that didn't pass through 'max_rows_to_group_by' in 'totals'. Otherwise, do not include them. - -`totals_auto_threshold` – By default, 0.5. The coefficient for `after_having_auto`. - -If `max_rows_to_group_by` and `group_by_overflow_mode = 'any'` are not used, all variations of `after_having` are the same, and you can use any of them (for example, `after_having_auto`). - -You can use WITH TOTALS in subqueries, including subqueries in the JOIN clause (in this case, the respective total values are combined). - -#### GROUP BY in external memory - -You can enable dumping temporary data to the disk to restrict memory usage during GROUP BY. -The `max_bytes_before_external_group_by` setting determines the threshold RAM consumption for dumping GROUP BY temporary data to the file system. If set to 0 (the default), it is disabled. - -When using `max_bytes_before_external_group_by`, we recommend that you set max_memory_usage about twice as high. This is necessary because there are two stages to aggregation: reading the date and forming intermediate data (1) and merging the intermediate data (2). Dumping data to the file system can only occur during stage 1. If the temporary data wasn't dumped, then stage 2 might require up to the same amount of memory as in stage 1. - -For example, if `max_memory_usage` was set to 10000000000 and you want to use external aggregation, it makes sense to set `max_bytes_before_external_group_by` to 10000000000, and max_memory_usage to 20000000000. When external aggregation is triggered (if there was at least one dump of temporary data), maximum consumption of RAM is only slightly more than ` max_bytes_before_external_group_by`. - -With distributed query processing, external aggregation is performed on remote servers. In order for the requestor server to use only a small amount of RAM, set ` distributed_aggregation_memory_efficient` to 1. - -When merging data flushed to the disk, as well as when merging results from remote servers when the ` distributed_aggregation_memory_efficient` setting is enabled, consumes up to 1/256 \* the number of threads from the total amount of RAM. - -When external aggregation is enabled, if there was less than ` max_bytes_before_external_group_by` of data (i.e. data was not flushed), the query runs just as fast as without external aggregation. If any temporary data was flushed, the run time will be several times longer (approximately three times). - -If you have an ORDER BY with a small LIMIT after GROUP BY, then the ORDER BY CLAUSE will not use significant amounts of RAM. -But if the ORDER BY doesn't have LIMIT, don't forget to enable external sorting (`max_bytes_before_external_sort`). - -### LIMIT N BY clause - -LIMIT N BY COLUMNS selects the top N rows for each group of COLUMNS. LIMIT N BY is not related to LIMIT; they can both be used in the same query. The key for LIMIT N BY can contain any number of columns or expressions. - -Example: - -```sql -SELECT - domainWithoutWWW(URL) AS domain, - domainWithoutWWW(REFERRER_URL) AS referrer, - device_type, - count() cnt -FROM hits -GROUP BY domain, referrer, device_type -ORDER BY cnt DESC -LIMIT 5 BY domain, device_type -LIMIT 100 -``` - -The query will select the top 5 referrers for each `domain, device_type` pair, but not more than 100 rows (`LIMIT n BY + LIMIT`). - -### HAVING clause - -Allows filtering the result received after GROUP BY, similar to the WHERE clause. -WHERE and HAVING differ in that WHERE is performed before aggregation (GROUP BY), while HAVING is performed after it. -If aggregation is not performed, HAVING can't be used. - - - -### ORDER BY clause - -The ORDER BY clause contains a list of expressions, which can each be assigned DESC or ASC (the sorting direction). If the direction is not specified, ASC is assumed. ASC is sorted in ascending order, and DESC in descending order. The sorting direction applies to a single expression, not to the entire list. Example: `ORDER BY Visits DESC, SearchPhrase` - -For sorting by String values, you can specify collation (comparison). Example: `ORDER BY SearchPhrase COLLATE 'tr'` - for sorting by keyword in ascending order, using the Turkish alphabet, case insensitive, assuming that strings are UTF-8 encoded. COLLATE can be specified or not for each expression in ORDER BY independently. If ASC or DESC is specified, COLLATE is specified after it. When using COLLATE, sorting is always case-insensitive. - -We only recommend using COLLATE for final sorting of a small number of rows, since sorting with COLLATE is less efficient than normal sorting by bytes. - -Rows that have identical values for the list of sorting expressions are output in an arbitrary order, which can also be nondeterministic (different each time). -If the ORDER BY clause is omitted, the order of the rows is also undefined, and may be nondeterministic as well. - -When floating point numbers are sorted, NaNs are separate from the other values. Regardless of the sorting order, NaNs come at the end. In other words, for ascending sorting they are placed as if they are larger than all the other numbers, while for descending sorting they are placed as if they are smaller than the rest. - -Less RAM is used if a small enough LIMIT is specified in addition to ORDER BY. Otherwise, the amount of memory spent is proportional to the volume of data for sorting. For distributed query processing, if GROUP BY is omitted, sorting is partially done on remote servers, and the results are merged on the requestor server. This means that for distributed sorting, the volume of data to sort can be greater than the amount of memory on a single server. - -If there is not enough RAM, it is possible to perform sorting in external memory (creating temporary files on a disk). Use the setting `max_bytes_before_external_sort` for this purpose. If it is set to 0 (the default), external sorting is disabled. If it is enabled, when the volume of data to sort reaches the specified number of bytes, the collected data is sorted and dumped into a temporary file. After all data is read, all the sorted files are merged and the results are output. Files are written to the /var/lib/clickhouse/tmp/ directory in the config (by default, but you can use the 'tmp_path' parameter to change this setting). - -Running a query may use more memory than 'max_bytes_before_external_sort'. For this reason, this setting must have a value significantly smaller than 'max_memory_usage'. As an example, if your server has 128 GB of RAM and you need to run a single query, set 'max_memory_usage' to 100 GB, and 'max_bytes_before_external_sort' to 80 GB. - -External sorting works much less effectively than sorting in RAM. - -### SELECT clause - -The expressions specified in the SELECT clause are analyzed after the calculations for all the clauses listed above are completed. -More specifically, expressions are analyzed that are above the aggregate functions, if there are any aggregate functions. -The aggregate functions and everything below them are calculated during aggregation (GROUP BY). -These expressions work as if they are applied to separate rows in the result. - -### DISTINCT clause - -If DISTINCT is specified, only a single row will remain out of all the sets of fully matching rows in the result. -The result will be the same as if GROUP BY were specified across all the fields specified in SELECT without aggregate functions. But there are several differences from GROUP BY: - -- DISTINCT can be applied together with GROUP BY. -- When ORDER BY is omitted and LIMIT is defined, the query stops running immediately after the required number of different rows has been read. -- Data blocks are output as they are processed, without waiting for the entire query to finish running. - -DISTINCT is not supported if SELECT has at least one array column. - -### LIMIT clause - -LIMIT m allows you to select the first 'm' rows from the result. -LIMIT n, m allows you to select the first 'm' rows from the result after skipping the first 'n' rows. - -'n' and 'm' must be non-negative integers. - -If there isn't an ORDER BY clause that explicitly sorts results, the result may be arbitrary and nondeterministic. - -### UNION ALL clause - -You can use UNION ALL to combine any number of queries. Example: - -```sql -SELECT CounterID, 1 AS table, toInt64(count()) AS c - FROM test.hits - GROUP BY CounterID - -UNION ALL - -SELECT CounterID, 2 AS table, sum(Sign) AS c - FROM test.visits - GROUP BY CounterID - HAVING c > 0 -``` - -Only UNION ALL is supported. The regular UNION (UNION DISTINCT) is not supported. If you need UNION DISTINCT, you can write SELECT DISTINCT from a subquery containing UNION ALL. - -Queries that are parts of UNION ALL can be run simultaneously, and their results can be mixed together. - -The structure of results (the number and type of columns) must match for the queries. But the column names can differ. In this case, the column names for the final result will be taken from the first query. - -Queries that are parts of UNION ALL can't be enclosed in brackets. ORDER BY and LIMIT are applied to separate queries, not to the final result. If you need to apply a conversion to the final result, you can put all the queries with UNION ALL in a subquery in the FROM clause. - -### INTO OUTFILE clause - -Add the `INTO OUTFILE filename` clause (where filename is a string literal) to redirect query output to the specified file. -In contrast to MySQL, the file is created on the client side. The query will fail if a file with the same filename already exists. -This functionality is available in the command-line client and clickhouse-local (a query sent via HTTP interface will fail). - -The default output format is TabSeparated (the same as in the command-line client batch mode). - -### FORMAT clause - -Specify 'FORMAT format' to get data in any specified format. -You can use this for convenience, or for creating dumps. -For more information, see the section "Formats". -If the FORMAT clause is omitted, the default format is used, which depends on both the settings and the interface used for accessing the DB. For the HTTP interface and the command-line client in batch mode, the default format is TabSeparated. For the command-line client in interactive mode, the default format is PrettyCompact (it has attractive and compact tables). - -When using the command-line client, data is passed to the client in an internal efficient format. The client independently interprets the FORMAT clause of the query and formats the data itself (thus relieving the network and the server from the load). - -### IN operators - -The `IN`, `NOT IN`, `GLOBAL IN`, and `GLOBAL NOT IN` operators are covered separately, since their functionality is quite rich. - -The left side of the operator is either a single column or a tuple. - -Examples: - -```sql -SELECT UserID IN (123, 456) FROM ... -SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ... -``` - -If the left side is a single column that is in the index, and the right side is a set of constants, the system uses the index for processing the query. - -Don't list too many values explicitly (i.e. millions). If a data set is large, put it in a temporary table (for example, see the section "External data for query processing"), then use a subquery. - -The right side of the operator can be a set of constant expressions, a set of tuples with constant expressions (shown in the examples above), or the name of a database table or SELECT subquery in brackets. - -If the right side of the operator is the name of a table (for example, `UserID IN users`), this is equivalent to the subquery `UserID IN (SELECT * FROM users)`. Use this when working with external data that is sent along with the query. For example, the query can be sent together with a set of user IDs loaded to the 'users' temporary table, which should be filtered. - -If the right side of the operator is a table name that has the Set engine (a prepared data set that is always in RAM), the data set will not be created over again for each query. - -The subquery may specify more than one column for filtering tuples. -Example: - -```sql -SELECT (CounterID, UserID) IN (SELECT CounterID, UserID FROM ...) FROM ... -``` - -The columns to the left and right of the IN operator should have the same type. - -The IN operator and subquery may occur in any part of the query, including in aggregate functions and lambda functions. -Example: - -```sql -SELECT - EventDate, - avg(UserID IN - ( - SELECT UserID - FROM test.hits - WHERE EventDate = toDate('2014-03-17') - )) AS ratio -FROM test.hits -GROUP BY EventDate -ORDER BY EventDate ASC -``` - -```text -┌──EventDate─┬────ratio─┐ -│ 2014-03-17 │ 1 │ -│ 2014-03-18 │ 0.807696 │ -│ 2014-03-19 │ 0.755406 │ -│ 2014-03-20 │ 0.723218 │ -│ 2014-03-21 │ 0.697021 │ -│ 2014-03-22 │ 0.647851 │ -│ 2014-03-23 │ 0.648416 │ -└────────────┴──────────┘ -``` - -For each day after March 17th, count the percentage of pageviews made by users who visited the site on March 17th. -A subquery in the IN clause is always run just one time on a single server. There are no dependent subqueries. - - - -#### Distributed subqueries - -There are two options for IN-s with subqueries (similar to JOINs): normal `IN` / ` OIN` and `IN GLOBAL` / `GLOBAL JOIN`. They differ in how they are run for distributed query processing. - -
- -Remember that the algorithms described below may work differently depending on the [settings](../operations/settings/settings.md#settings-distributed_product_mode) `distributed_product_mode` setting. - -
- -When using the regular IN, the query is sent to remote servers, and each of them runs the subqueries in the `IN` or `JOIN` clause. - -When using `GLOBAL IN` / `GLOBAL JOINs`, first all the subqueries are run for `GLOBAL IN` / `GLOBAL JOINs`, and the results are collected in temporary tables. Then the temporary tables are sent to each remote server, where the queries are run using this temporary data. - -For a non-distributed query, use the regular `IN` / `JOIN`. - -Be careful when using subqueries in the `IN` / `JOIN` clauses for distributed query processing. - -Let's look at some examples. Assume that each server in the cluster has a normal **local_table**. Each server also has a **distributed_table** table with the **Distributed** type, which looks at all the servers in the cluster. - -For a query to the **distributed_table**, the query will be sent to all the remote servers and run on them using the **local_table**. - -For example, the query - -```sql -SELECT uniq(UserID) FROM distributed_table -``` - -will be sent to all remote servers as - -```sql -SELECT uniq(UserID) FROM local_table -``` - -and run on each of them in parallel, until it reaches the stage where intermediate results can be combined. Then the intermediate results will be returned to the requestor server and merged on it, and the final result will be sent to the client. - -Now let's examine a query with IN: - -```sql -SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) -``` - -- Calculation of the intersection of audiences of two sites. - -This query will be sent to all remote servers as - -```sql -SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34) -``` - -In other words, the data set in the IN clause will be collected on each server independently, only across the data that is stored locally on each of the servers. - -This will work correctly and optimally if you are prepared for this case and have spread data across the cluster servers such that the data for a single UserID resides entirely on a single server. In this case, all the necessary data will be available locally on each server. Otherwise, the result will be inaccurate. We refer to this variation of the query as "local IN". - -To correct how the query works when data is spread randomly across the cluster servers, you could specify **distributed_table** inside a subquery. The query would look like this: - -```sql -SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) -``` - -This query will be sent to all remote servers as - -```sql -SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) -``` - -The subquery will begin running on each remote server. Since the subquery uses a distributed table, the subquery that is on each remote server will be resent to every remote server as - -```sql -SELECT UserID FROM local_table WHERE CounterID = 34 -``` - -For example, if you have a cluster of 100 servers, executing the entire query will require 10,000 elementary requests, which is generally considered unacceptable. - -In such cases, you should always use GLOBAL IN instead of IN. Let's look at how it works for the query - -```sql -SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID GLOBAL IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) -``` - -The requestor server will run the subquery - -```sql -SELECT UserID FROM distributed_table WHERE CounterID = 34 -``` - -and the result will be put in a temporary table in RAM. Then the request will be sent to each remote server as - -```sql -SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID GLOBAL IN _data1 -``` - -and the temporary table `_data1` will be sent to every remote server with the query (the name of the temporary table is implementation-defined). - -This is more optimal than using the normal IN. However, keep the following points in mind: - -1. When creating a temporary table, data is not made unique. To reduce the volume of data transmitted over the network, specify DISTINCT in the subquery. (You don't need to do this for a normal IN.) -2. The temporary table will be sent to all the remote servers. Transmission does not account for network topology. For example, if 10 remote servers reside in a datacenter that is very remote in relation to the requestor server, the data will be sent 10 times over the channel to the remote datacenter. Try to avoid large data sets when using GLOBAL IN. -3. When transmitting data to remote servers, restrictions on network bandwidth are not configurable. You might overload the network. -4. Try to distribute data across servers so that you don't need to use GLOBAL IN on a regular basis. -5. If you need to use GLOBAL IN often, plan the location of the ClickHouse cluster so that a single group of replicas resides in no more than one data center with a fast network between them, so that a query can be processed entirely within a single data center. - -It also makes sense to specify a local table in the `GLOBAL IN` clause, in case this local table is only available on the requestor server and you want to use data from it on remote servers. - -### Extreme values - -In addition to results, you can also get minimum and maximum values for the results columns. To do this, set the **extremes** setting to 1. Minimums and maximums are calculated for numeric types, dates, and dates with times. For other columns, the default values are output. - -An extra two rows are calculated – the minimums and maximums, respectively. These extra two rows are output in JSON\*, TabSeparated\*, and Pretty\* formats, separate from the other rows. They are not output for other formats. - -In JSON\* formats, the extreme values are output in a separate 'extremes' field. In TabSeparated\* formats, the row comes after the main result, and after 'totals' if present. It is preceded by an empty row (after the other data). In Pretty\* formats, the row is output as a separate table after the main result, and after 'totals' if present. - -Extreme values are calculated for rows that have passed through LIMIT. However, when using 'LIMIT offset, size', the rows before 'offset' are included in 'extremes'. In stream requests, the result may also include a small number of rows that passed through LIMIT. - -### Notes - -The `GROUP BY` and `ORDER BY` clauses do not support positional arguments. This contradicts MySQL, but conforms to standard SQL. -For example, `GROUP BY 1, 2` will be interpreted as grouping by constants (i.e. aggregation of all rows into one). - -You can use synonyms (`AS` aliases) in any part of a query. - -You can put an asterisk in any part of a query instead of an expression. When the query is analyzed, the asterisk is expanded to a list of all table columns (excluding the `MATERIALIZED` and `ALIAS` columns). There are only a few cases when using an asterisk is justified: - -- When creating a table dump. -- For tables containing just a few columns, such as system tables. -- For getting information about what columns are in a table. In this case, set `LIMIT 1`. But it is better to use the `DESC TABLE` query. -- When there is strong filtration on a small number of columns using `PREWHERE`. -- In subqueries (since columns that aren't needed for the external query are excluded from subqueries). - -In all other cases, we don't recommend using the asterisk, since it only gives you the drawbacks of a columnar DBMS instead of the advantages. In other words using the asterisk is not recommended. - -## KILL QUERY - -```sql -KILL QUERY - WHERE - [SYNC|ASYNC|TEST] - [FORMAT format] -``` - -Attempts to forcibly terminate the currently running queries. -The queries to terminate are selected from the system.processes table using the criteria defined in the `WHERE` clause of the `KILL` query. - -Examples: - -```sql --- Forcibly terminates all queries with the specified query_id: -KILL QUERY WHERE query_id='2-857d-4a57-9ee0-327da5d60a90' - --- Synchronously terminates all queries run by 'username': -KILL QUERY WHERE user='username' SYNC -``` - -Read-only users can only stop their own queries. - -By default, the asynchronous version of queries is used (`ASYNC`), which doesn't wait for confirmation that queries have stopped. - -The synchronous version (`SYNC`) waits for all queries to stop and displays information about each process as it stops. -The response contains the `kill_status` column, which can take the following values: - -1. 'finished' – The query was terminated successfully. -2. 'waiting' – Waiting for the query to end after sending it a signal to terminate. -3. The other values ​​explain why the query can't be stopped. - -A test query (`TEST`) only checks the user's rights and displays a list of queries to stop. diff --git a/docs/en/query_language/index.md b/docs/en/query_language/index.md index 4f9e3704d12..d9ff70fd69c 100644 --- a/docs/en/query_language/index.md +++ b/docs/en/query_language/index.md @@ -1,7 +1,7 @@ # Query language -* [SELECT](select.md) -* [INSERT INTO](insert_into.md) -* [CREATE](create.md) -* [ALTER](alter.md) -* [Other kinds of queries](misc.md) +* [SELECT](select.md#select) +* [INSERT INTO](insert_into.md#queries-insert) +* [CREATE](create.md#create-database) +* [ALTER](alter.md#query_language_queries_alter) +* [Other kinds of queries](misc.md#miscellaneous-queries) diff --git a/docs/ru/data_types/float.md b/docs/ru/data_types/float.md index ea81d3d2bd9..228fd93193e 100644 --- a/docs/ru/data_types/float.md +++ b/docs/ru/data_types/float.md @@ -65,4 +65,4 @@ SELECT 0 / 0 └──────────────┘ ``` - Смотрите правила сортировки `NaN` в разделе [Секция ORDER BY](../query_language/queries.md#query_language-queries-order_by). + Смотрите правила сортировки `NaN` в разделе [Секция ORDER BY](../query_language/select.md#query_language-queries-order_by). diff --git a/docs/ru/operations/server_settings/settings.md b/docs/ru/operations/server_settings/settings.md index 6734f42178b..e15782a34c4 100644 --- a/docs/ru/operations/server_settings/settings.md +++ b/docs/ru/operations/server_settings/settings.md @@ -67,7 +67,7 @@ ClickHouse проверит условия `min_part_size` и `min_part_size_rat База данных по умолчанию. -Перечень баз данных можно получить запросом [SHOW DATABASES](../../query_language/queries.md#query_language_queries_show_databases). +Перечень баз данных можно получить запросом [SHOW DATABASES](../../query_language/misc.md#query_language_queries_show_databases). **Пример** diff --git a/docs/ru/operations/settings/settings.md b/docs/ru/operations/settings/settings.md index 89a43b6bb6e..727189b5e99 100644 --- a/docs/ru/operations/settings/settings.md +++ b/docs/ru/operations/settings/settings.md @@ -4,7 +4,7 @@ ## distributed_product_mode -Изменяет поведение [распределенных подзапросов](../../query_language/queries.md#queries-distributed-subrequests). +Изменяет поведение [распределенных подзапросов](../../query_language/select.md#queries-distributed-subrequests). ClickHouse применяет настройку в тех случаях, когда запрос содержит произведение распределённых таблиц, т.е. когда запрос к распределенной таблице содержит не-GLOBAL подзапрос к также распределенной таблице. diff --git a/docs/ru/operations/system_tables.md b/docs/ru/operations/system_tables.md index 32086933d4a..3d8f3032d10 100644 --- a/docs/ru/operations/system_tables.md +++ b/docs/ru/operations/system_tables.md @@ -126,7 +126,7 @@ default_expression String - выражение для значения по ум Столбцы: -- partition (String) - Имя партиции. Формат YYYYMM. Что такое партиция можно узнать из описания запроса [ALTER](../query_language/queries.md#query_language_queries_alter). +- partition (String) - Имя партиции. Формат YYYYMM. Что такое партиция можно узнать из описания запроса [ALTER](../query_language/alter.md#query_language_queries_alter). - name (String) - Имя куска. - active (UInt8) - Признак активности. Если кусок активен, то он используется таблице, в противном случает он будет удален. Неактивные куски остаются после слияний. - marks (UInt64) - Количество засечек. Чтобы получить примерное количество строк в куске, умножьте ``marks`` на гранулированность индекса (обычно 8192). diff --git a/docs/ru/operations/table_engines/file.md b/docs/ru/operations/table_engines/file.md index 93b2c0c3f45..aaa334c7806 100644 --- a/docs/ru/operations/table_engines/file.md +++ b/docs/ru/operations/table_engines/file.md @@ -22,7 +22,7 @@ File(Format) При создании таблицы с помощью `File(Format)` сервер ClickHouse создает в хранилище каталог с именем таблицы, а после добавления в таблицу данных помещает туда файл `data.Format`. -Можно вручную создать в хранилище каталог таблицы, поместить туда файл, затем на сервере ClickHouse добавить ([ATTACH](../../query_language/queries.md#queries-attach)) информацию о таблице, соответствующей имени каталога и прочитать из файла данные. +Можно вручную создать в хранилище каталог таблицы, поместить туда файл, затем на сервере ClickHouse добавить ([ATTACH](../../query_language/misc.md#queries-attach)) информацию о таблице, соответствующей имени каталога и прочитать из файла данные.
Будьте аккуратны с этой функциональностью, поскольку сервер ClickHouse не отслеживает внешние изменения данных. Если в файл будет производиться запись одновременно со стороны сервера ClickHouse и с внешней стороны, то результат непредсказуем. diff --git a/docs/ru/operations/table_engines/materializedview.md b/docs/ru/operations/table_engines/materializedview.md index 997d17928c2..8c44eb40c01 100644 --- a/docs/ru/operations/table_engines/materializedview.md +++ b/docs/ru/operations/table_engines/materializedview.md @@ -1,3 +1,3 @@ # MaterializedView -Используется для реализации материализованных представлений (подробнее см. запрос [CREATE TABLE](../../query_language/queries.md#query_language-queries-create_table)). Для хранения данных, использует другой движок, который был указан при создании представления. При чтении из таблицы, просто использует этот движок. +Используется для реализации материализованных представлений (подробнее см. запрос [CREATE TABLE](../../query_language/create.md#query_language-queries-create_table)). Для хранения данных, использует другой движок, который был указан при создании представления. При чтении из таблицы, просто использует этот движок. diff --git a/docs/ru/operations/table_engines/replication.md b/docs/ru/operations/table_engines/replication.md index 9c9cb69ff1a..40d23b2b9ea 100644 --- a/docs/ru/operations/table_engines/replication.md +++ b/docs/ru/operations/table_engines/replication.md @@ -15,7 +15,7 @@ Репликация не зависит от шардирования. На каждом шарде репликация работает независимо. -Реплицируются сжатые данные запросов `INSERT`, `ALTER` (см. подробности в описании запроса [ALTER](../../query_language/queries.md#query_language_queries_alter)). +Реплицируются сжатые данные запросов `INSERT`, `ALTER` (см. подробности в описании запроса [ALTER](../../query_language/alter.md#query_language_queries_alter)). Запросы `CREATE`, `DROP`, `ATTACH`, `DETACH`, `RENAME` выполняются на одном сервере и не реплицируются: diff --git a/docs/ru/operations/utils/clickhouse-local.md b/docs/ru/operations/utils/clickhouse-local.md index 01e4de52c71..06053e15a2f 100644 --- a/docs/ru/operations/utils/clickhouse-local.md +++ b/docs/ru/operations/utils/clickhouse-local.md @@ -2,7 +2,7 @@ # clickhouse-local -Принимает на вход данные, которые можно представить в табличном виде и выполняет над ними операции, заданные на [языке запросов](../../query_language/queries.md#queries) ClickHouse. +Принимает на вход данные, которые можно представить в табличном виде и выполняет над ними операции, заданные на [языке запросов](../../query_language/index.md#queries) ClickHouse. `clickhouse-local` использует движок сервера ClickHouse, т.е. поддерживает все форматы данных и движки таблиц, с которыми работает ClickHouse, при этом для выполнения операций не требуется запущенный сервер. diff --git a/docs/ru/query_language/index.md b/docs/ru/query_language/index.md index 666616b6003..b4900ee1180 100644 --- a/docs/ru/query_language/index.md +++ b/docs/ru/query_language/index.md @@ -1,7 +1,7 @@ # Язык запросов -* [SELECT](select.md) -* [INSERT INTO](insert_into.md) -* [CREATE](create.md) -* [ALTER](alter.md) -* [Прочие виды запросов](misc.md) +* [SELECT](select.md#select) +* [INSERT INTO](insert_into.md#queries-insert) +* [CREATE](create.md#create-database) +* [ALTER](alter.md#query_language_queries_alter) +* [Прочие виды запросов](misc.md#miscellaneous-queries) From a98f7d381bbc9c12e3fd2989f6deee820d41217f Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 12:22:13 +0300 Subject: [PATCH 033/425] There is only table of contents left --- docs/{mkdocs_en.yml => toc_en.yml} | 0 docs/{mkdocs_ru.yml => toc_ru.yml} | 0 docs/tools/build.py | 2 +- docs/tools/concatenate.py | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename docs/{mkdocs_en.yml => toc_en.yml} (100%) rename docs/{mkdocs_ru.yml => toc_ru.yml} (100%) diff --git a/docs/mkdocs_en.yml b/docs/toc_en.yml similarity index 100% rename from docs/mkdocs_en.yml rename to docs/toc_en.yml diff --git a/docs/mkdocs_ru.yml b/docs/toc_ru.yml similarity index 100% rename from docs/mkdocs_ru.yml rename to docs/toc_ru.yml diff --git a/docs/tools/build.py b/docs/tools/build.py index 73ebe7aaa40..7e4ffe2c067 100755 --- a/docs/tools/build.py +++ b/docs/tools/build.py @@ -38,7 +38,7 @@ def autoremoved_file(path): def build_for_lang(lang, args): logging.info('Building %s docs' % lang) - config_path = os.path.join(args.docs_dir, 'mkdocs_%s.yml' % lang) + config_path = os.path.join(args.docs_dir, 'toc_%s.yml' % lang) try: theme_cfg = { diff --git a/docs/tools/concatenate.py b/docs/tools/concatenate.py index 5a10c536ced..0afa66d7adf 100755 --- a/docs/tools/concatenate.py +++ b/docs/tools/concatenate.py @@ -19,7 +19,7 @@ import os def concatenate(lang, docs_path, single_page_file): - proj_config = os.path.join(docs_path, 'mkdocs_%s.yml' % lang) + proj_config = os.path.join(docs_path, 'toc_%s.yml' % lang) lang_path = os.path.join(docs_path, lang) with open(proj_config) as cfg_file: From 2553eafa3af0e32684ad45c7da19d2e7ac411596 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 12:26:01 +0300 Subject: [PATCH 034/425] "Query language" is actually part of SQL abbreviation --- docs/en/query_language/index.md | 2 +- docs/ru/query_language/index.md | 2 +- docs/toc_en.yml | 2 +- docs/toc_ru.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/query_language/index.md b/docs/en/query_language/index.md index d9ff70fd69c..1be92bb33d0 100644 --- a/docs/en/query_language/index.md +++ b/docs/en/query_language/index.md @@ -1,4 +1,4 @@ -# Query language +# SQL dialect * [SELECT](select.md#select) * [INSERT INTO](insert_into.md#queries-insert) diff --git a/docs/ru/query_language/index.md b/docs/ru/query_language/index.md index b4900ee1180..28482aa6120 100644 --- a/docs/ru/query_language/index.md +++ b/docs/ru/query_language/index.md @@ -1,4 +1,4 @@ -# Язык запросов +# Диалект SQL * [SELECT](select.md#select) * [INSERT INTO](insert_into.md#queries-insert) diff --git a/docs/toc_en.yml b/docs/toc_en.yml index 90f55fb7e32..74c3b59decb 100644 --- a/docs/toc_en.yml +++ b/docs/toc_en.yml @@ -50,7 +50,7 @@ pages: - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' -- 'SQL query language': +- 'SQL dialect': - 'hidden': 'query_language/index.md' - 'SELECT': 'query_language/select.md' - 'INSERT INTO': 'query_language/insert_into.md' diff --git a/docs/toc_ru.yml b/docs/toc_ru.yml index 954a129f954..3d1d9da1e01 100644 --- a/docs/toc_ru.yml +++ b/docs/toc_ru.yml @@ -50,7 +50,7 @@ pages: - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' -- 'SQL язык запросов': +- 'SQL диалект': - 'hidden': 'query_language/index.md' - 'SELECT': 'query_language/select.md' - 'INSERT INTO': 'query_language/insert_into.md' From b9b6547de02f98427b319041b19abb77dfe07470 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 12:41:18 +0300 Subject: [PATCH 035/425] Change filename in README.md too --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 29aacdf96dd..d733c1a232d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ Basically ClickHouse uses "documentation as code" approach, so you can edit Markdown files in this folder from GitHub web interface or fork ClickHouse repository, edit, commit, push and open pull request. -At the moment documentation is bilingual in English and Russian, so it's better to try keeping languages in sync if you can, but it's not strictly required as there are people watching over this. If you add new article, you should also add it to `mkdocs_{en,ru}.yaml` file with pages index. +At the moment documentation is bilingual in English and Russian, so it's better to try keeping languages in sync if you can, but it's not strictly required as there are people watching over this. If you add new article, you should also add it to `toc_{en,ru}.yaml` file with pages index. Master branch is then asynchronously published to ClickHouse official website: From e4cb388a08b782aedda14c29e3888aa31af68acb Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 18 Jul 2018 12:43:40 +0300 Subject: [PATCH 036/425] fix mistype --- docs/en/query_language/select.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/query_language/select.md b/docs/en/query_language/select.md index 70df9020f57..1b457819342 100644 --- a/docs/en/query_language/select.md +++ b/docs/en/query_language/select.md @@ -1,6 +1,6 @@ # SELECT queries syntax -`SELECT` performs data retieval. +`SELECT` performs data retrieval. ```sql SELECT [DISTINCT] expr_list From 1f2c54c8afe004ed7b801521c88d35785c37477c Mon Sep 17 00:00:00 2001 From: alesapin Date: Wed, 18 Jul 2018 20:06:13 +0300 Subject: [PATCH 037/425] CLICKHOUSE-3842: Fix loadKeys method in dictionary library --- .../Dictionaries/LibraryDictionarySource.cpp | 35 +++++++++++-------- .../dictionary_library/dictionary_library.cpp | 22 +++--------- .../dictionary_library/dictionary_library_c.c | 26 ++++++++++++-- 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/dbms/src/Dictionaries/LibraryDictionarySource.cpp b/dbms/src/Dictionaries/LibraryDictionarySource.cpp index d9acef989c8..00a216686c0 100644 --- a/dbms/src/Dictionaries/LibraryDictionarySource.cpp +++ b/dbms/src/Dictionaries/LibraryDictionarySource.cpp @@ -208,25 +208,30 @@ BlockInputStreamPtr LibraryDictionarySource::loadKeys(const Columns & key_column { LOG_TRACE(log, "loadKeys " << toString() << " size = " << requested_rows.size()); - auto columns_holder = std::make_unique(key_columns.size()); - ClickHouseLibrary::CStrings columns_pass{ - static_cast(columns_holder.get()), key_columns.size()}; - size_t key_columns_n = 0; - for (auto & column : key_columns) + auto holder = std::make_unique(key_columns.size()); + std::vector> columnDataHolders; + for (size_t i = 0; i < key_columns.size(); ++i) { - columns_pass.data[key_columns_n] = column->getName().c_str(); - ++key_columns_n; - } - const ClickHouseLibrary::VectorUInt64 requested_rows_c{ - ext::bit_cast(requested_rows.data()), requested_rows.size()}; - void * data_ptr = nullptr; + auto cellHolder = std::make_unique(requested_rows.size()); + for (size_t j = 0; j < requested_rows.size(); ++j) + { + auto dataRef = key_columns[i]->getDataAt(requested_rows[j]); + cellHolder[j] = ClickHouseLibrary::Field{.data = static_cast(dataRef.data), .size = dataRef.size}; + } + holder[i] + = ClickHouseLibrary::Row{.data = static_cast(cellHolder.get()), .size = requested_rows.size()}; + columnDataHolders.push_back(std::move(cellHolder)); + } + + ClickHouseLibrary::Table requestCols{.data = static_cast(holder.get()), .size = key_columns.size()}; + + void * data_ptr = nullptr; /// Get function pointer before dataNew call because library->get may throw. - auto func_loadKeys - = library->getstrings), decltype(&columns_pass), decltype(&requested_rows_c))>( - "ClickHouseDictionary_v3_loadKeys"); + auto func_loadKeys = library->getstrings), decltype(&requestCols))>( + "ClickHouseDictionary_v3_loadKeys"); data_ptr = library->get("ClickHouseDictionary_v3_dataNew")(lib_data); - auto data = func_loadKeys(data_ptr, &settings->strings, &columns_pass, &requested_rows_c); + auto data = func_loadKeys(data_ptr, &settings->strings, &requestCols); auto block = dataToBlock(description.sample_block, data); SCOPE_EXIT(library->get("ClickHouseDictionary_v3_dataDelete")(lib_data, data_ptr)); return std::make_shared(block); diff --git a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp index 8e18abbe80f..59b75d0a26f 100644 --- a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp +++ b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library.cpp @@ -136,10 +136,7 @@ void * ClickHouseDictionary_v3_loadAll(void * data_ptr, ClickHouseLibrary::CStri return static_cast(&ptr->ctable); } -void * ClickHouseDictionary_v3_loadKeys(void * data_ptr, - ClickHouseLibrary::CStrings * settings, - ClickHouseLibrary::CStrings * columns, - const ClickHouseLibrary::VectorUInt64 * requested_rows) +void * ClickHouseDictionary_v3_loadKeys(void * data_ptr, ClickHouseLibrary::CStrings * settings, ClickHouseLibrary::Table * requested_keys) { auto ptr = static_cast(data_ptr); LOG(ptr->lib->log, "loadKeys lib call ptr=" << data_ptr << " => " << ptr); @@ -151,20 +148,11 @@ void * ClickHouseDictionary_v3_loadKeys(void * data_ptr, LOG(ptr->lib->log, "setting " << i << " :" << settings->data[i]); } } - if (columns) + if (requested_keys) { - LOG(ptr->lib->log, "columns passed:" << columns->size); - for (size_t i = 0; i < columns->size; ++i) - { - LOG(ptr->lib->log, "col " << i << " :" << columns->data[i]); - } - } - if (requested_rows) - { - LOG(ptr->lib->log, "requested_rows passed: " << requested_rows->size); - for (size_t i = 0; i < requested_rows->size; ++i) - { - LOG(ptr->lib->log, "id " << i << " :" << requested_rows->data[i]); + LOG(ptr->lib->log, "requested_keys columns passed: " << requested_keys->size); + for (size_t i = 0; i < requested_keys->size; ++i) { + LOG(ptr->lib->log, "requested_keys at column " << i << " passed: " << requested_keys->data[i].size); } } diff --git a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c index c3d5ba901d7..2a18b236485 100644 --- a/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c +++ b/dbms/tests/external_dictionaries/dictionary_library/dictionary_library_c.c @@ -30,6 +30,27 @@ typedef struct int someField; } DataHolder; +typedef struct +{ + const void * data; + uint64_t size; +} ClickHouseLibField; + +typedef struct +{ + const ClickHouseLibField * data; + uint64_t size; +} ClickHouseLibRow; + +typedef struct +{ + const ClickHouseLibRow * data; + uint64_t size; + uint64_t error_code; + const char * error_string; +} ClickHouseLibTable; + + #define LOG(logger, format, ...) \ do \ { \ @@ -54,11 +75,10 @@ void * ClickHouseDictionary_v3_loadAll(void * data_ptr, ClickHouseLibCStrings * return 0; } -void * ClickHouseDictionary_v3_loadKeys( - void * data_ptr, ClickHouseLibCStrings * settings, ClickHouseLibCStrings * columns, const ClickHouseLibVectorUInt64 * requested_rows) +void * ClickHouseDictionary_v3_loadKeys(void * data_ptr, ClickHouseLibCStrings * settings, ClickHouseLibTable* requested_keys) { LibHolder * lib = ((DataHolder *)(data_ptr))->lib; - LOG(lib->log, "loadKeys c lib call ptr=%p size=%" PRIu64, data_ptr, requested_rows->size); + LOG(lib->log, "loadKeys c lib call ptr=%p size=%" PRIu64, data_ptr, requested_keys->size); return 0; } From ba04b9dcb89e4c3aebc3c6fc5b0d5f49913575f9 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Wed, 18 Jul 2018 21:45:23 +0300 Subject: [PATCH 038/425] Functions for Nullable arguments. --- docs/mkdocs_ru.yml | 1 + docs/ru/data_types/array.md | 79 ++++- .../data_types/special_data_types/nothing.md | 2 +- docs/ru/functions/functions_for_nulls.md | 289 ++++++++++++++++++ docs/ru/functions/index.md | 7 + docs/ru/table_engines/mysql.md | 2 + 6 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 docs/ru/functions/functions_for_nulls.md diff --git a/docs/mkdocs_ru.yml b/docs/mkdocs_ru.yml index 2530d85d04c..029abf76f45 100644 --- a/docs/mkdocs_ru.yml +++ b/docs/mkdocs_ru.yml @@ -208,6 +208,7 @@ pages: - 'Функции для реализации оператора IN.': 'functions/in_functions.md' - 'Функция arrayJoin': 'functions/array_join.md' - 'Функции для работы с географическими координатами': 'functions/geo.md' + - 'Функции для работы с Nullable-агрументами': 'functions/functions_for_nulls.md' - 'Агрегатные функции': - 'Введение': 'agg_functions/index.md' diff --git a/docs/ru/data_types/array.md b/docs/ru/data_types/array.md index 00e708c9181..0e3b78a9688 100644 --- a/docs/ru/data_types/array.md +++ b/docs/ru/data_types/array.md @@ -2,5 +2,80 @@ # Array(T) -Массив из элементов типа T. Типом T может быть любой тип, в том числе, массив. -Многомерные массивы не рекомендуется использовать, так как их поддержка довольно слабая (например, многомерные массивы нельзя сохранить в таблицы с движком семейства MergeTree). +Массив из элементов типа `T`. + +`T` может любым, в том числе, массивом. Используйте многомерные массивы с осторожностью. ClickHouse поддерживает многомерные массивы ограниченно, например, их нельзя хранить в таблицах семейства `MergeTree`. + +## Создание массива + +Массив можно создать с помощью функции: + +``` +array(T) +``` + +Также можно использовать квадратные скобки + +``` +[] +``` + +Пример создания массива: +``` +:) SELECT array(1, 2) AS x, toTypeName(x) + +SELECT + [1, 2] AS x, + toTypeName(x) + +┌─x─────┬─toTypeName(array(1, 2))─┐ +│ [1,2] │ Array(UInt8) │ +└───────┴─────────────────────────┘ + +1 rows in set. Elapsed: 0.002 sec. + +:) SELECT [1, 2] AS x, toTypeName(x) + +SELECT + [1, 2] AS x, + toTypeName(x) + +┌─x─────┬─toTypeName([1, 2])─┐ +│ [1,2] │ Array(UInt8) │ +└───────┴────────────────────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + +## Особенности работы с типами данных + +При создании массива "на лету" ClickHouse автоматически определяет тип аргументов как тип, в котором можно хранить все перечисленные аргументы. Если среди аргументов есть [NULL](../query_language/syntax.md#null-literal), то тип элементов массива — [Nullable](nullable.md#data_type-nullable). + +Примеры автоматического определения типа данных: + +``` +:) SELECT array(1, 2, NULL) AS x, toTypeName(x) + +SELECT + [1, 2, NULL] AS x, + toTypeName(x) + +┌─x──────────┬─toTypeName(array(1, 2, NULL))─┐ +│ [1,2,NULL] │ Array(Nullable(UInt8)) │ +└────────────┴───────────────────────────────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + +Если попытаться создать массив из несовместимых типов данных, то ClickHouse выбросит исключение: + +``` +:) SELECT array(1, 'a') + +SELECT [1, 'a'] + +Received exception from server (version 1.1.54388): +Code: 386. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::Exception: There is no supertype for types UInt8, String because some of them are String/FixedString and some of them are not. + +0 rows in set. Elapsed: 0.246 sec. +``` diff --git a/docs/ru/data_types/special_data_types/nothing.md b/docs/ru/data_types/special_data_types/nothing.md index 43c3ff05840..b6c9ac9887a 100644 --- a/docs/ru/data_types/special_data_types/nothing.md +++ b/docs/ru/data_types/special_data_types/nothing.md @@ -4,7 +4,7 @@ Этот тип данных предназначен только для того, чтобы представлять [NULL](../../query_language/syntax.md#null-literal). -Невозможно создать значение типа `Nothing`, поэтому он используется там, где значение не подразумевается. Например, `NULL` записывается как `Nullable(Nothing)` ([Nullable](../../data_types/nullable.md#data_type-nullable) — это тип данных, позволяющий хранить `NULL` в таблицах). Также тип Nothing используется для обозначения пустых массивов: +Невозможно создать значение типа `Nothing`, поэтому он используется там, где значение не подразумевается. Например, `NULL` записывается как `Nullable(Nothing)` ([Nullable](../../data_types/nullable.md#data_type-nullable) — это тип данных, позволяющий хранить `NULL` в таблицах). Также тип `Nothing` используется для обозначения пустых массивов: ```bash :) SELECT toTypeName(Array()) diff --git a/docs/ru/functions/functions_for_nulls.md b/docs/ru/functions/functions_for_nulls.md new file mode 100644 index 00000000000..423c2f05746 --- /dev/null +++ b/docs/ru/functions/functions_for_nulls.md @@ -0,0 +1,289 @@ +# Функции для работы с Nullable-агрументами + +## isNull + +Проверяет является ли аргумент [NULL](../query_language/syntax.md#null-literal). + +``` +isNull(x) +``` + +**Параметры** + +- `x` — значение с не составным типом данных. + +**Возвращаемое значение** + +- `1`, если `x` — `NULL`. +- `0`, если `x` — не `NULL`. + +**Пример** + +Входная таблица + +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +│ 2 │ 3 │ +└───┴──────┘ +``` + +Запрос + +``` +:) SELECT x FROM t_null WHERE isNull(y) + +SELECT x +FROM t_null +WHERE isNull(y) + +┌─x─┐ +│ 1 │ +└───┘ + +1 rows in set. Elapsed: 0.010 sec. +``` + +## isNotNull + +Проверяет не является ли аргумент [NULL](../query_language/syntax.md#null-literal). + +``` +isNotNull(x) +``` + +**Параметры** + +- `x` — значение с не составным типом данных. + +**Возвращаемое значение** + +- `0`, если `x` — `NULL`. +- `1`, если `x` — не `NULL`. + +**Пример** + +Входная таблица + +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +│ 2 │ 3 │ +└───┴──────┘ +``` + +Запрос + +``` +:) SELECT x FROM t_null WHERE isNotNull(y) + +SELECT x +FROM t_null +WHERE isNotNull(y) + +┌─x─┐ +│ 2 │ +└───┘ + +1 rows in set. Elapsed: 0.010 sec. +``` + +## coalesce + +Последовательно проверяет являются ли переданные аргументы `NULL` и возвращает первый не `NULL`. + +``` +coalesce(x,...) +``` +**Параметры** + +- Произвольное количество параметров не составного типа. Все параметры должны быть совместимы по типу данных. + +**Возвращаемые значения** + +- Первый не `NULL` аргумент. +- `NULL`, если все аргументы — `NULL`. + +**Пример** + +Предположим, что у нас адресная книга, в которой может быть указано несколько способов связи с клиентом. + +``` +┌─name─────┬─mail─┬─phone─────┬──icq─┐ +│ client 1 │ ᴺᵁᴸᴸ │ 123-45-67 │ 123 │ +│ client 2 │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ +└──────────┴──────┴───────────┴──────┘ +``` + +Поля `mail` и `phone` имеют тип String, а поле `icq` — `UInt32`, его необходимо будет преобразовать в `String`. + +Получим из адресной книги первый доступный способ связаться с клиентом: + +``` +:) SELECT coalesce(mail, phone, CAST(icq,'Nullable(String)')) FROM aBook + +SELECT coalesce(mail, phone, CAST(icq, 'Nullable(String)')) +FROM aBook + +┌─name─────┬─coalesce(mail, phone, CAST(icq, 'Nullable(String)'))─┐ +│ client 1 │ 123-45-67 │ +│ client 2 │ ᴺᵁᴸᴸ │ +└──────────┴──────────────────────────────────────────────────────┘ + +2 rows in set. Elapsed: 0.006 sec. +``` + +## ifNull + +Возвращает альтернативное значение, если основной аргумент — `NULL`. + +``` +ifNull(x,alt) +``` + +**Параметры** + +- `x` — значение для проверки на `NULL`, +- `alt` — значение, которое функция вернёт, если `x` — `NULL`. + +**Возвращаемые значения** + +- Значение `x`, если `x` — не `NULL`. +- Значение `alt`, если `x` — `NULL`. + +**Пример** + +``` +SELECT ifNull('a', 'b') + +┌─ifNull('a', 'b')─┐ +│ a │ +└──────────────────┘ +``` +``` +SELECT ifNull(NULL, 'b') + +┌─ifNull(NULL, 'b')─┐ +│ b │ +└───────────────────┘ +``` + +## nullIf + +Возвращает `NULL`, если аргументы равны. + +``` +nullIf(x, y) +``` + +**Параметры** + +`x`, `y` — значения для сравнивания. Они должны быть совместимых типов, иначе ClickHouse сгенерирует исключение. + +**Возвращаемые значения** + +- `NULL`, если аргументы равны. +- Значение `x`, если аргументы не равны. + +**Пример** + +``` +SELECT nullIf(1, 1) + +┌─nullIf(1, 1)─┐ +│ ᴺᵁᴸᴸ │ +└──────────────┘ +``` +``` +SELECT nullIf(1, 2) + +┌─nullIf(1, 2)─┐ +│ 1 │ +└──────────────┘ +``` + +## assumeNotNull + +Приводит значение типа [Nullable](../data_types/nullable.md#data_type-nullable) к не `Nullable`, если значение не `NULL`. + +``` +assumeNotNull(x) +``` + +**Параметры** + +- `x` — значение. + +**Возвращаемые значения** + +- То же значение с не `Nullable` типом, если значение не `NULL`. +- Значение по умолчанию для не `Nullable` типа, если исходное значение — `NULL`. + +**Пример** + +Рассмотрим таблицу `t_null`. + +``` +SHOW CREATE TABLE t_null + +┌─statement─────────────────────────────────────────────────────────────────┐ +│ CREATE TABLE default.t_null ( x Int8, y Nullable(Int8)) ENGINE = TinyLog │ +└───────────────────────────────────────────────────────────────────────────┘ +``` +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +│ 2 │ 3 │ +└───┴──────┘ +``` + +Применим функцию `assumeNotNull` к столбцу `y`. + +``` +SELECT assumeNotNull(y) FROM t_null + +┌─assumeNotNull(y)─┐ +│ 0 │ +│ 3 │ +└──────────────────┘ +``` +``` +SELECT toTypeName(assumeNotNull(y)) FROM t_null + +┌─toTypeName(assumeNotNull(y))─┐ +│ Int8 │ +│ Int8 │ +└──────────────────────────────┘ +``` + +## toNullable + +Преобразует тип аргумента к `Nullable`. + +``` +toNullable(x) +``` + +**Параметры** + +- `x` — значение произвольного не составного типа. + +**Возвращаемое значение** + +- Входное значение с типом не `Nullable`. + +**Пример** + +``` +SELECT toTypeName(10) + +┌─toTypeName(10)─┐ +│ UInt8 │ +└────────────────┘ + +SELECT toTypeName(toNullable(10)) + +┌─toTypeName(toNullable(10))─┐ +│ Nullable(UInt8) │ +└────────────────────────────┘ +``` diff --git a/docs/ru/functions/index.md b/docs/ru/functions/index.md index c8e86b44327..870eccb24ab 100644 --- a/docs/ru/functions/index.md +++ b/docs/ru/functions/index.md @@ -27,6 +27,13 @@ Функции могут быть по-разному реализованы для константных и не константных аргументов (выполняется разный код). Но результат работы для константы и полноценного столбца, содержащего только одно такое же значение, должен совпадать. +## Обработка NULL + +Функции имеют следующие виды поведения: + +- Если хотя бы один из аргументов функции — `NULL`, то результат функции тоже `NULL`. +- Специальное поведение, указанное в описании каждой функции отдельно. В исходном коде ClickHouse такие функции можно определить по свойству `UseDefaultImplementationForNulls=false`. + ## Неизменяемость Функции не могут поменять значения своих аргументов - любые изменения возвращаются в качестве результата. Соответственно, от порядка записи функций в запросе, результат вычислений отдельных функций не зависит. diff --git a/docs/ru/table_engines/mysql.md b/docs/ru/table_engines/mysql.md index 5db09c25b71..484ac87726a 100644 --- a/docs/ru/table_engines/mysql.md +++ b/docs/ru/table_engines/mysql.md @@ -13,3 +13,5 @@ MySQL('host:port', 'database', 'table', 'user', 'password'); На данный момент простые условия `WHERE`, такие как `=, !=, >, >=, <, <=` будут выполняться на стороне сервера MySQL. Остальные условия и ограничение выборки `LIMIT` будут выполнены в ClickHouse только после выполнения запроса к MySQL. + +Движок `MySQL` не поддерживает тип данных [Nullable](../data_types/nullable.md#data_type-nullable), поэтому при чтении данных из таблиц MySQL `NULL` преобразуются в значения по умолчанию для заданного типа столбца, обычно это `0` или пустая строка. From d0d61e4ea4397760e1a418be49274748af2bc369 Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 19 Jul 2018 11:47:35 +0300 Subject: [PATCH 039/425] CLICKHOUSE-3842: Rename local variables --- .../Dictionaries/LibraryDictionarySource.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dbms/src/Dictionaries/LibraryDictionarySource.cpp b/dbms/src/Dictionaries/LibraryDictionarySource.cpp index 00a216686c0..eaedfa71704 100644 --- a/dbms/src/Dictionaries/LibraryDictionarySource.cpp +++ b/dbms/src/Dictionaries/LibraryDictionarySource.cpp @@ -209,29 +209,29 @@ BlockInputStreamPtr LibraryDictionarySource::loadKeys(const Columns & key_column LOG_TRACE(log, "loadKeys " << toString() << " size = " << requested_rows.size()); auto holder = std::make_unique(key_columns.size()); - std::vector> columnDataHolders; + std::vector> column_data_holders; for (size_t i = 0; i < key_columns.size(); ++i) { - auto cellHolder = std::make_unique(requested_rows.size()); + auto cell_holder = std::make_unique(requested_rows.size()); for (size_t j = 0; j < requested_rows.size(); ++j) { - auto dataRef = key_columns[i]->getDataAt(requested_rows[j]); - cellHolder[j] = ClickHouseLibrary::Field{.data = static_cast(dataRef.data), .size = dataRef.size}; + auto data_ref = key_columns[i]->getDataAt(requested_rows[j]); + cell_holder[j] = ClickHouseLibrary::Field{.data = static_cast(data_ref.data), .size = data_ref.size}; } holder[i] - = ClickHouseLibrary::Row{.data = static_cast(cellHolder.get()), .size = requested_rows.size()}; + = ClickHouseLibrary::Row{.data = static_cast(cell_holder.get()), .size = requested_rows.size()}; - columnDataHolders.push_back(std::move(cellHolder)); + column_data_holders.push_back(std::move(cell_holder)); } - ClickHouseLibrary::Table requestCols{.data = static_cast(holder.get()), .size = key_columns.size()}; + ClickHouseLibrary::Table request_cols{.data = static_cast(holder.get()), .size = key_columns.size()}; void * data_ptr = nullptr; /// Get function pointer before dataNew call because library->get may throw. - auto func_loadKeys = library->getstrings), decltype(&requestCols))>( + auto func_loadKeys = library->getstrings), decltype(&request_cols))>( "ClickHouseDictionary_v3_loadKeys"); data_ptr = library->get("ClickHouseDictionary_v3_dataNew")(lib_data); - auto data = func_loadKeys(data_ptr, &settings->strings, &requestCols); + auto data = func_loadKeys(data_ptr, &settings->strings, &request_cols); auto block = dataToBlock(description.sample_block, data); SCOPE_EXIT(library->get("ClickHouseDictionary_v3_dataDelete")(lib_data, data_ptr)); return std::make_shared(block); From 827af06912d1caa977d10588298480d784b00aa7 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 20 Jul 2018 00:49:52 +0300 Subject: [PATCH 040/425] s/formats\/interfaces/interfaces\/formats/g --- docs/redirects.txt | 48 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/redirects.txt b/docs/redirects.txt index 6471896d5fa..3a975a5f812 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -17,30 +17,30 @@ system_tables/system.replicas.md operations/system_tables.md system_tables/system.settings.md operations/system_tables.md system_tables/system.tables.md operations/system_tables.md system_tables/system.zookeeper.md operations/system_tables.md -formats/capnproto.md formats/interfaces.md -formats/csv.md formats/interfaces.md -formats/csvwithnames.md formats/interfaces.md -formats.md formats/interfaces.md -formats/json.md formats/interfaces.md -formats/jsoncompact.md formats/interfaces.md -formats/jsoneachrow.md formats/interfaces.md -formats/native.md formats/interfaces.md -formats/null.md formats/interfaces.md -formats/pretty.md formats/interfaces.md -formats/prettycompact.md formats/interfaces.md -formats/prettycompactmonoblock.md formats/interfaces.md -formats/prettynoescapes.md formats/interfaces.md -formats/prettyspace.md formats/interfaces.md -formats/rowbinary.md formats/interfaces.md -formats/tabseparated.md formats/interfaces.md -formats/tabseparatedraw.md formats/interfaces.md -formats/tabseparatedwithnames.md formats/interfaces.md -formats/tabseparatedwithnamesandtypes.md formats/interfaces.md -formats/tskv.md formats/interfaces.md -formats/values.md formats/interfaces.md -formats/vertical.md formats/interfaces.md -formats/verticalraw.md formats/interfaces.md -formats/xml.md formats/interfaces.md +formats/capnproto.md interfaces/formats.md +formats/csv.md interfaces/formats.md +formats/csvwithnames.md interfaces/formats.md +formats.md interfaces/formats.md +formats/json.md interfaces/formats.md +formats/jsoncompact.md interfaces/formats.md +formats/jsoneachrow.md interfaces/formats.md +formats/native.md interfaces/formats.md +formats/null.md interfaces/formats.md +formats/pretty.md interfaces/formats.md +formats/prettycompact.md interfaces/formats.md +formats/prettycompactmonoblock.md interfaces/formats.md +formats/prettynoescapes.md interfaces/formats.md +formats/prettyspace.md interfaces/formats.md +formats/rowbinary.md interfaces/formats.md +formats/tabseparated.md interfaces/formats.md +formats/tabseparatedraw.md interfaces/formats.md +formats/tabseparatedwithnames.md interfaces/formats.md +formats/tabseparatedwithnamesandtypes.md interfaces/formats.md +formats/tskv.md interfaces/formats.md +formats/values.md interfaces/formats.md +formats/vertical.md interfaces/formats.md +formats/verticalraw.md interfaces/formats.md +formats/xml.md interfaces/formats.md utils/clickhouse-copier.md operations/utils/clickhouse-copier.md utils/clickhouse-local.md operations/utils/clickhouse-local.md utils.md operations/utils.md From b09cb7a727344c371a4028b9a9676d68cd6bb8f0 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 20 Jul 2018 11:11:26 +0300 Subject: [PATCH 041/425] Remove extra clarification from header as it was too verbose, probably making it a bit more confusing --- docs/toc_en.yml | 2 +- docs/toc_ru.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/toc_en.yml b/docs/toc_en.yml index 74c3b59decb..5bf8f98af69 100644 --- a/docs/toc_en.yml +++ b/docs/toc_en.yml @@ -160,7 +160,7 @@ pages: - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md' - 'clickhouse-local': 'operations/utils/clickhouse-local.md' -- 'ClickHouse Development': +- 'Development': - 'hidden': 'development/index.md' - 'Overview of ClickHouse architecture': 'development/architecture.md' - 'How to build ClickHouse on Linux': 'development/build.md' diff --git a/docs/toc_ru.yml b/docs/toc_ru.yml index 3d1d9da1e01..2e8ea6f38b1 100644 --- a/docs/toc_ru.yml +++ b/docs/toc_ru.yml @@ -162,7 +162,7 @@ pages: - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md' - 'clickhouse-local': 'operations/utils/clickhouse-local.md' -- 'Разработка ClickHouse': +- 'Разработка': - 'hidden': 'development/index.md' - 'Overview of ClickHouse architecture': 'development/architecture.md' - 'Как собрать ClickHouse на Linux': 'development/build.md' From 716c65632451f8ecb9b7d63902bd2e6e41bad3c4 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 20 Jul 2018 11:12:26 +0300 Subject: [PATCH 042/425] Empty article was supposed to be hidden --- docs/toc_en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/toc_en.yml b/docs/toc_en.yml index 5bf8f98af69..cb5d71a4753 100644 --- a/docs/toc_en.yml +++ b/docs/toc_en.yml @@ -110,7 +110,7 @@ pages: - 'General syntax': 'query_language/syntax.md' - 'Operations': - - 'Operations': 'operations/index.md' + - 'hidden': 'operations/index.md' - 'Table engines': - 'Introduction': 'operations/table_engines/index.md' - 'MergeTree family': From 745622ce76709e6cbfa19477b444769c4694f704 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 20 Jul 2018 11:14:39 +0300 Subject: [PATCH 043/425] At least change incorrect title --- docs/en/operations/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/operations/index.md b/docs/en/operations/index.md index 0ff38af8086..1450754bc0f 100644 --- a/docs/en/operations/index.md +++ b/docs/en/operations/index.md @@ -1,2 +1,2 @@ -# Usage +# Operations From 7fbabbdee6aea34c2e353844df4c9af4d08f3566 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 20 Jul 2018 11:23:43 +0300 Subject: [PATCH 044/425] Move special links to the bottom of nav and slightly highlight them --- .../assets/stylesheets/custom.css | 5 +++++ .../mkdocs-material-theme/partials/nav.html | 22 +++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/tools/mkdocs-material-theme/assets/stylesheets/custom.css b/docs/tools/mkdocs-material-theme/assets/stylesheets/custom.css index a51d373c6d5..81000043005 100644 --- a/docs/tools/mkdocs-material-theme/assets/stylesheets/custom.css +++ b/docs/tools/mkdocs-material-theme/assets/stylesheets/custom.css @@ -128,3 +128,8 @@ h1, h2, h3, .md-logo { .md-hide { display: none; } + +#md-extra-nav { + background: #efefef; + padding-top: 0.5rem; +} diff --git a/docs/tools/mkdocs-material-theme/partials/nav.html b/docs/tools/mkdocs-material-theme/partials/nav.html index 9a5c4b3da09..c306ba1746a 100644 --- a/docs/tools/mkdocs-material-theme/partials/nav.html +++ b/docs/tools/mkdocs-material-theme/partials/nav.html @@ -3,7 +3,17 @@ {{ config.site_name }} + {% if not config.extra.single_page %}
    + {% for nav_item in nav %} + {% set path = "nav-" + loop.index | string %} + {% set level = 1 %} + {% include "partials/nav-item.html" %} + {% endfor %} +
+ {% endif %} + +
  • + {% if config.extra.lang == 'ru' %} + {% if config.extra.single_page %} + Многостраничная версия + {% else %} + Одностраничная версия + {% endif %} + {% else %} + {% if config.extra.single_page %} + Multi page version + {% else %} + Single page version + {% endif %} + {% endif %}
  • - + {% if config.extra.lang == 'ru' %} + Исходники ClickHouse + {% else %} + ClickHouse sources + {% endif %}
From 81b757bb05654a7fcca68279c2869c818cb60f72 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 25 Jul 2018 12:19:50 +0300 Subject: [PATCH 136/425] CLICKHOUSE-3858: get rid of more js workarounds for old docs build system + some fixes --- docs/tools/build.py | 1 - docs/tools/mkdocs-material-theme/base.html | 23 ------------------- .../partials/header.html | 20 +++++++++++++++- .../mkdocs-material-theme/partials/nav.html | 10 ++++---- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/docs/tools/build.py b/docs/tools/build.py index 1af08669c4f..4466fc71ce0 100755 --- a/docs/tools/build.py +++ b/docs/tools/build.py @@ -60,7 +60,6 @@ def build_for_lang(lang, args): 'static_templates': ['404.html'], 'extra': { 'single_page': False, - 'lang': lang, 'opposite_lang': 'en' if lang == 'ru' else 'ru', 'search': { 'language': 'en' if lang == 'en' else 'en, %s' % lang diff --git a/docs/tools/mkdocs-material-theme/base.html b/docs/tools/mkdocs-material-theme/base.html index 548f57c853c..97283c55078 100644 --- a/docs/tools/mkdocs-material-theme/base.html +++ b/docs/tools/mkdocs-material-theme/base.html @@ -224,34 +224,11 @@ } }); } - function drawLanguageSwitch() { - var url, text, title; - if (window.location.pathname.indexOf('/ru/') >= 0) { - url = window.location.pathname.replace('/ru/', '/en/'); - text = "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - ""; - title = "Switch to English" - } else { - url = window.location.pathname.replace('/en/', '/ru/'); - text = "\n" + - "\n" + - "\n" + - "\n" + - ""; - title = "Переключить на русский язык" - } - document.getElementById("md-language-switch").innerHTML = '' + text + ''; - } ready(function () { {% if config.extra.single_page and page.content %} document.getElementById("content").innerHTML = {{ page.content|tojson|safe }}; document.getElementsByClassName('md-footer')[0].style.display = 'block'; {% endif %} - drawLanguageSwitch(); app.initialize({ version: "{{ mkdocs_version }}", url: { diff --git a/docs/tools/mkdocs-material-theme/partials/header.html b/docs/tools/mkdocs-material-theme/partials/header.html index 9b81a53de8d..21b95950b88 100644 --- a/docs/tools/mkdocs-material-theme/partials/header.html +++ b/docs/tools/mkdocs-material-theme/partials/header.html @@ -40,9 +40,27 @@ {% endif %} {% endblock %}
- {% if config.repo_url %} + {% if page %}
+ {% if config.extra.lang == 'ru' %} + + + + + + + + + {% else %} + + + + + + + + {% endif %}
{% endif %} diff --git a/docs/tools/mkdocs-material-theme/partials/nav.html b/docs/tools/mkdocs-material-theme/partials/nav.html index d638c9f64d4..66366e6ad40 100644 --- a/docs/tools/mkdocs-material-theme/partials/nav.html +++ b/docs/tools/mkdocs-material-theme/partials/nav.html @@ -15,28 +15,30 @@ From 0b14512735bd3183891c6e35f3483bc87660d7a7 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 25 Jul 2018 12:21:38 +0300 Subject: [PATCH 137/425] lang has already been passed --- docs/tools/build.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/tools/build.py b/docs/tools/build.py index 4466fc71ce0..ff1551ed8d7 100755 --- a/docs/tools/build.py +++ b/docs/tools/build.py @@ -109,7 +109,6 @@ def build_single_page_version(lang, args, cfg): 'site_dir': temp, 'extra': { 'single_page': True, - 'lang': lang, 'opposite_lang': 'en' if lang == 'ru' else 'ru', 'search': { 'language': 'en, ru' From 121411fe1d426117983a24fa5499b5cdec4ef142 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Wed, 25 Jul 2018 12:28:20 +0300 Subject: [PATCH 138/425] Badge does not look well right after the list --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 905e6e5ba90..8cb9fa3379e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ClickHouse is an open-source column-oriented database management system that allows generating analytical data reports in real time. +[![Build Status](https://travis-ci.org/yandex/ClickHouse.svg?branch=master)](https://travis-ci.org/yandex/ClickHouse) + ## Useful links * [Official website](https://clickhouse.yandex/) has quick high-level overview of ClickHouse on main page. @@ -9,5 +11,3 @@ ClickHouse is an open-source column-oriented database management system that all * [Documentation](https://clickhouse.yandex/docs/en/) provides more in-depth information. * [Contacts](https://clickhouse.yandex/#contacts) can help to get your questions answered if there are any. - -[![Build Status](https://travis-ci.org/yandex/ClickHouse.svg?branch=master)](https://travis-ci.org/yandex/ClickHouse) From 15cc1cf91b2d50b6b980c2eb124530d222a8f300 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 25 Jul 2018 17:00:54 +0800 Subject: [PATCH 139/425] Fix integration test. without specifying errorlog, I got ``` E Logging trace to /var/log/clickhouse-server/clickhouse-server.log E Logging errors to clickhouse-server.err.log E Poco::Exception. Code: 1000, e.code() = 13, e.displayText() = Access to file denied: /clickhouse-server.err.log, e.what() = Access to file denied ``` --- dbms/tests/integration/helpers/cluster.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dbms/tests/integration/helpers/cluster.py b/dbms/tests/integration/helpers/cluster.py index 4242fa8fa62..d2c5f27bd4a 100644 --- a/dbms/tests/integration/helpers/cluster.py +++ b/dbms/tests/integration/helpers/cluster.py @@ -206,6 +206,7 @@ services: - server - --config-file=/etc/clickhouse-server/config.xml - --log-file=/var/log/clickhouse-server/clickhouse-server.log + - --errorlog-file=/var/log/clickhouse-server/clickhouse-server.err.log depends_on: {depends_on} ''' From 61059c3d9a9d43d250edeba5d516c18dbf5a198c Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 25 Jul 2018 14:29:26 +0300 Subject: [PATCH 140/425] Macos: allow build with mariadb-connector-c (#2715) * Try fix version generate * Macos: allow build with mariadb-connector-c --- libs/libmysqlxx/cmake/find_mysqlclient.cmake | 5 +++-- libs/libmysqlxx/src/Connection.cpp | 4 ++++ libs/libmysqlxx/src/Exception.cpp | 4 ++++ libs/libmysqlxx/src/Pool.cpp | 5 +++++ libs/libmysqlxx/src/Query.cpp | 4 ++++ libs/libmysqlxx/src/ResultBase.cpp | 4 ++++ libs/libmysqlxx/src/Row.cpp | 4 ++++ libs/libmysqlxx/src/StoreQueryResult.cpp | 4 ++++ libs/libmysqlxx/src/UseQueryResult.cpp | 4 ++++ 9 files changed, 36 insertions(+), 2 deletions(-) diff --git a/libs/libmysqlxx/cmake/find_mysqlclient.cmake b/libs/libmysqlxx/cmake/find_mysqlclient.cmake index 4b37aca436c..445512b7c06 100644 --- a/libs/libmysqlxx/cmake/find_mysqlclient.cmake +++ b/libs/libmysqlxx/cmake/find_mysqlclient.cmake @@ -5,6 +5,7 @@ if (ENABLE_MYSQL) "/usr/local/opt/mysql/lib" "/usr/local/lib" "/usr/local/lib64" + "/usr/local/lib/mariadb" # macos brew mariadb-connector-c "/usr/mysql/lib" "/usr/mysql/lib64" "/usr/lib" @@ -18,12 +19,12 @@ if (ENABLE_MYSQL) "/usr/local/include" "/usr/include") - find_path (MYSQL_INCLUDE_DIR NAMES mysql/mysql.h PATHS ${MYSQL_INCLUDE_PATHS} PATH_SUFFIXES mysql) + find_path (MYSQL_INCLUDE_DIR NAMES mysql/mysql.h mariadb/mysql.h PATHS ${MYSQL_INCLUDE_PATHS} PATH_SUFFIXES mysql) if (USE_STATIC_LIBRARIES) find_library (STATIC_MYSQLCLIENT_LIB NAMES mariadbclient mysqlclient PATHS ${MYSQL_LIB_PATHS} PATH_SUFFIXES mysql) else () - find_library (MYSQLCLIENT_LIBRARIES NAMES mariadbclient mysqlclient PATHS ${MYSQL_LIB_PATHS} PATH_SUFFIXES mysql) + find_library (MYSQLCLIENT_LIBRARIES NAMES mariadb mariadbclient mysqlclient PATHS ${MYSQL_LIB_PATHS} PATH_SUFFIXES mysql) endif () if (MYSQL_INCLUDE_DIR AND (STATIC_MYSQLCLIENT_LIB OR MYSQLCLIENT_LIBRARIES)) diff --git a/libs/libmysqlxx/src/Connection.cpp b/libs/libmysqlxx/src/Connection.cpp index 00eeed49616..6d9e7d5b673 100644 --- a/libs/libmysqlxx/src/Connection.cpp +++ b/libs/libmysqlxx/src/Connection.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include #include diff --git a/libs/libmysqlxx/src/Exception.cpp b/libs/libmysqlxx/src/Exception.cpp index 623f66d720b..dadd37e29e7 100644 --- a/libs/libmysqlxx/src/Exception.cpp +++ b/libs/libmysqlxx/src/Exception.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include diff --git a/libs/libmysqlxx/src/Pool.cpp b/libs/libmysqlxx/src/Pool.cpp index 33065df2bb5..fec612abcad 100644 --- a/libs/libmysqlxx/src/Pool.cpp +++ b/libs/libmysqlxx/src/Pool.cpp @@ -1,5 +1,10 @@ +#if __has_include() +#include +#include +#else #include #include +#endif #include diff --git a/libs/libmysqlxx/src/Query.cpp b/libs/libmysqlxx/src/Query.cpp index a9dcc3d768b..0bcafa04421 100644 --- a/libs/libmysqlxx/src/Query.cpp +++ b/libs/libmysqlxx/src/Query.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include #include diff --git a/libs/libmysqlxx/src/ResultBase.cpp b/libs/libmysqlxx/src/ResultBase.cpp index ccfe320bfdc..b03f92e38f2 100644 --- a/libs/libmysqlxx/src/ResultBase.cpp +++ b/libs/libmysqlxx/src/ResultBase.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include #include diff --git a/libs/libmysqlxx/src/Row.cpp b/libs/libmysqlxx/src/Row.cpp index a24e705f24a..e4baa681d69 100644 --- a/libs/libmysqlxx/src/Row.cpp +++ b/libs/libmysqlxx/src/Row.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include diff --git a/libs/libmysqlxx/src/StoreQueryResult.cpp b/libs/libmysqlxx/src/StoreQueryResult.cpp index 2c8d5d79fbe..05ad4299e17 100644 --- a/libs/libmysqlxx/src/StoreQueryResult.cpp +++ b/libs/libmysqlxx/src/StoreQueryResult.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include #include diff --git a/libs/libmysqlxx/src/UseQueryResult.cpp b/libs/libmysqlxx/src/UseQueryResult.cpp index a779a4282af..c5c52ffcb9c 100644 --- a/libs/libmysqlxx/src/UseQueryResult.cpp +++ b/libs/libmysqlxx/src/UseQueryResult.cpp @@ -1,4 +1,8 @@ +#if __has_include() +#include +#else #include +#endif #include #include From 867a3ebfae9aff93f94e0885bd20038845cc781d Mon Sep 17 00:00:00 2001 From: VadimPE Date: Wed, 25 Jul 2018 15:31:47 +0300 Subject: [PATCH 141/425] CLICKHOUSE-3837 fix mistakes --- dbms/src/Client/ConnectionPoolWithFailover.h | 3 +- .../ClusterProxy/SelectStreamFactory.cpp | 29 +++-------- .../ClusterProxy/SelectStreamFactory.h | 2 + .../evaluateConstantExpression.cpp | 5 +- dbms/src/Parsers/ASTSelectQuery.cpp | 48 ++++++++++++------- dbms/src/Parsers/ASTSelectQuery.h | 3 +- dbms/src/Storages/StorageDistributed.cpp | 43 +++++++---------- dbms/src/Storages/StorageDistributed.h | 9 ++-- .../Storages/getStructureOfRemoteTable.cpp | 4 +- .../TableFunctions/TableFunctionRemote.cpp | 34 ++++++++----- 10 files changed, 94 insertions(+), 86 deletions(-) diff --git a/dbms/src/Client/ConnectionPoolWithFailover.h b/dbms/src/Client/ConnectionPoolWithFailover.h index 63827e0e812..62ca75859ba 100644 --- a/dbms/src/Client/ConnectionPoolWithFailover.h +++ b/dbms/src/Client/ConnectionPoolWithFailover.h @@ -47,7 +47,8 @@ public: */ std::vector getMany(const Settings * settings, PoolMode pool_mode); - std::vector getManyForTableFunc(const Settings * settings, PoolMode pool_mode); + /// The same as getMany(), but return std::vector. + std::vector getManyForTableFunction(const Settings * settings, PoolMode pool_mode); using Base = PoolWithFailoverBase; using TryResult = Base::TryResult; diff --git a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp index b5200ce436e..eb1d54c457e 100644 --- a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp +++ b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp @@ -81,18 +81,12 @@ void SelectStreamFactory::createForShard( res.emplace_back(createLocalStream(query_ast, context, processed_stage)); }; - auto emplace_remote_stream_for_database = [&]() - { - auto stream = std::make_shared(shard_info.pool, query, header, context, nullptr, throttler, external_tables, processed_stage); - stream->setPoolMode(PoolMode::GET_MANY); - stream->setMainTable(main_table); - res.emplace_back(std::move(stream)); - }; - - auto emplace_remote_stream_for_func = [&]() + auto emplace_remote_stream = [&]() { auto stream = std::make_shared(shard_info.pool, query, header, context, nullptr, throttler, external_tables, processed_stage); stream->setPoolMode(PoolMode::GET_MANY); + if (!table_func_ptr) + stream->setMainTable(main_table); res.emplace_back(std::move(stream)); }; @@ -119,10 +113,7 @@ void SelectStreamFactory::createForShard( "There is no table " << main_table.database << "." << main_table.table << " on local replica of shard " << shard_info.shard_num << ", will try remote replicas."); - if (table_func_ptr) - emplace_remote_stream_for_func(); - else - emplace_remote_stream_for_database(); + emplace_remote_stream(); return; } else @@ -170,10 +161,7 @@ void SelectStreamFactory::createForShard( if (shard_info.pool) { /// If we cannot fallback, then we cannot use local replica. Try our luck with remote replicas. - if (table_func_ptr) - emplace_remote_stream_for_func(); - else - emplace_remote_stream_for_database(); + emplace_remote_stream(); return; } else @@ -203,7 +191,7 @@ void SelectStreamFactory::createForShard( try { if (table_func_ptr) - try_results = pool->getManyForTableFunc(&context.getSettingsRef(), PoolMode::GET_MANY); + try_results = pool->getManyForTableFunction(&context.getSettingsRef(), PoolMode::GET_MANY); else try_results = pool->getManyChecked(&context.getSettingsRef(), PoolMode::GET_MANY, main_table); } @@ -241,10 +229,7 @@ void SelectStreamFactory::createForShard( res.emplace_back(std::make_shared("LazyShardWithLocalReplica", header, lazily_create_stream)); } else - if (table_func_ptr) - emplace_remote_stream_for_func(); - else - emplace_remote_stream_for_database(); + emplace_remote_stream(); } } diff --git a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h index d3989d95279..38dabf82dcc 100644 --- a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h +++ b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h @@ -13,12 +13,14 @@ namespace ClusterProxy class SelectStreamFactory final : public IStreamFactory { public: + /// Database in a query. SelectStreamFactory( const Block & header_, QueryProcessingStage::Enum processed_stage_, QualifiedTableName main_table_, const Tables & external_tables); + /// TableFunction in a query. SelectStreamFactory( const Block & header_, QueryProcessingStage::Enum processed_stage_, diff --git a/dbms/src/Interpreters/evaluateConstantExpression.cpp b/dbms/src/Interpreters/evaluateConstantExpression.cpp index 56a090942c7..6dcff35e6a4 100644 --- a/dbms/src/Interpreters/evaluateConstantExpression.cpp +++ b/dbms/src/Interpreters/evaluateConstantExpression.cpp @@ -53,12 +53,15 @@ std::pair> evaluateConstantExpression(co ASTPtr evaluateConstantExpressionAsLiteral(const ASTPtr & node, const Context & context) -{ +{ + /// Branch with string in qery. if (typeid_cast(node.get())) return node; + /// Branch with TableFunction in query. if (auto table_func_ptr = typeid_cast(node.get())) if (TableFunctionFactory::instance().isTableFunctionName(table_func_ptr->name)) + return node; return std::make_shared(evaluateConstantExpression(node, context).first); diff --git a/dbms/src/Parsers/ASTSelectQuery.cpp b/dbms/src/Parsers/ASTSelectQuery.cpp index 06f955c7559..8bb5f2488d8 100644 --- a/dbms/src/Parsers/ASTSelectQuery.cpp +++ b/dbms/src/Parsers/ASTSelectQuery.cpp @@ -356,7 +356,7 @@ void ASTSelectQuery::setDatabaseIfNeeded(const String & database_name) } -void ASTSelectQuery::replaceDatabaseAndTable(const String & database_name, const String & table_name, ASTPtr table_function_ptr) +void ASTSelectQuery::replaceDatabaseAndTable(const String & database_name, const String & table_name) { ASTTableExpression * table_expression = getFirstTableExpression(*this); @@ -373,26 +373,42 @@ void ASTSelectQuery::replaceDatabaseAndTable(const String & database_name, const table_expression = table_expr.get(); } - if (table_function_ptr) { - table_expression->table_function = table_function_ptr; - table_expression->database_and_table_name = nullptr; + ASTPtr table = std::make_shared(table_name, ASTIdentifier::Table); + + if (!database_name.empty()) + { + ASTPtr database = std::make_shared(database_name, ASTIdentifier::Database); + + table_expression->database_and_table_name = std::make_shared(database_name + "." + table_name, ASTIdentifier::Table); + table_expression->database_and_table_name->children = {database, table}; } else { - ASTPtr table = std::make_shared(table_name, ASTIdentifier::Table); - if (!database_name.empty()) - { - ASTPtr database = std::make_shared(database_name, ASTIdentifier::Database); - - table_expression->database_and_table_name = std::make_shared(database_name + "." + table_name, ASTIdentifier::Table); - table_expression->database_and_table_name->children = {database, table}; - } - else - { - table_expression->database_and_table_name = std::make_shared(table_name, ASTIdentifier::Table); - } + table_expression->database_and_table_name = std::make_shared(table_name, ASTIdentifier::Table); } } + +void ASTSelectQuery::addTableFunction(ASTPtr & table_function_ptr) +{ + ASTTableExpression * table_expression = getFirstTableExpression(*this); + + if (!table_expression) + { + auto tables_list = std::make_shared(); + auto element = std::make_shared(); + auto table_expr = std::make_shared(); + element->table_expression = table_expr; + element->children.emplace_back(table_expr); + tables_list->children.emplace_back(element); + tables = tables_list; + children.emplace_back(tables_list); + table_expression = table_expr.get(); + } + + table_expression->table_function = table_function_ptr; + table_expression->database_and_table_name = nullptr; +} + }; diff --git a/dbms/src/Parsers/ASTSelectQuery.h b/dbms/src/Parsers/ASTSelectQuery.h index 1191bb2c4ff..91d8d52172c 100644 --- a/dbms/src/Parsers/ASTSelectQuery.h +++ b/dbms/src/Parsers/ASTSelectQuery.h @@ -46,7 +46,8 @@ public: bool array_join_is_left() const; bool final() const; void setDatabaseIfNeeded(const String & database_name); - void replaceDatabaseAndTable(const String & database_name, const String & table_name, ASTPtr table_function_name = nullptr); + void replaceDatabaseAndTable(const String & database_name, const String & table_name); + void addTableFunction(ASTPtr & table_function_ptr); protected: void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 4569c12ee56..937b2d02b83 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -65,12 +65,15 @@ namespace ErrorCodes namespace { -/// select query has database and table names as AST pointers -/// Creates a copy of query, changes database and table names. +/// select query has database, table and table function names as AST pointers +/// Creates a copy of query, changes database, table and table function names. ASTPtr rewriteSelectQuery(const ASTPtr & query, const std::string & database, const std::string & table, ASTPtr table_function_ptr = nullptr) { auto modified_query_ast = query->clone(); - typeid_cast(*modified_query_ast).replaceDatabaseAndTable(database, table, table_function_ptr); + if (table_function_ptr) + typeid_cast(*modified_query_ast).addTableFunction(table_function_ptr); + else + typeid_cast(*modified_query_ast).replaceDatabaseAndTable(database, table); return modified_query_ast; } @@ -154,7 +157,7 @@ StorageDistributed::StorageDistributed( bool attach) : IStorage{columns_}, table_name(table_name_), - remote_database(remote_database_), remote_table(remote_table_), remote_table_function_ptr(nullptr), + remote_database(remote_database_), remote_table(remote_table_), context(context_), cluster_name(context.getMacros()->expand(cluster_name_)), has_sharding_key(sharding_key_), sharding_key_expr(sharding_key_ ? ExpressionAnalyzer(sharding_key_, context, nullptr, getColumns().getAllPhysical()).getActions(false) : nullptr), sharding_key_column_name(sharding_key_ ? sharding_key_->getColumnName() : String{}), @@ -174,15 +177,13 @@ StorageDistributed::StorageDistributed( const String & database_name, const String & table_name_, const ColumnsDescription & columns_, - const String & remote_database_, - const String & remote_table_, ASTPtr remote_table_function_ptr_, const String & cluster_name_, const Context & context_, const ASTPtr & sharding_key_, const String & data_path_, bool attach) - : StorageDistributed(database_name, table_name_, columns_, remote_database_, remote_table_, cluster_name_, context_, sharding_key_, data_path_, attach) + : StorageDistributed(database_name, table_name_, columns_, String{}, String{}, cluster_name_, context_, sharding_key_, data_path_, attach) { remote_table_function_ptr = remote_table_function_ptr_; } @@ -208,14 +209,12 @@ StoragePtr StorageDistributed::createWithOwnCluster( StoragePtr StorageDistributed::createWithOwnCluster( const std::string & table_name_, const ColumnsDescription & columns_, - const String & remote_database_, /// database on remote servers. - const String & remote_table_, /// The name of the table on the remote servers. - ASTPtr remote_table_function_ptr_, /// Table function ptr. + ASTPtr & remote_table_function_ptr_, ClusterPtr & owned_cluster_, const Context & context_) { auto res = ext::shared_ptr_helper::create( - String{}, table_name_, columns_, remote_database_, remote_table_, remote_table_function_ptr_, String{}, context_, ASTPtr(), String(), false); + String{}, table_name_, columns_, remote_table_function_ptr_, String{}, context_, ASTPtr(), String(), false); res->owned_cluster = owned_cluster_; @@ -249,23 +248,17 @@ BlockInputStreams StorageDistributed::read( const auto & modified_query_ast = rewriteSelectQuery( query_info.query, remote_database, remote_table, remote_table_function_ptr); - - Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, Names{}, processed_stage).getSampleBlock()); + + Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, {}, processed_stage).getSampleBlock()); - if (remote_table_function_ptr) - { - ClusterProxy::SelectStreamFactory select_stream_factory( - header, processed_stage, remote_table_function_ptr, context.getExternalTables()); - return ClusterProxy::executeQuery( - select_stream_factory, cluster, modified_query_ast, context, settings); - } - else - { - ClusterProxy::SelectStreamFactory select_stream_factory( + ClusterProxy::SelectStreamFactory select_stream_factory = remote_table_function_ptr ? + ClusterProxy::SelectStreamFactory( + header, processed_stage, remote_table_function_ptr, context.getExternalTables()) + : ClusterProxy::SelectStreamFactory( header, processed_stage, QualifiedTableName{remote_database, remote_table}, context.getExternalTables()); - return ClusterProxy::executeQuery( + + return ClusterProxy::executeQuery( select_stream_factory, cluster, modified_query_ast, context, settings); - } } diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 657e03bf636..dda56bb3312 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -44,9 +45,7 @@ public: static StoragePtr createWithOwnCluster( const std::string & table_name_, const ColumnsDescription & columns_, - const String & remote_database_, /// database on remote servers. - const String & remote_table_, /// The name of the table on the remote servers. - ASTPtr remote_table_function_ptr_, /// Table function ptr. + ASTPtr & remote_table_function_ptr_, /// Table function ptr. ClusterPtr & owned_cluster_, const Context & context_); @@ -156,13 +155,11 @@ protected: const ASTPtr & sharding_key_, const String & data_path_, bool attach); - + StorageDistributed( const String & database_name, const String & table_name_, const ColumnsDescription & columns_, - const String & remote_database_, - const String & remote_table_, ASTPtr remote_table_function_ptr_, const String & cluster_name_, const Context & context_, diff --git a/dbms/src/Storages/getStructureOfRemoteTable.cpp b/dbms/src/Storages/getStructureOfRemoteTable.cpp index ac92f72a063..37cc036c367 100644 --- a/dbms/src/Storages/getStructureOfRemoteTable.cpp +++ b/dbms/src/Storages/getStructureOfRemoteTable.cpp @@ -40,7 +40,7 @@ ColumnsDescription getStructureOfRemoteTable( return TableFunctionFactory::instance().get(table_function->name, context)->execute(table_func_ptr, context)->getColumns(); } - auto table_func_name = table_func_ptr->getAliasOrColumnName(); + auto table_func_name = queryToString(table_func_ptr); query = "DESC TABLE " + table_func_name; } else @@ -63,7 +63,7 @@ ColumnsDescription getStructureOfRemoteTable( const DataTypeFactory & data_type_factory = DataTypeFactory::instance(); ParserExpression expr_parser; - + while (Block current = input->read()) { ColumnPtr name = current.getByName("name").column; diff --git a/dbms/src/TableFunctions/TableFunctionRemote.cpp b/dbms/src/TableFunctions/TableFunctionRemote.cpp index 0310f9287e9..128070fb5f1 100644 --- a/dbms/src/TableFunctions/TableFunctionRemote.cpp +++ b/dbms/src/TableFunctions/TableFunctionRemote.cpp @@ -196,9 +196,9 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C String cluster_name; String cluster_description; - String remote_database = ""; - String remote_table = ""; - ASTPtr remote_table_function_ptr = nullptr; + String remote_database; + String remote_table; + ASTPtr remote_table_function_ptr; String username; String password; @@ -232,7 +232,7 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context); - auto table_function = static_cast(args[arg_num].get()); + const auto table_function = static_cast(args[arg_num].get()); if (TableFunctionFactory::instance().isTableFunctionName(table_function->name)) { @@ -314,14 +314,24 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C cluster = std::make_shared(context.getSettings(), names, username, password, context.getTCPPort(), false); } - auto res = StorageDistributed::createWithOwnCluster( - getName(), - getStructureOfRemoteTable(*cluster, remote_database, remote_table, context, remote_table_function_ptr), - remote_database, - remote_table, - remote_table_function_ptr, - cluster, - context); + auto structure_remote_table = getStructureOfRemoteTable(*cluster, remote_database, remote_table, context, remote_table_function_ptr); + + StoragePtr res = remote_table_function_ptr ? + res = StorageDistributed::createWithOwnCluster( + getName(), + structure_remote_table, + remote_table_function_ptr, + cluster, + context) + + : res = StorageDistributed::createWithOwnCluster( + getName(), + structure_remote_table, + remote_database, + remote_table, + cluster, + context); + res->startup(); return res; } From 1b078736698d8fde222a5d5b2abede347adf0481 Mon Sep 17 00:00:00 2001 From: VadimPE Date: Wed, 25 Jul 2018 15:53:38 +0300 Subject: [PATCH 142/425] CLICKHOUSE-3837 fix --- dbms/src/Storages/StorageDistributed.cpp | 2 +- dbms/src/Storages/getStructureOfRemoteTable.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 937b2d02b83..66df474509e 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -249,7 +249,7 @@ BlockInputStreams StorageDistributed::read( const auto & modified_query_ast = rewriteSelectQuery( query_info.query, remote_database, remote_table, remote_table_function_ptr); - Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, {}, processed_stage).getSampleBlock()); + Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, String{}, processed_stage).getSampleBlock()); ClusterProxy::SelectStreamFactory select_stream_factory = remote_table_function_ptr ? ClusterProxy::SelectStreamFactory( diff --git a/dbms/src/Storages/getStructureOfRemoteTable.h b/dbms/src/Storages/getStructureOfRemoteTable.h index f537fa9bd5a..9f1769a7096 100644 --- a/dbms/src/Storages/getStructureOfRemoteTable.h +++ b/dbms/src/Storages/getStructureOfRemoteTable.h @@ -2,6 +2,7 @@ #include #include +#include namespace DB From 1d5d097b0d500b98ce9a8fe8332b53b373d0a580 Mon Sep 17 00:00:00 2001 From: VadimPE Date: Wed, 25 Jul 2018 16:16:36 +0300 Subject: [PATCH 143/425] CLICKHOUSE-3837 fix build --- dbms/src/Client/ConnectionPoolWithFailover.cpp | 2 +- dbms/src/Storages/StorageDistributed.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Client/ConnectionPoolWithFailover.cpp b/dbms/src/Client/ConnectionPoolWithFailover.cpp index 56efc1f90be..a311dac95b1 100644 --- a/dbms/src/Client/ConnectionPoolWithFailover.cpp +++ b/dbms/src/Client/ConnectionPoolWithFailover.cpp @@ -83,7 +83,7 @@ std::vector ConnectionPoolWithFailover::getMany(const Se return entries; } -std::vector ConnectionPoolWithFailover::getManyForTableFunc(const Settings * settings, PoolMode pool_mode) +std::vector ConnectionPoolWithFailover::getManyForTableFunction(const Settings * settings, PoolMode pool_mode) { TryGetEntryFunc try_get_entry = [&](NestedPool & pool, std::string & fail_message) { diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 66df474509e..5805ea439f3 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -249,7 +249,7 @@ BlockInputStreams StorageDistributed::read( const auto & modified_query_ast = rewriteSelectQuery( query_info.query, remote_database, remote_table, remote_table_function_ptr); - Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, String{}, processed_stage).getSampleBlock()); + Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, Names{}, processed_stage).getSampleBlock()); ClusterProxy::SelectStreamFactory select_stream_factory = remote_table_function_ptr ? ClusterProxy::SelectStreamFactory( From f88f68db097c3590326eb5874c3c1f7036393e90 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 25 Jul 2018 18:27:31 +0300 Subject: [PATCH 144/425] Macos: fix include for mysql, use mariadb-connector-c in docs (#2717) * Macos: fix mysql link * Macos: Fix mysql include * doc --- docs/en/development/build_osx.md | 2 +- libs/libmysqlxx/CMakeLists.txt | 2 +- libs/libmysqlxx/cmake/find_mysqlclient.cmake | 4 ++++ utils/build/build_macos.sh | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/en/development/build_osx.md b/docs/en/development/build_osx.md index 46ce91b3b9d..b54fd7ac32c 100644 --- a/docs/en/development/build_osx.md +++ b/docs/en/development/build_osx.md @@ -12,7 +12,7 @@ With appropriate changes, it should also work on any other Linux distribution. ## Install required compilers, tools, and libraries ```bash -brew install cmake ninja gcc icu4c mysql openssl unixodbc libtool gettext readline +brew install cmake ninja gcc icu4c mariadb-connector-c openssl unixodbc libtool gettext readline ``` ## Checkout ClickHouse sources diff --git a/libs/libmysqlxx/CMakeLists.txt b/libs/libmysqlxx/CMakeLists.txt index cd80a7b9b24..95c1c44c315 100644 --- a/libs/libmysqlxx/CMakeLists.txt +++ b/libs/libmysqlxx/CMakeLists.txt @@ -37,7 +37,7 @@ endif () if (APPLE) find_library (ICONV_LIBRARY iconv) - set (MYSQLCLIENT_LIBRARIES ${STATIC_MYSQLCLIENT_LIB} ${ICONV_LIBRARY}) + set (MYSQLCLIENT_LIBRARIES ${MYSQLCLIENT_LIBRARIES} ${STATIC_MYSQLCLIENT_LIB} ${ICONV_LIBRARY}) elseif (USE_STATIC_LIBRARIES AND STATIC_MYSQLCLIENT_LIB) set (MYSQLCLIENT_LIB ${CMAKE_CURRENT_BINARY_DIR}/libmysqlclient.a) add_custom_command ( diff --git a/libs/libmysqlxx/cmake/find_mysqlclient.cmake b/libs/libmysqlxx/cmake/find_mysqlclient.cmake index 445512b7c06..d019703e876 100644 --- a/libs/libmysqlxx/cmake/find_mysqlclient.cmake +++ b/libs/libmysqlxx/cmake/find_mysqlclient.cmake @@ -30,6 +30,10 @@ if (ENABLE_MYSQL) if (MYSQL_INCLUDE_DIR AND (STATIC_MYSQLCLIENT_LIB OR MYSQLCLIENT_LIBRARIES)) set (USE_MYSQL 1) set (MYSQLXX_LIBRARY mysqlxx) + if (APPLE) + # /usr/local/include/mysql/mysql_com.h:1011:10: fatal error: mysql/udf_registration_types.h: No such file or directory + set(MYSQL_INCLUDE_DIR ${MYSQL_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR}/mysql) + endif () endif () endif () diff --git a/utils/build/build_macos.sh b/utils/build/build_macos.sh index 4ca50e2d78c..462dd3e528e 100755 --- a/utils/build/build_macos.sh +++ b/utils/build/build_macos.sh @@ -12,7 +12,7 @@ fi ## Install required compilers, tools, libraries -brew install cmake gcc icu4c mysql openssl unixodbc libtool gettext readline +brew install cmake gcc icu4c mariadb-connector-c openssl unixodbc libtool gettext readline ## Checkout ClickHouse sources From 0965f991b3377316b511914eda8466de4bcb9d63 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Wed, 18 Jul 2018 13:22:01 +0800 Subject: [PATCH 145/425] Add row_delimiter argument to StorageKafka. There are common cases where a message doesn't end with a row delimiter. This patch allows specifying a row_delimiter char to compensate that. https://github.com/yandex/ClickHouse/issues/2298 --- dbms/src/Storages/StorageKafka.cpp | 76 ++++++++++++++----- dbms/src/Storages/StorageKafka.h | 5 +- dbms/tests/integration/helpers/cluster.py | 27 +++++-- .../helpers/docker_compose_kafka.yml | 24 ++++++ .../test_storage_kafka/__init__.py | 0 .../test_storage_kafka/configs/kafka.xml | 5 ++ .../integration/test_storage_kafka/test.py | 53 +++++++++++++ .../test_kafka_json.reference | 50 ++++++++++++ 8 files changed, 216 insertions(+), 24 deletions(-) create mode 100644 dbms/tests/integration/helpers/docker_compose_kafka.yml create mode 100644 dbms/tests/integration/test_storage_kafka/__init__.py create mode 100644 dbms/tests/integration/test_storage_kafka/configs/kafka.xml create mode 100644 dbms/tests/integration/test_storage_kafka/test.py create mode 100644 dbms/tests/integration/test_storage_kafka/test_kafka_json.reference diff --git a/dbms/src/Storages/StorageKafka.cpp b/dbms/src/Storages/StorageKafka.cpp index a9666bab22c..7823dfdd65a 100644 --- a/dbms/src/Storages/StorageKafka.cpp +++ b/dbms/src/Storages/StorageKafka.cpp @@ -62,12 +62,19 @@ class ReadBufferFromKafkaConsumer : public ReadBuffer { rd_kafka_t * consumer; rd_kafka_message_t * current; + bool current_pending; Poco::Logger * log; size_t read_messages; + char row_delimiter; bool nextImpl() override { - reset(); + if (current_pending) + { + BufferBase::set(reinterpret_cast(current->payload), current->len, 0); + current_pending = false; + return true; + } // Process next buffered message rd_kafka_message_t * msg = rd_kafka_consumer_poll(consumer, READ_POLL_MS); @@ -88,13 +95,24 @@ class ReadBufferFromKafkaConsumer : public ReadBuffer rd_kafka_message_destroy(msg); return nextImpl(); } + ++read_messages; + + // Now we've received a new message. Check if we need to produce a delimiter + if (row_delimiter != '\0' && current != nullptr) + { + BufferBase::set(&row_delimiter, 1, 0); + reset(); + current = msg; + current_pending = true; + return true; + } // Consume message and mark the topic/partition offset - // The offsets will be committed in the insertSuffix() method after the block is completed - // If an exception is thrown before that would occur, the client will rejoin without comitting offsets - BufferBase::set(reinterpret_cast(msg->payload), msg->len, 0); + // The offsets will be committed in the readSuffix() method after the block is completed + // If an exception is thrown before that would occur, the client will rejoin without committing offsets + reset(); current = msg; - ++read_messages; + BufferBase::set(reinterpret_cast(current->payload), current->len, 0); return true; } @@ -108,8 +126,11 @@ class ReadBufferFromKafkaConsumer : public ReadBuffer } public: - ReadBufferFromKafkaConsumer(rd_kafka_t * consumer_, Poco::Logger * log_) - : ReadBuffer(nullptr, 0), consumer(consumer_), current(nullptr), log(log_), read_messages(0) {} + ReadBufferFromKafkaConsumer(rd_kafka_t * consumer_, Poco::Logger * log_, char row_delimiter_) + : ReadBuffer(nullptr, 0), consumer(consumer_), current(nullptr), + current_pending(false), log(log_), read_messages(0), row_delimiter(row_delimiter_) { + LOG_TRACE(log, "row delimiter is :" << row_delimiter); + } ~ReadBufferFromKafkaConsumer() { reset(); } @@ -143,7 +164,7 @@ public: // Create a formatted reader on Kafka messages LOG_TRACE(storage.log, "Creating formatted reader"); - read_buf = std::make_unique(consumer->stream, storage.log); + read_buf = std::make_unique(consumer->stream, storage.log, storage.row_delimiter); reader = FormatFactory::instance().getInput(storage.format_name, *read_buf, storage.getSampleBlock(), context, max_block_size); } @@ -226,13 +247,14 @@ StorageKafka::StorageKafka( Context & context_, const ColumnsDescription & columns_, const String & brokers_, const String & group_, const Names & topics_, - const String & format_name_, const String & schema_name_, size_t num_consumers_) + const String & format_name_, char row_delimiter_, const String & schema_name_, size_t num_consumers_) : IStorage{columns_}, table_name(table_name_), database_name(database_name_), context(context_), topics(context.getMacros()->expand(topics_)), brokers(context.getMacros()->expand(brokers_)), group(context.getMacros()->expand(group_)), format_name(context.getMacros()->expand(format_name_)), + row_delimiter(row_delimiter_), schema_name(context.getMacros()->expand(schema_name_)), num_consumers(num_consumers_), log(&Logger::get("StorageKafka (" + table_name_ + ")")), semaphore(0, num_consumers_), mutex(), consumers(), event_update() @@ -552,10 +574,10 @@ void registerStorageKafka(StorageFactory & factory) * - Schema (optional, if the format supports it) */ - if (engine_args.size() < 3 || engine_args.size() > 6) + if (engine_args.size() < 3 || engine_args.size() > 7) throw Exception( - "Storage Kafka requires 3-6 parameters" - " - Kafka broker list, list of topics to consume, consumer group ID, message format, schema, number of consumers", + "Storage Kafka requires 3-7 parameters" + " - Kafka broker list, list of topics to consume, consumer group ID, message format, row delimiter, schema, number of consumers", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); String brokers; @@ -569,13 +591,33 @@ void registerStorageKafka(StorageFactory & factory) engine_args[2] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[2], args.local_context); engine_args[3] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[3], args.local_context); - // Parse format schema if supported (optional) - String schema; + // Parse row delimiter (optional) + char row_delimiter = '\0'; if (engine_args.size() >= 5) { engine_args[4] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[4], args.local_context); auto ast = typeid_cast(engine_args[4].get()); + String arg; + if (ast && ast->value.getType() == Field::Types::String) + arg = safeGet(ast->value); + else + throw Exception("Row delimiter must be a char", ErrorCodes::BAD_ARGUMENTS); + if (arg.size() > 1) + throw Exception("Row delimiter must be a char", ErrorCodes::BAD_ARGUMENTS); + else if (arg.size() == 0) + row_delimiter = '\0'; + else + row_delimiter = arg[0]; + } + + // Parse format schema if supported (optional) + String schema; + if (engine_args.size() >= 6) + { + engine_args[5] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[4], args.local_context); + + auto ast = typeid_cast(engine_args[5].get()); if (ast && ast->value.getType() == Field::Types::String) schema = safeGet(ast->value); else @@ -584,9 +626,9 @@ void registerStorageKafka(StorageFactory & factory) // Parse number of consumers (optional) UInt64 num_consumers = 1; - if (engine_args.size() >= 6) + if (engine_args.size() >= 7) { - auto ast = typeid_cast(engine_args[5].get()); + auto ast = typeid_cast(engine_args[6].get()); if (ast && ast->value.getType() == Field::Types::UInt64) num_consumers = safeGet(ast->value); else @@ -613,7 +655,7 @@ void registerStorageKafka(StorageFactory & factory) return StorageKafka::create( args.table_name, args.database_name, args.context, args.columns, - brokers, group, topics, format, schema, num_consumers); + brokers, group, topics, format, row_delimiter, schema, num_consumers); }); } diff --git a/dbms/src/Storages/StorageKafka.h b/dbms/src/Storages/StorageKafka.h index 45530517e94..9652d1d6a46 100644 --- a/dbms/src/Storages/StorageKafka.h +++ b/dbms/src/Storages/StorageKafka.h @@ -75,6 +75,9 @@ private: const String brokers; const String group; const String format_name; + // Optional row delimiter for generating char delimited stream + // in order to make various input stream parsers happy. + char row_delimiter; const String schema_name; /// Total number of consumers size_t num_consumers; @@ -109,7 +112,7 @@ protected: Context & context_, const ColumnsDescription & columns_, const String & brokers_, const String & group_, const Names & topics_, - const String & format_name_, const String & schema_name_, size_t num_consumers_); + const String & format_name_, char row_delimiter_, const String & schema_name_, size_t num_consumers_); }; } diff --git a/dbms/tests/integration/helpers/cluster.py b/dbms/tests/integration/helpers/cluster.py index d2c5f27bd4a..ad3dffb9d1d 100644 --- a/dbms/tests/integration/helpers/cluster.py +++ b/dbms/tests/integration/helpers/cluster.py @@ -49,17 +49,18 @@ class ClickHouseCluster: self.base_cmd = ['docker-compose', '--project-directory', self.base_dir, '--project-name', self.project_name] self.base_zookeeper_cmd = None self.base_mysql_cmd = [] + self.base_kafka_cmd = [] self.pre_zookeeper_commands = [] self.instances = {} self.with_zookeeper = False self.with_mysql = False + self.with_kafka = False self.docker_client = None self.is_up = False - def add_instance(self, name, config_dir=None, main_configs=[], user_configs=[], macroses={}, with_zookeeper=False, with_mysql=False, - clickhouse_path_dir=None, hostname=None): + def add_instance(self, name, config_dir=None, main_configs=[], user_configs=[], macroses={}, with_zookeeper=False, with_mysql=False, with_kafka=False, clickhouse_path_dir=None, hostname=None): """Add an instance to the cluster. name - the name of the instance directory and the value of the 'instance' macro in ClickHouse. @@ -77,7 +78,7 @@ class ClickHouseCluster: instance = ClickHouseInstance( self, self.base_dir, name, config_dir, main_configs, user_configs, macroses, with_zookeeper, - self.zookeeper_config_path, with_mysql, self.base_configs_dir, self.server_bin_path, clickhouse_path_dir, hostname=hostname) + self.zookeeper_config_path, with_mysql, with_kafka, self.base_configs_dir, self.server_bin_path, clickhouse_path_dir, hostname=hostname) self.instances[name] = instance self.base_cmd.extend(['--file', instance.docker_compose_path]) @@ -93,6 +94,12 @@ class ClickHouseCluster: self.base_mysql_cmd = ['docker-compose', '--project-directory', self.base_dir, '--project-name', self.project_name, '--file', p.join(HELPERS_DIR, 'docker_compose_mysql.yml')] + if with_kafka and not self.with_kafka: + self.with_kafka = True + self.base_cmd.extend(['--file', p.join(HELPERS_DIR, 'docker_compose_kafka.yml')]) + self.base_kafka_cmd = ['docker-compose', '--project-directory', self.base_dir, '--project-name', + self.project_name, '--file', p.join(HELPERS_DIR, 'docker_compose_kafka.yml')] + return instance @@ -135,6 +142,9 @@ class ClickHouseCluster: if self.with_mysql and self.base_mysql_cmd: subprocess.check_call(self.base_mysql_cmd + ['up', '-d', '--no-recreate']) + if self.with_kafka and self.base_kafka_cmd: + subprocess.check_call(self.base_kafka_cmd + ['up', '-d', '--no-recreate']) + # Uncomment for debugging #print ' '.join(self.base_cmd + ['up', '--no-recreate']) @@ -214,7 +224,7 @@ services: class ClickHouseInstance: def __init__( self, cluster, base_path, name, custom_config_dir, custom_main_configs, custom_user_configs, macroses, - with_zookeeper, zookeeper_config_path, with_mysql, base_configs_dir, server_bin_path, clickhouse_path_dir, hostname=None): + with_zookeeper, zookeeper_config_path, with_mysql, with_kafka, base_configs_dir, server_bin_path, clickhouse_path_dir, hostname=None): self.name = name self.base_cmd = cluster.base_cmd[:] @@ -234,6 +244,7 @@ class ClickHouseInstance: self.server_bin_path = server_bin_path self.with_mysql = with_mysql + self.with_kafka = with_kafka self.path = p.join(self.cluster.instances_dir, name) self.docker_compose_path = p.join(self.path, 'docker_compose.yml') @@ -283,9 +294,10 @@ class ClickHouseInstance: deadline = start_time + timeout while True: - status = self.get_docker_handle().status + handle = self.get_docker_handle() + status = handle.status; if status == 'exited': - raise Exception("Instance `{}' failed to start. Container status: {}".format(self.name, status)) + raise Exception("Instance `{}' failed to start. Container status: {}, logs: {}".format(self.name, status, handle.logs())) current_time = time.time() time_left = deadline - current_time @@ -375,6 +387,9 @@ class ClickHouseInstance: if self.with_mysql: depends_on.append("mysql1") + if self.with_kafka: + depends_on.append("kafka1") + if self.with_zookeeper: depends_on.append("zoo1") depends_on.append("zoo2") diff --git a/dbms/tests/integration/helpers/docker_compose_kafka.yml b/dbms/tests/integration/helpers/docker_compose_kafka.yml new file mode 100644 index 00000000000..42dd154b1e8 --- /dev/null +++ b/dbms/tests/integration/helpers/docker_compose_kafka.yml @@ -0,0 +1,24 @@ +version: '2' + +services: + kafka_zookeeper: + image: zookeeper:3.4.9 + hostname: kafka_zookeeper + environment: + ZOO_MY_ID: 1 + ZOO_PORT: 2181 + ZOO_SERVERS: server.1=kafka_zookeeper:2888:3888 + + kafka1: + image: confluentinc/cp-kafka:4.1.0 + hostname: kafka1 + ports: + - "9092:9092" + environment: + KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka1:9092" + KAFKA_ZOOKEEPER_CONNECT: "kafka_zookeeper:2181" + KAFKA_BROKER_ID: 1 + KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO" + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + depends_on: + - kafka_zookeeper diff --git a/dbms/tests/integration/test_storage_kafka/__init__.py b/dbms/tests/integration/test_storage_kafka/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dbms/tests/integration/test_storage_kafka/configs/kafka.xml b/dbms/tests/integration/test_storage_kafka/configs/kafka.xml new file mode 100644 index 00000000000..e5c07881e06 --- /dev/null +++ b/dbms/tests/integration/test_storage_kafka/configs/kafka.xml @@ -0,0 +1,5 @@ + + + earliest + + diff --git a/dbms/tests/integration/test_storage_kafka/test.py b/dbms/tests/integration/test_storage_kafka/test.py new file mode 100644 index 00000000000..d522d775dc7 --- /dev/null +++ b/dbms/tests/integration/test_storage_kafka/test.py @@ -0,0 +1,53 @@ +import os.path as p +import time +import datetime +import pytest + +from helpers.cluster import ClickHouseCluster +from helpers.test_tools import TSV + +from kafka import KafkaProducer +import json + + + +cluster = ClickHouseCluster(__file__) +instance = cluster.add_instance('instance', main_configs=['configs/kafka.xml'], with_kafka = True) + +@pytest.fixture(scope="module") +def started_cluster(): + try: + cluster.start() + instance.query('CREATE DATABASE test') + + yield cluster + + finally: + cluster.shutdown() + +def test_kafka_json(started_cluster): + instance.query(''' +DROP TABLE IF EXISTS test.kafka; +CREATE TABLE test.kafka (key UInt64, value UInt64) + ENGINE = Kafka('kafka1:9092', 'json', 'json', 'JSONEachRow', '\\n'); +''') + + retries = 0 + while True: + try: + producer = KafkaProducer() + break + except: + retries += 1 + if retries > 50: + raise + print("Waiting for kafka to be available...") + time.sleep(1) + for i in xrange(50): + producer.send('json', json.dumps({'key': i, 'value': i})) + producer.flush() + time.sleep(3) + result = instance.query('SELECT * FROM test.kafka;') + with open(p.join(p.dirname(__file__), 'test_kafka_json.reference')) as reference: + assert TSV(result) == TSV(reference) + instance.query('DROP TABLE test.kafka') diff --git a/dbms/tests/integration/test_storage_kafka/test_kafka_json.reference b/dbms/tests/integration/test_storage_kafka/test_kafka_json.reference new file mode 100644 index 00000000000..959bb2aad74 --- /dev/null +++ b/dbms/tests/integration/test_storage_kafka/test_kafka_json.reference @@ -0,0 +1,50 @@ +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 +33 33 +34 34 +35 35 +36 36 +37 37 +38 38 +39 39 +40 40 +41 41 +42 42 +43 43 +44 44 +45 45 +46 46 +47 47 +48 48 +49 49 From b4556cc5982109513ddaa7c1ab0a34fffa4f8261 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 25 Jul 2018 19:00:51 +0300 Subject: [PATCH 146/425] ~/work/ClickHouse/dbms/tests/integration$ find . -name '*.py' | xargs sed -i -r -e 's/macroses/macros/g' # [#CLICKHOUSE-2] --- dbms/tests/integration/helpers/cluster.py | 16 ++++++++-------- .../integration/test_cluster_copier/test.py | 2 +- .../integration/test_distributed_ddl/test.py | 2 +- .../test_extreme_deduplication/test.py | 4 ++-- .../integration/test_random_inserts/test.py | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dbms/tests/integration/helpers/cluster.py b/dbms/tests/integration/helpers/cluster.py index ad3dffb9d1d..5d5f33e3392 100644 --- a/dbms/tests/integration/helpers/cluster.py +++ b/dbms/tests/integration/helpers/cluster.py @@ -60,7 +60,7 @@ class ClickHouseCluster: self.is_up = False - def add_instance(self, name, config_dir=None, main_configs=[], user_configs=[], macroses={}, with_zookeeper=False, with_mysql=False, with_kafka=False, clickhouse_path_dir=None, hostname=None): + def add_instance(self, name, config_dir=None, main_configs=[], user_configs=[], macros={}, with_zookeeper=False, with_mysql=False, with_kafka=False, clickhouse_path_dir=None, hostname=None): """Add an instance to the cluster. name - the name of the instance directory and the value of the 'instance' macro in ClickHouse. @@ -77,7 +77,7 @@ class ClickHouseCluster: raise Exception("Can\'t add instance `%s': there is already an instance with the same name!" % name) instance = ClickHouseInstance( - self, self.base_dir, name, config_dir, main_configs, user_configs, macroses, with_zookeeper, + self, self.base_dir, name, config_dir, main_configs, user_configs, macros, with_zookeeper, self.zookeeper_config_path, with_mysql, with_kafka, self.base_configs_dir, self.server_bin_path, clickhouse_path_dir, hostname=hostname) self.instances[name] = instance @@ -223,7 +223,7 @@ services: class ClickHouseInstance: def __init__( - self, cluster, base_path, name, custom_config_dir, custom_main_configs, custom_user_configs, macroses, + self, cluster, base_path, name, custom_config_dir, custom_main_configs, custom_user_configs, macros, with_zookeeper, zookeeper_config_path, with_mysql, with_kafka, base_configs_dir, server_bin_path, clickhouse_path_dir, hostname=None): self.name = name @@ -236,7 +236,7 @@ class ClickHouseInstance: self.custom_main_config_paths = [p.abspath(p.join(base_path, c)) for c in custom_main_configs] self.custom_user_config_paths = [p.abspath(p.join(base_path, c)) for c in custom_user_configs] self.clickhouse_path_dir = p.abspath(p.join(base_path, clickhouse_path_dir)) if clickhouse_path_dir else None - self.macroses = macroses if macroses is not None else {} + self.macros = macros if macros is not None else {} self.with_zookeeper = with_zookeeper self.zookeeper_config_path = zookeeper_config_path @@ -352,11 +352,11 @@ class ClickHouseInstance: shutil.copy(p.join(HELPERS_DIR, 'common_instance_config.xml'), config_d_dir) - # Generate and write macroses file - macroses = self.macroses.copy() - macroses['instance'] = self.name + # Generate and write macros file + macros = self.macros.copy() + macros['instance'] = self.name with open(p.join(config_d_dir, 'macros.xml'), 'w') as macros_config: - macros_config.write(self.dict_to_xml({"macros" : macroses})) + macros_config.write(self.dict_to_xml({"macros" : macros})) # Put ZooKeeper config if self.with_zookeeper: diff --git a/dbms/tests/integration/test_cluster_copier/test.py b/dbms/tests/integration/test_cluster_copier/test.py index a19fa8231cf..3f3c5f31741 100644 --- a/dbms/tests/integration/test_cluster_copier/test.py +++ b/dbms/tests/integration/test_cluster_copier/test.py @@ -58,7 +58,7 @@ def started_cluster(): name = "s{}_{}_{}".format(cluster_name, shard_name, replica_name) cluster.add_instance(name, config_dir="configs", - macroses={"cluster": cluster_name, "shard": shard_name, "replica": replica_name}, + macros={"cluster": cluster_name, "shard": shard_name, "replica": replica_name}, with_zookeeper=True) cluster.start() diff --git a/dbms/tests/integration/test_distributed_ddl/test.py b/dbms/tests/integration/test_distributed_ddl/test.py index 75e5ada9851..c2851438c00 100755 --- a/dbms/tests/integration/test_distributed_ddl/test.py +++ b/dbms/tests/integration/test_distributed_ddl/test.py @@ -72,7 +72,7 @@ def init_cluster(cluster): cluster.add_instance( 'ch{}'.format(i+1), config_dir="configs", - macroses={"layer": 0, "shard": i/2 + 1, "replica": i%2 + 1}, + macros={"layer": 0, "shard": i/2 + 1, "replica": i%2 + 1}, with_zookeeper=True) cluster.start() diff --git a/dbms/tests/integration/test_extreme_deduplication/test.py b/dbms/tests/integration/test_extreme_deduplication/test.py index d1a19dc1c60..f8043632ba6 100644 --- a/dbms/tests/integration/test_extreme_deduplication/test.py +++ b/dbms/tests/integration/test_extreme_deduplication/test.py @@ -12,8 +12,8 @@ from helpers.client import QueryTimeoutExceedException cluster = ClickHouseCluster(__file__) -node1 = cluster.add_instance('node1', config_dir='configs', with_zookeeper=True, macroses={"layer": 0, "shard": 0, "replica": 1}) -node2 = cluster.add_instance('node2', config_dir='configs', with_zookeeper=True, macroses={"layer": 0, "shard": 0, "replica": 2}) +node1 = cluster.add_instance('node1', config_dir='configs', with_zookeeper=True, macros={"layer": 0, "shard": 0, "replica": 1}) +node2 = cluster.add_instance('node2', config_dir='configs', with_zookeeper=True, macros={"layer": 0, "shard": 0, "replica": 2}) nodes = [node1, node2] @pytest.fixture(scope="module") diff --git a/dbms/tests/integration/test_random_inserts/test.py b/dbms/tests/integration/test_random_inserts/test.py index 88abd762504..9e5029c5b64 100644 --- a/dbms/tests/integration/test_random_inserts/test.py +++ b/dbms/tests/integration/test_random_inserts/test.py @@ -14,8 +14,8 @@ from helpers.client import CommandRequest cluster = ClickHouseCluster(__file__) -node1 = cluster.add_instance('node1', config_dir='configs', with_zookeeper=True, macroses={"layer": 0, "shard": 0, "replica": 1}) -node2 = cluster.add_instance('node2', config_dir='configs', with_zookeeper=True, macroses={"layer": 0, "shard": 0, "replica": 2}) +node1 = cluster.add_instance('node1', config_dir='configs', with_zookeeper=True, macros={"layer": 0, "shard": 0, "replica": 1}) +node2 = cluster.add_instance('node2', config_dir='configs', with_zookeeper=True, macros={"layer": 0, "shard": 0, "replica": 2}) nodes = [node1, node2] @pytest.fixture(scope="module") From 9adb2516897cc6a2b800775b0fbc9f0c41280397 Mon Sep 17 00:00:00 2001 From: alesapin Date: Wed, 25 Jul 2018 19:08:23 +0300 Subject: [PATCH 147/425] CLICKHOUSE-3857: Add table table_engines, alias factory base class and columns alias_to and case_insensitive to functions --- .../AggregateFunctionBitwise.cpp | 6 +- .../AggregateFunctionFactory.cpp | 8 +- .../AggregateFunctionFactory.h | 31 +++-- .../AggregateFunctionQuantile.cpp | 32 ++--- .../AggregateFunctionsStatisticsSimple.cpp | 12 +- dbms/src/Common/IFactoryWithAliases.h | 125 ++++++++++++++++++ dbms/src/DataTypes/DataTypeFactory.cpp | 65 +-------- dbms/src/DataTypes/DataTypeFactory.h | 38 ++---- dbms/src/Functions/FunctionFactory.cpp | 12 +- dbms/src/Functions/FunctionFactory.h | 19 ++- dbms/src/Functions/FunctionsRound.cpp | 4 +- dbms/src/Storages/StorageFactory.h | 5 + .../System/StorageSystemDataTypeFamilies.cpp | 2 +- .../System/StorageSystemFunctions.cpp | 33 +++-- .../System/StorageSystemTableEngines.cpp | 22 +++ .../System/StorageSystemTableEngines.h | 27 ++++ .../Storages/System/attachSystemTables.cpp | 2 + 17 files changed, 275 insertions(+), 168 deletions(-) create mode 100644 dbms/src/Common/IFactoryWithAliases.h create mode 100644 dbms/src/Storages/System/StorageSystemTableEngines.cpp create mode 100644 dbms/src/Storages/System/StorageSystemTableEngines.h diff --git a/dbms/src/AggregateFunctions/AggregateFunctionBitwise.cpp b/dbms/src/AggregateFunctions/AggregateFunctionBitwise.cpp index 762baf2451b..8c188bcbb8e 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionBitwise.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionBitwise.cpp @@ -38,9 +38,9 @@ void registerAggregateFunctionsBitwise(AggregateFunctionFactory & factory) factory.registerFunction("groupBitXor", createAggregateFunctionBitwise); /// Aliases for compatibility with MySQL. - factory.registerFunction("BIT_OR", createAggregateFunctionBitwise, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("BIT_AND", createAggregateFunctionBitwise, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("BIT_XOR", createAggregateFunctionBitwise, AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("BIT_OR", "groupBitOr", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("BIT_AND", "groupBitAnd", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("BIT_XOR", "groupBitXor", AggregateFunctionFactory::CaseInsensitive); } } diff --git a/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp b/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp index 366aef1f829..353b5a213b3 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp @@ -78,11 +78,12 @@ AggregateFunctionPtr AggregateFunctionFactory::get( AggregateFunctionPtr AggregateFunctionFactory::getImpl( - const String & name, + const String & name_param, const DataTypes & argument_types, const Array & parameters, int recursion_level) const { + String name = getAliasToOrName(name_param); /// Find by exact match. auto it = aggregate_functions.find(name); if (it != aggregate_functions.end()) @@ -126,10 +127,11 @@ AggregateFunctionPtr AggregateFunctionFactory::tryGet(const String & name, const bool AggregateFunctionFactory::isAggregateFunctionName(const String & name, int recursion_level) const { - if (aggregate_functions.count(name)) + if (aggregate_functions.count(name) || isAlias(name)) return true; - if (recursion_level == 0 && case_insensitive_aggregate_functions.count(Poco::toLower(name))) + String name_lowercase = Poco::toLower(name); + if (recursion_level == 0 && (case_insensitive_aggregate_functions.count(name_lowercase) || isAlias(name_lowercase))) return true; if (AggregateFunctionCombinatorPtr combinator = AggregateFunctionCombinatorFactory::instance().tryFindSuffix(name)) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionFactory.h b/dbms/src/AggregateFunctions/AggregateFunctionFactory.h index bc36e76c11f..92598e52509 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionFactory.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionFactory.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -20,27 +21,18 @@ class IDataType; using DataTypePtr = std::shared_ptr; using DataTypes = std::vector; +/** Creator have arguments: name of aggregate function, types of arguments, values of parameters. + * Parameters are for "parametric" aggregate functions. + * For example, in quantileWeighted(0.9)(x, weight), 0.9 is "parameter" and x, weight are "arguments". + */ +using AggregateFunctionCreator = std::function; + /** Creates an aggregate function by name. */ -class AggregateFunctionFactory final : public ext::singleton +class AggregateFunctionFactory final : public ext::singleton, public IFactoryWithAliases { - friend class StorageSystemFunctions; - public: - /** Creator have arguments: name of aggregate function, types of arguments, values of parameters. - * Parameters are for "parametric" aggregate functions. - * For example, in quantileWeighted(0.9)(x, weight), 0.9 is "parameter" and x, weight are "arguments". - */ - using Creator = std::function; - - /// For compatibility with SQL, it's possible to specify that certain aggregate function name is case insensitive. - enum CaseSensitiveness - { - CaseSensitive, - CaseInsensitive - }; - /// Register a function by its name. /// No locking, you must register all functions before usage of get. void registerFunction( @@ -77,6 +69,13 @@ private: /// Case insensitive aggregate functions will be additionally added here with lowercased name. AggregateFunctions case_insensitive_aggregate_functions; + + const AggregateFunctions & getCreatorMap() const override { return aggregate_functions; } + + const AggregateFunctions & getCaseInsensitiveCreatorMap() const override { return case_insensitive_aggregate_functions; } + + String getFactoryName() const override { return "AggregateFunctionFactory"; } + }; } diff --git a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp index 250ee422e8b..62455af6353 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp @@ -93,30 +93,14 @@ void registerAggregateFunctionsQuantile(AggregateFunctionFactory & factory) createAggregateFunctionQuantile); /// 'median' is an alias for 'quantile' - - factory.registerFunction("median", - createAggregateFunctionQuantile); - - factory.registerFunction("medianDeterministic", - createAggregateFunctionQuantile); - - factory.registerFunction("medianExact", - createAggregateFunctionQuantile); - - factory.registerFunction("medianExactWeighted", - createAggregateFunctionQuantile); - - factory.registerFunction("medianTiming", - createAggregateFunctionQuantile); - - factory.registerFunction("medianTimingWeighted", - createAggregateFunctionQuantile); - - factory.registerFunction("medianTDigest", - createAggregateFunctionQuantile); - - factory.registerFunction("medianTDigestWeighted", - createAggregateFunctionQuantile); + factory.registerAlias("median", NameQuantile::name); + factory.registerAlias("medianDeterministic", NameQuantileDeterministic::name); + factory.registerAlias("medianExact", NameQuantileExact::name); + factory.registerAlias("medianExactWeighted", NameQuantileExactWeighted::name); + factory.registerAlias("medianTiming", NameQuantileTiming::name); + factory.registerAlias("medianTimingWeighted", NameQuantileTimingWeighted::name); + factory.registerAlias("medianTDigest", NameQuantileTDigest::name); + factory.registerAlias("medianTDigestWeighted", NameQuantileTDigestWeighted::name); } } diff --git a/dbms/src/AggregateFunctions/AggregateFunctionsStatisticsSimple.cpp b/dbms/src/AggregateFunctions/AggregateFunctionsStatisticsSimple.cpp index 089ea59cd79..c42372187bc 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionsStatisticsSimple.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionsStatisticsSimple.cpp @@ -56,12 +56,12 @@ void registerAggregateFunctionsStatisticsSimple(AggregateFunctionFactory & facto factory.registerFunction("corr", createAggregateFunctionStatisticsBinary, AggregateFunctionFactory::CaseInsensitive); /// Synonims for compatibility. - factory.registerFunction("VAR_SAMP", createAggregateFunctionStatisticsUnary, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("VAR_POP", createAggregateFunctionStatisticsUnary, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("STDDEV_SAMP", createAggregateFunctionStatisticsUnary, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("STDDEV_POP", createAggregateFunctionStatisticsUnary, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("COVAR_SAMP", createAggregateFunctionStatisticsBinary, AggregateFunctionFactory::CaseInsensitive); - factory.registerFunction("COVAR_POP", createAggregateFunctionStatisticsBinary, AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("VAR_SAMP", "varSamp", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("VAR_POP", "varPop", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("STDDEV_SAMP", "stddevSamp", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("STDDEV_POP", "stddevPop", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("COVAR_SAMP", "covarSamp", AggregateFunctionFactory::CaseInsensitive); + factory.registerAlias("COVAR_POP", "covarPop", AggregateFunctionFactory::CaseInsensitive); } } diff --git a/dbms/src/Common/IFactoryWithAliases.h b/dbms/src/Common/IFactoryWithAliases.h new file mode 100644 index 00000000000..dc341782894 --- /dev/null +++ b/dbms/src/Common/IFactoryWithAliases.h @@ -0,0 +1,125 @@ +#pragma once + +#include +#include +#include + +#include + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + +/** If stored objects may have several names (aliases) + * this interface may be helpful + * template parameter is available as Creator + */ +template +class IFactoryWithAliases +{ +protected: + using Creator = CreatorFunc; + + String getAliasToOrName(const String & name) const + { + if (aliases.count(name)) + return aliases.at(name); + else if (String name_lowercase = Poco::toLower(name); case_insensitive_aliases.count(name_lowercase)) + return case_insensitive_aliases.at(name_lowercase); + else + return name; + } + +public: + /// For compatibility with SQL, it's possible to specify that certain function name is case insensitive. + enum CaseSensitiveness + { + CaseSensitive, + CaseInsensitive + }; + + /** Register additional name for creater + * real_name have to be already registered. + */ + void registerAlias(const String & alias_name, const String & real_name, CaseSensitiveness case_sensitiveness = CaseSensitive) + { + const auto & creator_map = getCreatorMap(); + const auto & case_insensitive_creator_map = getCaseInsensitiveCreatorMap(); + const String factory_name = getFactoryName(); + + String real_dict_name; + if (creator_map.count(real_name)) + real_dict_name = real_name; + else if (auto real_name_lowercase = Poco::toLower(real_name); case_insensitive_creator_map.count(real_name_lowercase)) + real_dict_name = real_name_lowercase; + else + throw Exception(factory_name + ": can't create alias '" + alias_name + "', the real name '" + real_name + "' is not registered", + ErrorCodes::LOGICAL_ERROR); + + String alias_name_lowercase = Poco::toLower(alias_name); + + if (creator_map.count(alias_name) || case_insensitive_creator_map.count(alias_name_lowercase)) + throw Exception( + factory_name + ": the alias name '" + alias_name + "' is already registered as real name", ErrorCodes::LOGICAL_ERROR); + + if (case_sensitiveness == CaseInsensitive) + if (!case_insensitive_aliases.emplace(alias_name_lowercase, real_dict_name).second) + throw Exception( + factory_name + ": case insensitive alias name '" + alias_name + "' is not unique", ErrorCodes::LOGICAL_ERROR); + + if (!aliases.emplace(alias_name, real_dict_name).second) + throw Exception(factory_name + ": alias name '" + alias_name + "' is not unique", ErrorCodes::LOGICAL_ERROR); + } + + std::vector getAllRegisteredNames() const + { + std::vector result; + auto getter = [](const auto & pair) { return pair.first; }; + std::transform(getCreatorMap().begin(), getCreatorMap().end(), std::back_inserter(result), getter); + std::transform(aliases.begin(), aliases.end(), std::back_inserter(result), getter); + return result; + } + + bool isCaseInsensitive(const String & name) const + { + String name_lowercase = Poco::toLower(name); + return getCaseInsensitiveCreatorMap().count(name_lowercase) || case_insensitive_aliases.count(name_lowercase); + } + + const String & aliasTo(const String & name) const + { + if (auto it = aliases.find(name); it != aliases.end()) + return it->second; + else if (auto it = case_insensitive_aliases.find(Poco::toLower(name)); it != case_insensitive_aliases.end()) + return it->second; + + throw Exception(getFactoryName() + ": name '" + name + "' is not alias", ErrorCodes::LOGICAL_ERROR); + } + + bool isAlias(const String & name) const + { + return aliases.count(name) || case_insensitive_aliases.count(name); + } + + virtual ~IFactoryWithAliases() {} + +private: + using InnerMap = std::unordered_map; // name -> creator + using AliasMap = std::unordered_map; // alias -> original type + + virtual const InnerMap & getCreatorMap() const = 0; + virtual const InnerMap & getCaseInsensitiveCreatorMap() const = 0; + virtual String getFactoryName() const = 0; + + /// Alias map to data_types from previous two maps + AliasMap aliases; + + /// Case insensitive aliases + AliasMap case_insensitive_aliases; +}; + +} diff --git a/dbms/src/DataTypes/DataTypeFactory.cpp b/dbms/src/DataTypes/DataTypeFactory.cpp index 87599a90370..9706ecf4944 100644 --- a/dbms/src/DataTypes/DataTypeFactory.cpp +++ b/dbms/src/DataTypes/DataTypeFactory.cpp @@ -51,8 +51,10 @@ DataTypePtr DataTypeFactory::get(const ASTPtr & ast) const throw Exception("Unexpected AST element for data type.", ErrorCodes::UNEXPECTED_AST_STRUCTURE); } -DataTypePtr DataTypeFactory::get(const String & family_name, const ASTPtr & parameters) const +DataTypePtr DataTypeFactory::get(const String & family_name_param, const ASTPtr & parameters) const { + String family_name = getAliasToOrName(family_name_param); + { DataTypesDictionary::const_iterator it = data_types.find(family_name); if (data_types.end() != it) @@ -67,11 +69,6 @@ DataTypePtr DataTypeFactory::get(const String & family_name, const ASTPtr & para return it->second(parameters); } - if (auto it = aliases.find(family_name); it != aliases.end()) - return get(it->second, parameters); - else if (auto it = case_insensitive_aliases.find(family_name_lowercase); it != case_insensitive_aliases.end()) - return get(it->second, parameters); - throw Exception("Unknown data type family: " + family_name, ErrorCodes::UNKNOWN_TYPE); } @@ -84,7 +81,7 @@ void DataTypeFactory::registerDataType(const String & family_name, Creator creat String family_name_lowercase = Poco::toLower(family_name); - if (aliases.count(family_name) || case_insensitive_aliases.count(family_name_lowercase)) + if (isAlias(family_name) || isAlias(family_name_lowercase)) throw Exception("DataTypeFactory: the data type family name '" + family_name + "' is already registered as alias", ErrorCodes::LOGICAL_ERROR); @@ -99,29 +96,6 @@ void DataTypeFactory::registerDataType(const String & family_name, Creator creat ErrorCodes::LOGICAL_ERROR); } -void DataTypeFactory::registerAlias(const String & alias_name, const String & real_name, CaseSensitiveness case_sensitiveness) -{ - String real_type_dict_name; - if (data_types.count(real_name)) - real_type_dict_name = real_name; - else if (auto type_name_lowercase = Poco::toLower(real_name); case_insensitive_data_types.count(type_name_lowercase)) - real_type_dict_name = type_name_lowercase; - else - throw Exception("DataTypeFactory: can't create alias '" + alias_name + "' the data type family '" + real_name + "' is not registered", ErrorCodes::LOGICAL_ERROR); - - String alias_name_lowercase = Poco::toLower(alias_name); - - if (data_types.count(alias_name) || case_insensitive_data_types.count(alias_name_lowercase)) - throw Exception("DataTypeFactory: the alias name " + alias_name + " is already registered as datatype", ErrorCodes::LOGICAL_ERROR); - - if (case_sensitiveness == CaseInsensitive) - if (!case_insensitive_aliases.emplace(alias_name_lowercase, real_type_dict_name).second) - throw Exception("DataTypeFactory: case insensitive alias name '" + alias_name + "' is not unique", ErrorCodes::LOGICAL_ERROR); - - if (!aliases.emplace(alias_name, real_type_dict_name).second) - throw Exception("DataTypeFactory: alias name '" + alias_name + "' is not unique", ErrorCodes::LOGICAL_ERROR); -} - void DataTypeFactory::registerSimpleDataType(const String & name, SimpleCreator creator, CaseSensitiveness case_sensitiveness) { if (creator == nullptr) @@ -136,37 +110,6 @@ void DataTypeFactory::registerSimpleDataType(const String & name, SimpleCreator }, case_sensitiveness); } -std::vector DataTypeFactory::getAllDataTypeNames() const -{ - std::vector result; - auto getter = [] (const auto & pair) { return pair.first; }; - std::transform(data_types.begin(), data_types.end(), std::back_inserter(result), getter); - std::transform(aliases.begin(), aliases.end(), std::back_inserter(result), getter); - return result; -} - -bool DataTypeFactory::isCaseInsensitive(const String & name) const -{ - String name_lowercase = Poco::toLower(name); - return case_insensitive_data_types.count(name_lowercase) || case_insensitive_aliases.count(name_lowercase); -} - -const String & DataTypeFactory::aliasTo(const String & name) const -{ - if (auto it = aliases.find(name); it != aliases.end()) - return it->second; - else if (auto it = case_insensitive_aliases.find(Poco::toLower(name)); it != case_insensitive_aliases.end()) - return it->second; - - throw Exception("DataTypeFactory: the data type '" + name + "' is not alias", ErrorCodes::LOGICAL_ERROR); -} - - -bool DataTypeFactory::isAlias(const String & name) const -{ - return aliases.count(name) || case_insensitive_aliases.count(name); -} - void registerDataTypeNumbers(DataTypeFactory & factory); void registerDataTypeDate(DataTypeFactory & factory); void registerDataTypeDateTime(DataTypeFactory & factory); diff --git a/dbms/src/DataTypes/DataTypeFactory.h b/dbms/src/DataTypes/DataTypeFactory.h index 423ff6acd1e..21d22cf932e 100644 --- a/dbms/src/DataTypes/DataTypeFactory.h +++ b/dbms/src/DataTypes/DataTypeFactory.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -19,58 +20,37 @@ using ASTPtr = std::shared_ptr; /** Creates a data type by name of data type family and parameters. */ -class DataTypeFactory final : public ext::singleton +class DataTypeFactory final : public ext::singleton, public IFactoryWithAliases> { private: - using Creator = std::function; using SimpleCreator = std::function; using DataTypesDictionary = std::unordered_map; - using AliasMap = std::unordered_map; // alias -> original type public: DataTypePtr get(const String & full_name) const; DataTypePtr get(const String & family_name, const ASTPtr & parameters) const; DataTypePtr get(const ASTPtr & ast) const; - /// For compatibility with SQL, it's possible to specify that certain data type name is case insensitive. - enum CaseSensitiveness - { - CaseSensitive, - CaseInsensitive - }; - /// Register a type family by its name. void registerDataType(const String & family_name, Creator creator, CaseSensitiveness case_sensitiveness = CaseSensitive); /// Register a simple data type, that have no parameters. void registerSimpleDataType(const String & name, SimpleCreator creator, CaseSensitiveness case_sensitiveness = CaseSensitive); - /** Register additional name for datatype. - * real_name datatype have to be already registered. - */ - void registerAlias(const String & alias_name, const String & real_name, CaseSensitiveness case_sensitiveness = CaseSensitive); - - std::vector getAllDataTypeNames() const; - - bool isCaseInsensitive(const String & name) const; - - const String & aliasTo(const String & name) const; - - bool isAlias(const String & name) const; - private: DataTypesDictionary data_types; /// Case insensitive data types will be additionally added here with lowercased name. DataTypesDictionary case_insensitive_data_types; - /// Alias map to data_types from previous two maps - AliasMap aliases; - - /// Case insensitive aliases - AliasMap case_insensitive_aliases; - DataTypeFactory(); + + const DataTypesDictionary & getCreatorMap() const override { return data_types; } + + const DataTypesDictionary & getCaseInsensitiveCreatorMap() const override { return case_insensitive_data_types; } + + String getFactoryName() const override { return "DataTypeFactory"; } + friend class ext::singleton; }; diff --git a/dbms/src/Functions/FunctionFactory.cpp b/dbms/src/Functions/FunctionFactory.cpp index 9bb2abbb013..0b2f042089d 100644 --- a/dbms/src/Functions/FunctionFactory.cpp +++ b/dbms/src/Functions/FunctionFactory.cpp @@ -6,7 +6,6 @@ #include - namespace DB { @@ -26,8 +25,13 @@ void FunctionFactory::registerFunction(const throw Exception("FunctionFactory: the function name '" + name + "' is not unique", ErrorCodes::LOGICAL_ERROR); + String function_name_lowercase = Poco::toLower(name); + if (isAlias(name) || isAlias(function_name_lowercase)) + throw Exception("FunctionFactory: the function name '" + name + "' is already registered as alias", + ErrorCodes::LOGICAL_ERROR); + if (case_sensitiveness == CaseInsensitive - && !case_insensitive_functions.emplace(Poco::toLower(name), creator).second) + && !case_insensitive_functions.emplace(function_name_lowercase, creator).second) throw Exception("FunctionFactory: the case insensitive function name '" + name + "' is not unique", ErrorCodes::LOGICAL_ERROR); } @@ -45,9 +49,11 @@ FunctionBuilderPtr FunctionFactory::get( FunctionBuilderPtr FunctionFactory::tryGet( - const std::string & name, + const std::string & name_param, const Context & context) const { + String name = getAliasToOrName(name_param); + auto it = functions.find(name); if (functions.end() != it) return it->second(context); diff --git a/dbms/src/Functions/FunctionFactory.h b/dbms/src/Functions/FunctionFactory.h index a061c3103fd..7fa0f81f475 100644 --- a/dbms/src/Functions/FunctionFactory.h +++ b/dbms/src/Functions/FunctionFactory.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -20,19 +21,9 @@ class Context; * Function could use for initialization (take ownership of shared_ptr, for example) * some dictionaries from Context. */ -class FunctionFactory : public ext::singleton +class FunctionFactory : public ext::singleton, public IFactoryWithAliases> { - friend class StorageSystemFunctions; - public: - using Creator = std::function; - - /// For compatibility with SQL, it's possible to specify that certain function name is case insensitive. - enum CaseSensitiveness - { - CaseSensitive, - CaseInsensitive - }; template void registerFunction(CaseSensitiveness case_sensitiveness = CaseSensitive) @@ -67,6 +58,12 @@ private: return std::make_shared(Function::create(context)); } + const Functions & getCreatorMap() const override { return functions; } + + const Functions & getCaseInsensitiveCreatorMap() const override { return case_insensitive_functions; } + + String getFactoryName() const override { return "FunctionFactory"; } + /// Register a function by its name. /// No locking, you must register all functions before usage of get. void registerFunction( diff --git a/dbms/src/Functions/FunctionsRound.cpp b/dbms/src/Functions/FunctionsRound.cpp index 7bf7eb791ad..9cb9e1001ae 100644 --- a/dbms/src/Functions/FunctionsRound.cpp +++ b/dbms/src/Functions/FunctionsRound.cpp @@ -16,8 +16,8 @@ void registerFunctionsRound(FunctionFactory & factory) factory.registerFunction("trunc", FunctionFactory::CaseInsensitive); /// Compatibility aliases. - factory.registerFunction("ceiling", FunctionFactory::CaseInsensitive); - factory.registerFunction("truncate", FunctionFactory::CaseInsensitive); + factory.registerAlias("ceiling", "ceil", FunctionFactory::CaseInsensitive); + factory.registerAlias("truncate", "trunc", FunctionFactory::CaseInsensitive); } } diff --git a/dbms/src/Storages/StorageFactory.h b/dbms/src/Storages/StorageFactory.h index 2acb9fb7c00..4addfcd9794 100644 --- a/dbms/src/Storages/StorageFactory.h +++ b/dbms/src/Storages/StorageFactory.h @@ -53,6 +53,11 @@ public: /// No locking, you must register all engines before usage of get. void registerStorage(const std::string & name, Creator creator); + const auto & getAllStorages() const + { + return storages; + } + private: using Storages = std::unordered_map; Storages storages; diff --git a/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp b/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp index 126f98e506f..68228ca3965 100644 --- a/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp +++ b/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp @@ -19,7 +19,7 @@ NamesAndTypesList StorageSystemDataTypeFamilies::getNamesAndTypes() void StorageSystemDataTypeFamilies::fillData(MutableColumns & res_columns, const Context &, const SelectQueryInfo &) const { const auto & factory = DataTypeFactory::instance(); - auto names = factory.getAllDataTypeNames(); + auto names = factory.getAllRegisteredNames(); for (const auto & name : names) { res_columns[0]->insert(name); diff --git a/dbms/src/Storages/System/StorageSystemFunctions.cpp b/dbms/src/Storages/System/StorageSystemFunctions.cpp index 4737f99aaf4..f8bcb379981 100644 --- a/dbms/src/Storages/System/StorageSystemFunctions.cpp +++ b/dbms/src/Storages/System/StorageSystemFunctions.cpp @@ -9,30 +9,45 @@ namespace DB { +namespace +{ + template + void fillRow(MutableColumns & res_columns, const String & name, UInt64 is_aggregate, const Factory & f) + { + res_columns[0]->insert(name); + res_columns[1]->insert(is_aggregate); + res_columns[2]->insert(UInt64(f.isCaseInsensitive(name))); + if (f.isAlias(name)) + res_columns[3]->insert(f.aliasTo(name)); + else + res_columns[3]->insert(String{}); + } +} NamesAndTypesList StorageSystemFunctions::getNamesAndTypes() { return { {"name", std::make_shared()}, {"is_aggregate", std::make_shared()}, + {"case_insensivie", std::make_shared()}, + {"alias_to", std::make_shared()}, }; } void StorageSystemFunctions::fillData(MutableColumns & res_columns, const Context &, const SelectQueryInfo &) const { - const auto & functions = FunctionFactory::instance().functions; - for (const auto & it : functions) + const auto & functions_factory = FunctionFactory::instance(); + const auto & function_names = functions_factory.getAllRegisteredNames(); + for (const auto & name : function_names) { - res_columns[0]->insert(it.first); - res_columns[1]->insert(UInt64(0)); + fillRow(res_columns, name, UInt64(0), functions_factory); } - const auto & aggregate_functions = AggregateFunctionFactory::instance().aggregate_functions; - for (const auto & it : aggregate_functions) + const auto & aggregate_functions_factory = AggregateFunctionFactory::instance(); + const auto & aggregate_function_names = aggregate_functions_factory.getAllRegisteredNames(); + for (const auto & name : aggregate_function_names) { - res_columns[0]->insert(it.first); - res_columns[1]->insert(UInt64(1)); + fillRow(res_columns, name, UInt64(1), aggregate_functions_factory); } } - } diff --git a/dbms/src/Storages/System/StorageSystemTableEngines.cpp b/dbms/src/Storages/System/StorageSystemTableEngines.cpp new file mode 100644 index 00000000000..99b0a650d68 --- /dev/null +++ b/dbms/src/Storages/System/StorageSystemTableEngines.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +namespace DB +{ + +NamesAndTypesList StorageSystemTableEngines::getNamesAndTypes() +{ + return {{"name", std::make_shared()}}; +} + +void StorageSystemTableEngines::fillData(MutableColumns & res_columns, const Context &, const SelectQueryInfo &) const +{ + const auto & storages = StorageFactory::instance().getAllStorages(); + for (const auto & [name, creator] : storages) + { + res_columns[0]->insert(name); + } +} + +} diff --git a/dbms/src/Storages/System/StorageSystemTableEngines.h b/dbms/src/Storages/System/StorageSystemTableEngines.h new file mode 100644 index 00000000000..f0f6b62d59d --- /dev/null +++ b/dbms/src/Storages/System/StorageSystemTableEngines.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +namespace DB +{ + +class StorageSystemTableEngines : public ext::shared_ptr_helper, + public IStorageSystemOneBlock +{ +protected: + void fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo & query_info) const override; + + using IStorageSystemOneBlock::IStorageSystemOneBlock; + +public: + std::string getName() const override + { + return "SystemTableEngines"; + } + + static NamesAndTypesList getNamesAndTypes(); +}; + +} diff --git a/dbms/src/Storages/System/attachSystemTables.cpp b/dbms/src/Storages/System/attachSystemTables.cpp index e29a26df4eb..479337d1b41 100644 --- a/dbms/src/Storages/System/attachSystemTables.cpp +++ b/dbms/src/Storages/System/attachSystemTables.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ void attachSystemTablesLocal(IDatabase & system_database) system_database.attachTable("aggregate_function_combinators", StorageSystemAggregateFunctionCombinators::create("aggregate_function_combinators")); system_database.attachTable("data_type_families", StorageSystemDataTypeFamilies::create("data_type_families")); system_database.attachTable("collations", StorageSystemCollations::create("collations")); + system_database.attachTable("table_engines", StorageSystemTableEngines::create("table_engines")); } void attachSystemTablesServer(IDatabase & system_database, bool has_zookeeper) From 60050a1224dd2058df754d049102c0e8d492b76c Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Wed, 25 Jul 2018 18:54:10 +0300 Subject: [PATCH 148/425] add RU changelog for v18.1.0 --- CHANGELOG_RU.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index 5282e10a556..c28d179e881 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -1,3 +1,29 @@ +## ClickHouse release 18.1.0, 2018-07-23 + +### Новые возможности: +* Поддержка запроса `ALTER TABLE t DELETE WHERE` для нереплицированных MergeTree-таблиц. +* Поддержка произвольных типов для семейства агрегатных функций `uniq*` ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). +* Поддержка произвольных типов в операторах сравнения ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). +* Возможность в `users.xml` указывать маску подсети в формате `10.0.0.1/255.255.255.0`. +* Добавлена функция `arrayDistinct()`. + +### Улучшения: +* Изменена схема версионирования релизов. Теперь первый компонент содержит год релиза, второй - номер крупных изменений (увеличивается для большинства релизов), третий - патч-версия. Релизы по-прежнему обратно совместимы, если другое не указано в changelog. +* Ускорено преобразование чисел с плавающей точкой в строку ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2664)). +* Теперь, если при вставке из-за ошибок парсинга пропущено некоторое количество строк (такое возможно про включённых настройках `input_allow_errors_num`, `input_allow_errors_ratio`), это количество пишется в лог сервера ([Leonardo Cecchi](https://github.com/yandex/ClickHouse/pull/2669)). + +### Исправление ошибок: +* Исправлена работа команды TRUNCATE для временных таблиц ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2624)). +* Исправлен редкий deadlock в клиентской библиотеке ZooKeeper, который возникал при сетевой ошибке во время вычитывания ответа. +* Исправлена ошибка при CAST в Nullable типы ([#1322](https://github.com/yandex/ClickHouse/issues/1322)). +* Исправлен неправильный результат функции `maxIntersection()` в случае совпадения границ отрезков ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2657)). +* Исправлена работа движка SummingMergeTree со столбцами типа AggregateFunction ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2665)). +* Исправлено неверное преобразование цепочки OR-выражений в аргументе функции ([chenxing-xc](https://github.com/yandex/ClickHouse/pull/2663)). +* Исправлена деградация производительности запросов, содержащих выражение `IN (подзапрос)` внутри другого подзапроса ([#2571](https://github.com/yandex/ClickHouse/issues/2571)). +* Исправлена несовместимость серверов разных версий при распределённых запросах, использующих функцию `CAST` не в верхнем регистре. +* Добавлено недостающее квотирование идентификаторов при запросах к внешним СУБД ([#2635](https://github.com/yandex/ClickHouse/issues/2635)). + + ## ClickHouse release 1.1.54394, 2018-07-12 ### Новые возможности: From 3914aaf2098f5dc1aad02c6bb659a4c17d9e209f Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 25 Jul 2018 19:15:53 +0300 Subject: [PATCH 149/425] Update CHANGELOG_RU.md --- CHANGELOG_RU.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index c28d179e881..7aacb21296f 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -4,7 +4,7 @@ * Поддержка запроса `ALTER TABLE t DELETE WHERE` для нереплицированных MergeTree-таблиц. * Поддержка произвольных типов для семейства агрегатных функций `uniq*` ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). * Поддержка произвольных типов в операторах сравнения ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). -* Возможность в `users.xml` указывать маску подсети в формате `10.0.0.1/255.255.255.0`. +* Возможность в `users.xml` указывать маску подсети в формате `10.0.0.1/255.255.255.0`. Это необходимо для использования "дырявых" масок IPv6 сетей ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). * Добавлена функция `arrayDistinct()`. ### Улучшения: From 388807739802a5f893ba9b5af0ead3cf1b7ed8b1 Mon Sep 17 00:00:00 2001 From: alesapin Date: Wed, 25 Jul 2018 19:19:11 +0300 Subject: [PATCH 150/425] CLICKHOUSE-3857: Fix typo --- dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp | 2 +- dbms/src/Storages/System/StorageSystemFunctions.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp b/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp index 68228ca3965..c8d692fddd8 100644 --- a/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp +++ b/dbms/src/Storages/System/StorageSystemDataTypeFamilies.cpp @@ -11,7 +11,7 @@ NamesAndTypesList StorageSystemDataTypeFamilies::getNamesAndTypes() { return { {"name", std::make_shared()}, - {"case_insensivie", std::make_shared()}, + {"case_insensitive", std::make_shared()}, {"alias_to", std::make_shared()}, }; } diff --git a/dbms/src/Storages/System/StorageSystemFunctions.cpp b/dbms/src/Storages/System/StorageSystemFunctions.cpp index f8bcb379981..f63d0b9b932 100644 --- a/dbms/src/Storages/System/StorageSystemFunctions.cpp +++ b/dbms/src/Storages/System/StorageSystemFunctions.cpp @@ -29,7 +29,7 @@ NamesAndTypesList StorageSystemFunctions::getNamesAndTypes() return { {"name", std::make_shared()}, {"is_aggregate", std::make_shared()}, - {"case_insensivie", std::make_shared()}, + {"case_insensitive", std::make_shared()}, {"alias_to", std::make_shared()}, }; } From 19a0ae304cd848670a8c1829349b5cb433951877 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 25 Jul 2018 19:20:01 +0300 Subject: [PATCH 151/425] Update CHANGELOG_RU.md --- CHANGELOG_RU.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index 7aacb21296f..758fc773d8f 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -8,7 +8,7 @@ * Добавлена функция `arrayDistinct()`. ### Улучшения: -* Изменена схема версионирования релизов. Теперь первый компонент содержит год релиза, второй - номер крупных изменений (увеличивается для большинства релизов), третий - патч-версия. Релизы по-прежнему обратно совместимы, если другое не указано в changelog. +* Изменена схема версионирования релизов. Теперь первый компонент содержит год релиза (A.D.; по московскому времени; из номера вычитается 2000), второй - номер крупных изменений (увеличивается для большинства релизов), третий - патч-версия. Релизы по-прежнему обратно совместимы, если другое не указано в changelog. * Ускорено преобразование чисел с плавающей точкой в строку ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2664)). * Теперь, если при вставке из-за ошибок парсинга пропущено некоторое количество строк (такое возможно про включённых настройках `input_allow_errors_num`, `input_allow_errors_ratio`), это количество пишется в лог сервера ([Leonardo Cecchi](https://github.com/yandex/ClickHouse/pull/2669)). From 9079bdad4e15989546aa798dc7c11b381f451e06 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 25 Jul 2018 19:27:38 +0300 Subject: [PATCH 152/425] Updated README #2701 --- dbms/tests/integration/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/tests/integration/README.md b/dbms/tests/integration/README.md index 86808503180..1a62b9a70c8 100644 --- a/dbms/tests/integration/README.md +++ b/dbms/tests/integration/README.md @@ -14,9 +14,9 @@ Don't use Docker from your system repository. * [pip](https://pypi.python.org/pypi/pip). To install: `sudo apt-get install python-pip` * [py.test](https://docs.pytest.org/) testing framework. To install: `sudo -H pip install pytest` -* [docker-compose](https://docs.docker.com/compose/) and additional python libraries. To install: `sudo -H pip install docker-compose docker dicttoxml kazoo PyMySQL` +* [docker-compose](https://docs.docker.com/compose/) and additional python libraries. To install: `sudo -H pip install docker-compose docker dicttoxml kazoo PyMySQL kafka` -(highly not recommended) If you really want to use OS packages on modern debian/ubuntu instead of "pip": `sudo apt install -y docker docker-compose python-pytest python-dicttoxml python-docker python-pymysql python-kazoo` +(highly not recommended) If you really want to use OS packages on modern debian/ubuntu instead of "pip": `sudo apt install -y docker docker-compose python-pytest python-dicttoxml python-docker python-pymysql python-kazoo python-kafka` If you want to run the tests under a non-privileged user, you must add this user to `docker` group: `sudo usermod -aG docker $USER` and re-login. (You must close all your sessions (for example, restart your computer)) From c9a8759e08bb6f5be7aaac98211ab1463a4ce460 Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Thu, 26 Jul 2018 00:34:40 +0800 Subject: [PATCH 153/425] Update README.md kafka integration test uses this package https://github.com/dpkp/kafka-python --- dbms/tests/integration/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/integration/README.md b/dbms/tests/integration/README.md index 1a62b9a70c8..cf1df4a40e8 100644 --- a/dbms/tests/integration/README.md +++ b/dbms/tests/integration/README.md @@ -14,7 +14,7 @@ Don't use Docker from your system repository. * [pip](https://pypi.python.org/pypi/pip). To install: `sudo apt-get install python-pip` * [py.test](https://docs.pytest.org/) testing framework. To install: `sudo -H pip install pytest` -* [docker-compose](https://docs.docker.com/compose/) and additional python libraries. To install: `sudo -H pip install docker-compose docker dicttoxml kazoo PyMySQL kafka` +* [docker-compose](https://docs.docker.com/compose/) and additional python libraries. To install: `sudo -H pip install docker-compose docker dicttoxml kazoo PyMySQL kafka-python` (highly not recommended) If you really want to use OS packages on modern debian/ubuntu instead of "pip": `sudo apt install -y docker docker-compose python-pytest python-dicttoxml python-docker python-pymysql python-kazoo python-kafka` From 73e3268e7996fc91f9d213a1bd4bb8ac2b17dee5 Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Wed, 25 Jul 2018 19:33:46 +0300 Subject: [PATCH 154/425] add pull request links to changelog Conflicts: CHANGELOG_RU.md --- CHANGELOG_RU.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index 758fc773d8f..8b8f5535ddf 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -1,11 +1,12 @@ ## ClickHouse release 18.1.0, 2018-07-23 ### Новые возможности: -* Поддержка запроса `ALTER TABLE t DELETE WHERE` для нереплицированных MergeTree-таблиц. +* Поддержка запроса `ALTER TABLE t DELETE WHERE` для нереплицированных MergeTree-таблиц ([#2634](https://github.com/yandex/ClickHouse/pull/2634)). * Поддержка произвольных типов для семейства агрегатных функций `uniq*` ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). * Поддержка произвольных типов в операторах сравнения ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). * Возможность в `users.xml` указывать маску подсети в формате `10.0.0.1/255.255.255.0`. Это необходимо для использования "дырявых" масок IPv6 сетей ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). -* Добавлена функция `arrayDistinct()`. +* Добавлена функция `arrayDistinct()` ([#2670](https://github.com/yandex/ClickHouse/pull/2670)). +* Движок SummingMergeTree теперь может работать со столбцами типа AggregateFunction ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2566)). ### Улучшения: * Изменена схема версионирования релизов. Теперь первый компонент содержит год релиза (A.D.; по московскому времени; из номера вычитается 2000), второй - номер крупных изменений (увеличивается для большинства релизов), третий - патч-версия. Релизы по-прежнему обратно совместимы, если другое не указано в changelog. @@ -14,13 +15,12 @@ ### Исправление ошибок: * Исправлена работа команды TRUNCATE для временных таблиц ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2624)). -* Исправлен редкий deadlock в клиентской библиотеке ZooKeeper, который возникал при сетевой ошибке во время вычитывания ответа. +* Исправлен редкий deadlock в клиентской библиотеке ZooKeeper, который возникал при сетевой ошибке во время вычитывания ответа ([c315200](https://github.com/yandex/ClickHouse/commit/c315200e64b87e44bdf740707fc857d1fdf7e947)). * Исправлена ошибка при CAST в Nullable типы ([#1322](https://github.com/yandex/ClickHouse/issues/1322)). * Исправлен неправильный результат функции `maxIntersection()` в случае совпадения границ отрезков ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2657)). -* Исправлена работа движка SummingMergeTree со столбцами типа AggregateFunction ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2665)). * Исправлено неверное преобразование цепочки OR-выражений в аргументе функции ([chenxing-xc](https://github.com/yandex/ClickHouse/pull/2663)). * Исправлена деградация производительности запросов, содержащих выражение `IN (подзапрос)` внутри другого подзапроса ([#2571](https://github.com/yandex/ClickHouse/issues/2571)). -* Исправлена несовместимость серверов разных версий при распределённых запросах, использующих функцию `CAST` не в верхнем регистре. +* Исправлена несовместимость серверов разных версий при распределённых запросах, использующих функцию `CAST` не в верхнем регистре ([fe8c4d6](https://github.com/yandex/ClickHouse/commit/fe8c4d64e434cacd4ceef34faa9005129f2190a5)). * Добавлено недостающее квотирование идентификаторов при запросах к внешним СУБД ([#2635](https://github.com/yandex/ClickHouse/issues/2635)). From c3b45514267a2a18cbfe95d1bfea796d4311ae09 Mon Sep 17 00:00:00 2001 From: alesapin Date: Wed, 25 Jul 2018 19:38:29 +0300 Subject: [PATCH 155/425] CLICKHOUSE-3832: Add interserver-side authentification. --- dbms/programs/server/InterserverIOHTTPHandler.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dbms/programs/server/InterserverIOHTTPHandler.cpp b/dbms/programs/server/InterserverIOHTTPHandler.cpp index 3cdbaa69b64..8c56b66ed05 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.cpp +++ b/dbms/programs/server/InterserverIOHTTPHandler.cpp @@ -29,14 +29,20 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque LOG_TRACE(log, "Request URI: " << request.getURI()); - /// NOTE: You can do authentication here if you need to. + const auto & config = server.config(); + + if (config.has("interserver_http_credentials.user")) { + String user = config.getString("interserver_http_credentials.user"); + String password = config.getString("interserver_http_credentials.password", ""); + Poco::Net::HTTPCredentials creds(user, password); + creds.authenticate(request, response); + } String endpoint_name = params.get("endpoint"); bool compress = params.get("compress") == "true"; ReadBufferFromIStream body(request.stream()); - const auto & config = server.config(); unsigned keep_alive_timeout = config.getUInt("keep_alive_timeout", 10); WriteBufferFromHTTPServerResponse out(request, response, keep_alive_timeout); From 570111c41f30343e2317dab392dc3ac2374c3371 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 25 Jul 2018 19:41:02 +0300 Subject: [PATCH 156/425] Update CHANGELOG_RU.md --- CHANGELOG_RU.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index 8b8f5535ddf..16e8f6a2f90 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -5,7 +5,7 @@ * Поддержка произвольных типов для семейства агрегатных функций `uniq*` ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). * Поддержка произвольных типов в операторах сравнения ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). * Возможность в `users.xml` указывать маску подсети в формате `10.0.0.1/255.255.255.0`. Это необходимо для использования "дырявых" масок IPv6 сетей ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). -* Добавлена функция `arrayDistinct()` ([#2670](https://github.com/yandex/ClickHouse/pull/2670)). +* Добавлена функция `arrayDistinct` ([#2670](https://github.com/yandex/ClickHouse/pull/2670)). * Движок SummingMergeTree теперь может работать со столбцами типа AggregateFunction ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2566)). ### Улучшения: From 489f1f84f1cb66d1270c6eee4aef231d6176223d Mon Sep 17 00:00:00 2001 From: VadimPE Date: Wed, 25 Jul 2018 21:17:54 +0300 Subject: [PATCH 157/425] CLICKHOUSE-3837 fix TableFunctionRemote --- dbms/src/TableFunctions/TableFunctionRemote.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/TableFunctions/TableFunctionRemote.cpp b/dbms/src/TableFunctions/TableFunctionRemote.cpp index 128070fb5f1..9bea9e881ca 100644 --- a/dbms/src/TableFunctions/TableFunctionRemote.cpp +++ b/dbms/src/TableFunctions/TableFunctionRemote.cpp @@ -317,14 +317,14 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C auto structure_remote_table = getStructureOfRemoteTable(*cluster, remote_database, remote_table, context, remote_table_function_ptr); StoragePtr res = remote_table_function_ptr ? - res = StorageDistributed::createWithOwnCluster( + StorageDistributed::createWithOwnCluster( getName(), structure_remote_table, remote_table_function_ptr, cluster, context) - : res = StorageDistributed::createWithOwnCluster( + : StorageDistributed::createWithOwnCluster( getName(), structure_remote_table, remote_database, From d619be0596dfcffdbfe14847cfddc2ad3e52cf4d Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 25 Jul 2018 21:20:09 +0300 Subject: [PATCH 158/425] Update CHANGELOG_RU.md --- CHANGELOG_RU.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG_RU.md b/CHANGELOG_RU.md index 16e8f6a2f90..8150e1f5a57 100644 --- a/CHANGELOG_RU.md +++ b/CHANGELOG_RU.md @@ -23,6 +23,9 @@ * Исправлена несовместимость серверов разных версий при распределённых запросах, использующих функцию `CAST` не в верхнем регистре ([fe8c4d6](https://github.com/yandex/ClickHouse/commit/fe8c4d64e434cacd4ceef34faa9005129f2190a5)). * Добавлено недостающее квотирование идентификаторов при запросах к внешним СУБД ([#2635](https://github.com/yandex/ClickHouse/issues/2635)). +### Обратно несовместимые изменения: +* Не работает преобразование строки, содержащей число ноль, в DateTime. Пример: `SELECT toDateTime('0')`. По той же причине не работает `DateTime DEFAULT '0'` в таблицах, а также `0` в словарях. Решение: заменить `0` на `0000-00-00 00:00:00`. + ## ClickHouse release 1.1.54394, 2018-07-12 From dc2c22ffff86b88ecc665f9d0543c2cf7e7eb705 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 25 Jul 2018 21:46:16 +0300 Subject: [PATCH 159/425] Update IFactoryWithAliases.h --- dbms/src/Common/IFactoryWithAliases.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Common/IFactoryWithAliases.h b/dbms/src/Common/IFactoryWithAliases.h index dc341782894..9006a3c7cfd 100644 --- a/dbms/src/Common/IFactoryWithAliases.h +++ b/dbms/src/Common/IFactoryWithAliases.h @@ -42,7 +42,7 @@ public: CaseInsensitive }; - /** Register additional name for creater + /** Register additional name for creator * real_name have to be already registered. */ void registerAlias(const String & alias_name, const String & real_name, CaseSensitiveness case_sensitiveness = CaseSensitive) From 57f9abf6b2df50bbb4d2ff71841ce0368750a56f Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 25 Jul 2018 22:34:58 +0300 Subject: [PATCH 160/425] Added clarifications for ZooKeeper operations [#CLICKHOUSE-3] --- docs/en/operations/tips.md | 4 ++++ docs/ru/operations/tips.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/en/operations/tips.md b/docs/en/operations/tips.md index 9378c25fab1..4d999062a5d 100644 --- a/docs/en/operations/tips.md +++ b/docs/en/operations/tips.md @@ -113,6 +113,10 @@ With the default settings, ZooKeeper is a time bomb: This bomb must be defused. +If you want to move data between different ZooKeeper clusters, never move it by hand-written script, because it will produce wrong data for sequential nodes. Never use "zkcopy" tool, by the same reason: https://github.com/ksprojects/zkcopy/issues/15 + +If you want to split ZooKeeper cluster, proper way is to increase number of replicas and then reconfigure it as two independent clusters. + The ZooKeeper (3.5.1) configuration below is used in the Yandex.Metrica production environment as of May 20, 2017: zoo.cfg: diff --git a/docs/ru/operations/tips.md b/docs/ru/operations/tips.md index 315a8fb07fa..a1ddc9246e5 100644 --- a/docs/ru/operations/tips.md +++ b/docs/ru/operations/tips.md @@ -107,6 +107,10 @@ XFS также подходит, но не так тщательно проте Лучше использовать свежую версию ZooKeeper, как минимум 3.4.9. Версия в стабильных дистрибутивах Linux может быть устаревшей. +Никогда не используете написанные вручную скрипты для переноса данных между разными ZooKeeper кластерами, потому что результат будет некорректный для sequential нод. Никогда не используйте утилиту "zkcopy", по той же причине: https://github.com/ksprojects/zkcopy/issues/15 + +Если вы хотите разделить существующий ZooKeeper кластер на два, правильный способ - увеличить количество его реплик, а затем переконфигурировать его как два независимых кластера. + С настройками по умолчанию, ZooKeeper является бомбой замедленного действия: > Сервер ZooKeeper не будет удалять файлы со старыми снепшоты и логами при использовании конфигурации по умолчанию (см. autopurge), это является ответственностью оператора. From 1c75c191067bfeb291bd19a2d1f81dde8d1a5b0a Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Thu, 26 Jul 2018 12:36:28 +0800 Subject: [PATCH 161/425] Set up dns server for kafka integration tests. --- .../tests/integration/helpers/docker_compose_kafka.yml | 10 ++++++++++ dbms/tests/integration/test_storage_kafka/test.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dbms/tests/integration/helpers/docker_compose_kafka.yml b/dbms/tests/integration/helpers/docker_compose_kafka.yml index 42dd154b1e8..0afef7bcda6 100644 --- a/dbms/tests/integration/helpers/docker_compose_kafka.yml +++ b/dbms/tests/integration/helpers/docker_compose_kafka.yml @@ -22,3 +22,13 @@ services: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 depends_on: - kafka_zookeeper + + dns-proxy-server: + image: defreitas/dns-proxy-server + hostname: dns.mageddo + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /etc/resolv.conf:/etc/resolv.conf + ports: + - 5380:5380 + network_mode: bridge diff --git a/dbms/tests/integration/test_storage_kafka/test.py b/dbms/tests/integration/test_storage_kafka/test.py index d522d775dc7..e5c3d9b2775 100644 --- a/dbms/tests/integration/test_storage_kafka/test.py +++ b/dbms/tests/integration/test_storage_kafka/test.py @@ -23,7 +23,7 @@ def started_cluster(): yield cluster finally: - cluster.shutdown() + cluster.shutdown(False) def test_kafka_json(started_cluster): instance.query(''' From 63ac512c6072252ce3f013e065509dde16baa99c Mon Sep 17 00:00:00 2001 From: VadimPE Date: Thu, 26 Jul 2018 11:06:06 +0300 Subject: [PATCH 162/425] CLICKHOUSE-3837 add tests --- .../00675_remote_with_table_function.reference | 2 ++ .../0_stateless/00675_remote_with_table_function.sql | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00675_remote_with_table_function.reference create mode 100644 dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql diff --git a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.reference b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.reference new file mode 100644 index 00000000000..7290ba859f4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.reference @@ -0,0 +1,2 @@ +4 +4 diff --git a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql new file mode 100644 index 00000000000..3cb63944d00 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS remote_test; +CREATE TABLE remote_test(a1 UInt8) ENGINE=Memory; +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(1); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(2); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(3); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(4); +SELECT COUNT(*) FROM remote('127.0.0.1', default.remote_test); +SELECT count(*) FROM remote('127.0.0.1', merge(default, '^remote_test')); + From 175f56413731dddadfba6bd2def01e071e8a881b Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 26 Jul 2018 12:53:59 +0300 Subject: [PATCH 163/425] CLICKHOUSE-3832: Fix bracket --- dbms/programs/server/InterserverIOHTTPHandler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dbms/programs/server/InterserverIOHTTPHandler.cpp b/dbms/programs/server/InterserverIOHTTPHandler.cpp index 8c56b66ed05..e7343989590 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.cpp +++ b/dbms/programs/server/InterserverIOHTTPHandler.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -31,7 +32,8 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque const auto & config = server.config(); - if (config.has("interserver_http_credentials.user")) { + if (config.has("interserver_http_credentials.user")) + { String user = config.getString("interserver_http_credentials.user"); String password = config.getString("interserver_http_credentials.password", ""); Poco::Net::HTTPCredentials creds(user, password); From 28548183783398379984382c7ca4ca29ecdbfc77 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Thu, 26 Jul 2018 14:38:07 +0300 Subject: [PATCH 164/425] Update 00675_remote_with_table_function.sql --- .../00675_remote_with_table_function.sql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql index 3cb63944d00..a3e46af05d2 100644 --- a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql +++ b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql @@ -1,9 +1,9 @@ -DROP TABLE IF EXISTS remote_test; -CREATE TABLE remote_test(a1 UInt8) ENGINE=Memory; -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(1); -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(2); -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(3); -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(4); -SELECT COUNT(*) FROM remote('127.0.0.1', default.remote_test); -SELECT count(*) FROM remote('127.0.0.1', merge(default, '^remote_test')); - +DROP TABLE IF EXISTS test.remote_test; +CREATE TABLE test.remote_test(a1 UInt8) ENGINE=Memory; +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(1); +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(2); +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(3); +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(4); +SELECT COUNT(*) FROM remote('127.0.0.1', test.remote_test); +SELECT count(*) FROM remote('127.0.0.1', merge(test, '^remote_test')); +DROP TABLE test.remote_test; From ec202a7fd0531af8850e307951b97f4642ec1c86 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 26 Jul 2018 17:40:33 +0300 Subject: [PATCH 165/425] Allow to start cluster with Kafka without pytest #2725 --- dbms/tests/integration/test_storage_kafka/test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dbms/tests/integration/test_storage_kafka/test.py b/dbms/tests/integration/test_storage_kafka/test.py index e5c3d9b2775..5c73ef94962 100644 --- a/dbms/tests/integration/test_storage_kafka/test.py +++ b/dbms/tests/integration/test_storage_kafka/test.py @@ -51,3 +51,8 @@ CREATE TABLE test.kafka (key UInt64, value UInt64) with open(p.join(p.dirname(__file__), 'test_kafka_json.reference')) as reference: assert TSV(result) == TSV(reference) instance.query('DROP TABLE test.kafka') + +if __name__ == '__main__': + cluster.start() + raw_input("Cluster created, press any key to destroy...") + cluster.shutdown() From afd57d0372d9836a1b94190c51e3c51b5faf5aeb Mon Sep 17 00:00:00 2001 From: BayoNet Date: Thu, 26 Jul 2018 17:41:59 +0300 Subject: [PATCH 166/425] - Functions with special support for NULL - Descriptions for functons: arrayResize, multiIf, getSizeOfEnumType, toColumnTypeName, dumpColumnStructure, defaultValueOfArgumentType, indexHint, replicate. - Enum description is updated --- docs/ru/data_types/enum.md | 96 +++++- docs/ru/functions/array_functions.md | 94 +++++- docs/ru/functions/conditional_functions.md | 47 ++- docs/ru/functions/other_functions.md | 281 +++++++++++++++++- .../ru/functions/type_conversion_functions.md | 18 ++ docs/ru/operators/index.md | 2 + 6 files changed, 520 insertions(+), 18 deletions(-) diff --git a/docs/ru/data_types/enum.md b/docs/ru/data_types/enum.md index ff977431959..9f0636c36c6 100644 --- a/docs/ru/data_types/enum.md +++ b/docs/ru/data_types/enum.md @@ -1,18 +1,102 @@ + + # Enum -Enum8 или Enum16. Представляет собой конечное множество строковых значений, сохраняемых более эффективно, чем это делает тип данных `String`. +Семейство типов. Включает в себя типы `Enum8` и `Enum16`. `Enum` сохраняет конечный набор пар `'строка' = целое число`. Все операции с данными типа `Enum` ClickHouse выполняет как с числами, однако пользователь при этом работает со строковыми константами. Это более эффективно с точки зрения производительности, чем работа с типом данных `String`. -Пример: +Подтипы: -```text -Enum8('hello' = 1, 'world' = 2) +- `Enum8` состоит из пар `'String' = Int8`. +- `Enum16` состоит из пар `'String' = Int16`. + +## Примеры применения + +Создадим таблицу со столбцом типа `Enum8('hello' = 1, 'world' = 2)`. + +``` +CREATE TABLE t_enum +( + x Enum8('hello' = 1, 'world' = 2) +) +ENGINE = TinyLog ``` -- тип данных с двумя возможными значениями - 'hello' и 'world'. +В столбец `x` можно сохранять только значения, перечисленные при определении типа, т.е. `'hello'` или `'world'`. Если попытаться сохранить другое значение, ClickHouse сгенерирует исключение. + +``` +:) INSERT INTO t_enum Values('hello'),('world'),('hello') + +INSERT INTO t_enum VALUES + +Ok. + +3 rows in set. Elapsed: 0.002 sec. + +:) insert into t_enum values('a') + +INSERT INTO t_enum VALUES + + +Exception on client: +Code: 49. DB::Exception: Unknown element 'a' for type Enum8('hello' = 1, 'world' = 2) +``` + +При запросе данных из таблицы ClickHouse выдаст строковые значения из `Enum`. + +``` +SELECT * FROM t_enum + +┌─x─────┐ +│ hello │ +│ world │ +│ hello │ +└───────┘ +``` +Если необходимо увидеть цифровые эквиваленты строкам, то необходимо привести тип. + +``` +SELECT CAST(x, 'Int8') FROM t_enum + +┌─CAST(x, 'Int8')─┐ +│ 1 │ +│ 2 │ +│ 1 │ +└─────────────────┘ +``` + +Чтобы создать значение типа Enum в запросе, также необходима функция `CAST`. + +``` +SELECT toTypeName(CAST('a', 'Enum8(\'a\' = 1, \'b\' = 2)')) + +┌─toTypeName(CAST('a', 'Enum8(\'a\' = 1, \'b\' = 2)'))─┐ +│ Enum8('a' = 1, 'b' = 2) │ +└──────────────────────────────────────────────────────┘ +``` + +## Общие правила и особенности использования Для каждого из значений прописывается число в диапазоне `-128 .. 127` для `Enum8` или в диапазоне `-32768 .. 32767` для `Enum16`. Все строки должны быть разными, числа - тоже. Разрешена пустая строка. При указании такого типа (в определении таблицы), числа могут идти не подряд и в произвольном порядке. При этом, порядок не имеет значения. -В оперативке столбец такого типа представлен так же, как `Int8` или `Int16` соответствующими числовыми значениями. +Ни строка, ни цифровое значение в `Enum` не могут быть [NULL](../query_language/syntax.md#null-literal). + +`Enum` может быть передан в тип [Nullable](nullable.md#data_type-nullable). Таким образом, если создать таблицу запросом + +``` +CREATE TABLE t_enum_nullable +( + x Nullable( Enum8('hello' = 1, 'world' = 2) ) +) +ENGINE = TinyLog +``` + +, то в ней можно будет хранить не только `'hello'` и `'world'`, но и `NULL`. + +``` +INSERT INTO t_enum_null Values('hello'),('world'),(NULL) +``` + +В оперативке столбец типа `Enum` представлен так же, как `Int8` или `Int16` соответствующими числовыми значениями. При чтении в текстовом виде, парсит значение как строку и ищет соответствующую строку из множества значений Enum-а. Если не находит - кидается исключение. При записи в текстовом виде, записывает значение как соответствующую строку. Если в данных столбца есть мусор - числа не из допустимого множества, то кидается исключение. При чтении и записи в бинарном виде, оно осуществляется так же, как для типов данных Int8, Int16. Неявное значение по умолчанию - это значение с минимальным номером. diff --git a/docs/ru/functions/array_functions.md b/docs/ru/functions/array_functions.md index 79818574fd7..cdd3a810490 100644 --- a/docs/ru/functions/array_functions.md +++ b/docs/ru/functions/array_functions.md @@ -75,11 +75,48 @@ n должен быть любым целочисленным типом. Проверяет наличие элемента elem в массиве arr. Возвращает 0, если элемента в массиве нет, или 1, если есть. +`NULL` обрабатывается как значение. + +``` +SELECT has([1, 2, NULL], NULL) + +┌─has([1, 2, NULL], NULL)─┐ +│ 1 │ +└─────────────────────────┘ +``` + ## indexOf(arr, x) -Возвращает индекс элемента x (начиная с 1), если он есть в массиве, или 0, если его нет. +Возвращает индекс первого элемента x (начиная с 1), если он есть в массиве, или 0, если его нет. + +Пример: + +``` +:) select indexOf([1,3,NULL,NULL],NULL) + +SELECT indexOf([1, 3, NULL, NULL], NULL) + +┌─indexOf([1, 3, NULL, NULL], NULL)─┐ +│ 3 │ +└───────────────────────────────────┘ +``` + +Элементы, равные `NULL`, обрабатываются как обычные значения. ## countEqual(arr, x) -Возвращает количество элементов массива, равных x. Эквивалентно arrayCount(elem -> elem = x, arr). +Возвращает количество элементов массива, равных x. Эквивалентно arrayCount(elem -> elem = x, arr). + +Элементы `NULL` обрабатываются как отдельные значения. + +Пример: + +``` +SELECT countEqual([1, 2, NULL, NULL], NULL) + +┌─countEqual([1, 2, NULL, NULL], NULL)─┐ +│ 2 │ +└──────────────────────────────────────┘ +``` + ## arrayEnumerate(arr) Возвращает массив \[1, 2, 3, ..., length(arr)\] @@ -232,7 +269,7 @@ arrayPushBack(array, single_value) **Аргументы** - `array` - Массив. -- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../data_types/index.md#data_types)". +- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../data_types/index.md#data_types)". Может быть равно `NULL`. Функция добавит элемент `NULL` в массив, а тип элементов массива преобразует в `Nullable`. **Пример** @@ -245,6 +282,8 @@ SELECT arrayPushBack(['a'], 'b') AS res └───────────┘ ``` + + ## arrayPushFront Добавляет один элемент в начало массива. @@ -256,7 +295,7 @@ arrayPushFront(array, single_value) **Аргументы** - `array` - Массив. -- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../data_types/index.md#data_types)". +- `single_value` - Одиночное значение. В массив с числам можно добавить только числа, в массив со строками только строки. При добавлении чисел ClickHouse автоматически приводит тип `single_value` к типу данных массива. Подробнее о типах данных в ClickHouse читайте в разделе "[Типы данных](../data_types/index.md#data_types)". Может быть равно `NULL`. Функция добавит элемент `NULL` в массив, а тип элементов массива преобразует в `Nullable`. **Пример** @@ -269,6 +308,43 @@ SELECT arrayPushBack(['b'], 'a') AS res └───────────┘ ``` +## arrayResize + +Изменяет длину массива. + +``` +arrayResize(array, size[, extender]) +``` + +**Параметры:** + +- `array` — массив. +- `size` — необходимая длина массива. + - Если `size` меньше изначального размера массива, то массив обрезается справа. + - Если `size` больше изначального размера массива, массив дополняется справа значениями `extender` или значениями по умолчанию для типа данных элементов массива. +- `extender` — значение для дополнения массива. Может быть `NULL`. + +**Возвращаемое значение:** + +Массив длины `size`. + +**Примеры вызовов** + +``` +SELECT arrayResize([1], 3) + +┌─arrayResize([1], 3)─┐ +│ [1,0,0] │ +└─────────────────────┘ +``` +``` +SELECT arrayResize([1], 3, NULL) + +┌─arrayResize([1], 3, NULL)─┐ +│ [1,NULL,NULL] │ +└───────────────────────────┘ +``` + ## arraySlice Возвращает срез массива. @@ -286,14 +362,15 @@ arraySlice(array, offset[, length]) **Пример** ```sql -SELECT arraySlice([1, 2, 3, 4, 5], 2, 3) AS res +SELECT arraySlice([1, 2, NULL, 4, 5], 2, 3) AS res ``` ``` -┌─res─────┐ -│ [2,3,4] │ -└─────────┘ +┌─res────────┐ +│ [2,NULL,4] │ +└────────────┘ ``` +Элементы массива равные `NULL` обрабатываются как обычные значения. ## arrayUniq(arr, ...) Если передан один аргумент, считает количество разных элементов в массиве. @@ -303,4 +380,3 @@ SELECT arraySlice([1, 2, 3, 4, 5], 2, 3) AS res ## arrayJoin(arr) Особенная функция. Смотрите раздел ["Функция arrayJoin"](array_join.md#functions_arrayjoin). - diff --git a/docs/ru/functions/conditional_functions.md b/docs/ru/functions/conditional_functions.md index f7c58807138..a6ce4c73adb 100644 --- a/docs/ru/functions/conditional_functions.md +++ b/docs/ru/functions/conditional_functions.md @@ -1,5 +1,48 @@ # Условные функции ## if(cond, then, else), оператор cond ? then : else -Возвращает then, если cond != 0 или else, если cond = 0. -cond должно иметь тип UInt8, а then и else должны иметь тип, для которого есть наименьший общий тип. + +Возвращает `then`, если `cond != 0` или `else`, если `cond = 0`. +`cond` должно иметь тип `UInt8`, а `then` и `else` должны иметь тип, для которого есть наименьший общий тип. + +`then` и `else` могут быть `NULL` + +## multiIf + +Позволяет более компактно записать оператор [CASE](../operators/index.html#operator_case) в запросе. + +``` +multiIf(cond_1, then_1, cond_2, then_2...else) +``` + +**Параметры** + +- `cond_N` — Условие, при выполнении которого функция вернёт `then_N`. +- `then_N` — Результат функции при выполнении. +- `else` — Результат функции, если ни одно из условий не выполнено. + +Функция принимает `2N+1` параметров. + +**Возвращаемые значения** + +Функция возвращает одно из значений `then_N` или `else`, в зависимости от условий `cond_N`. + +**Пример** + +Рассмотрим таблицу + +``` +┌─x─┬────y─┐ +│ 1 │ ᴺᵁᴸᴸ │ +│ 2 │ 3 │ +└───┴──────┘ +``` + +Выполним запрос `SELECT multiIf(isNull(y), x, y < 3, y, NULL) FROM t_null`. Результат: + +``` +┌─multiIf(isNull(y), x, less(y, 3), y, NULL)─┐ +│ 1 │ +│ ᴺᵁᴸᴸ │ +└────────────────────────────────────────────┘ +``` diff --git a/docs/ru/functions/other_functions.md b/docs/ru/functions/other_functions.md index b9aecec9f7d..645ab814056 100644 --- a/docs/ru/functions/other_functions.md +++ b/docs/ru/functions/other_functions.md @@ -7,9 +7,21 @@ Вычисляет приблизительную ширину при выводе значения в текстовом (tab-separated) виде на консоль. Функция используется системой для реализации Pretty форматов. +`NULL` представляется как строка, соответствующая отображению `NULL` в форматах `Pretty`. + +``` +SELECT visibleWidth(NULL) + +┌─visibleWidth(NULL)─┐ +│ 4 │ +└────────────────────┘ +``` + ## toTypeName(x) Возвращает строку, содержащую имя типа переданного аргумента. +Если на вход функции передать `NULL`, то она вернёт тип `Nullable(Nothing)`, что соответствует внутреннему представлению `NULL` в ClickHouse. + ## blockSize() Получить размер блока. В ClickHouse выполнение запроса всегда идёт по блокам (наборам кусочков столбцов). Функция позволяет получить размер блока, для которого её вызвали. @@ -19,7 +31,7 @@ В ClickHouse полноценные столбцы и константы представлены в памяти по-разному. Функции по-разному работают для аргументов-констант и обычных аргументов (выполняется разный код), хотя результат почти всегда должен быть одинаковым. Эта функция предназначена для отладки такого поведения. ## ignore(...) -Принимает любые аргументы, всегда возвращает 0. +Принимает любые аргументы, в т.ч. `NULL`, всегда возвращает 0. При этом, аргумент всё равно вычисляется. Это может использоваться для бенчмарков. ## sleep(seconds) @@ -261,3 +273,270 @@ FROM ## MACStringToOUI(s) Принимает MAC адрес в формате AA:BB:CC:DD:EE:FF (числа в шестнадцатеричной форме через двоеточие). Возвращает первые три октета как число в формате UInt64. Если MAC адрес в неправильном формате, то возвращает 0. + +## getSizeOfEnumType + +Возвращает количество полей в [Enum](../data_types/enum.md#data_type-enum). + +``` +getSizeOfEnumType(value) +``` + +**Параметры** + +- `value` — Значение типа `Enum`. + + +**Возвращаемые значения** + +- Количество полей входного значения типа `Enum`. +- Исключение, если тип не `Enum`. + +**Пример** + +``` +SELECT getSizeOfEnumType( CAST('a' AS Enum8('a' = 1, 'b' = 2) ) ) AS x + +┌─x─┐ +│ 2 │ +└───┘ +``` + +## toColumnTypeName + +Возвращает имя класса, которым представлен тип данных столбца в оперативной памяти. + +``` +toColumnTypeName(value) +``` + +**Параметры** + +- `value` — Значение произвольного типа. + +**Возвращаемые значения** + +- Строка с именем класса, который используется для представления типа данных `value` в оперативной памяти. + +**Пример разницы между `toTypeName` и `toColumnTypeName`** + +``` +:) select toTypeName(cast('2018-01-01 01:02:03' AS DateTime)) + +SELECT toTypeName(CAST('2018-01-01 01:02:03', 'DateTime')) + +┌─toTypeName(CAST('2018-01-01 01:02:03', 'DateTime'))─┐ +│ DateTime │ +└─────────────────────────────────────────────────────┘ + +1 rows in set. Elapsed: 0.008 sec. + +:) select toColumnTypeName(cast('2018-01-01 01:02:03' AS DateTime)) + +SELECT toColumnTypeName(CAST('2018-01-01 01:02:03', 'DateTime')) + +┌─toColumnTypeName(CAST('2018-01-01 01:02:03', 'DateTime'))─┐ +│ Const(UInt32) │ +└───────────────────────────────────────────────────────────┘ +``` + +В этом примере хорошо видно, что тип данных `DateTime` хранится в памяти как `Const(UInt32)`. + +## dumpColumnStructure + +Выводит развернутое описание структур данных в оперативной памяти + +``` +dumpColumnStructure(value) +``` + +**Параметры** + +- `value` — Значение произвольного типа. + +**Возвращаемые значения** + +- Строка с описанием структуры, которая используется для представления типа данных `value` в оперативной памяти. + +**Пример** + +``` +SELECT dumpColumnStructure(CAST('2018-01-01 01:02:03', 'DateTime')) + +┌─dumpColumnStructure(CAST('2018-01-01 01:02:03', 'DateTime'))─┐ +│ DateTime, Const(size = 1, UInt32(size = 1)) │ +└──────────────────────────────────────────────────────────────┘ +``` + +## defaultValueOfArgumentType + +Выводит значение по умолчанию для типа данных. + +Не учитывает значения по умолчанию для столбцов, заданные пользователем. + +``` +defaultValueOfArgumentType(expression) +``` + +**Параметры** + +- `expression` — Значение произвольного типа или выражение, результатом которого является значение произвольного типа. + +**Возвращаемые значения** + +- `0` для чисел; +- Пустая строка для строк; +- `ᴺᵁᴸᴸ` для [Nullable](../data_types/nullable.md#data_type-nullable). + +**Пример** + +``` +:) SELECT defaultValueOfArgumentType( CAST(1 AS Int8) ) + +SELECT defaultValueOfArgumentType(CAST(1, 'Int8')) + +┌─defaultValueOfArgumentType(CAST(1, 'Int8'))─┐ +│ 0 │ +└─────────────────────────────────────────────┘ + +1 rows in set. Elapsed: 0.002 sec. + +:) SELECT defaultValueOfArgumentType( CAST(1 AS Nullable(Int8) ) ) + +SELECT defaultValueOfArgumentType(CAST(1, 'Nullable(Int8)')) + +┌─defaultValueOfArgumentType(CAST(1, 'Nullable(Int8)'))─┐ +│ ᴺᵁᴸᴸ │ +└───────────────────────────────────────────────────────┘ + +1 rows in set. Elapsed: 0.002 sec. +``` + +## indexHint + +Выводит данные, попавшие в диапазон, выбранный по индексу без фильтрации по указанному в качестве аргумента выражению. + +Переданное в функцию выражение не вычисляется, но при этом ClickHouse применяет к этому выражению индекс таким же образом, как если бы выражение участвовало в запросе без `indexHint`. + + +**Возвращаемое значение** + +- 1. + + +**Пример** + +Рассмотрим таблицу с тестовыми данными [ontime](../getting_started/example_datasets/ontime.md#example_datasets-ontime). + +``` +SELECT count() FROM ontime + +┌─count()─┐ +│ 4276457 │ +└─────────┘ +``` + +В таблице есть индексы по полям `(FlightDate, (Year, FlightDate))`. + +Выполним выборку по дате следующим образом: + +``` +:) SELECT FlightDate AS k, count() FROM ontime GROUP BY k ORDER BY k + +SELECT + FlightDate AS k, + count() +FROM ontime +GROUP BY k +ORDER BY k ASC + +┌──────────k─┬─count()─┐ +│ 2017-01-01 │ 13970 │ +│ 2017-01-02 │ 15882 │ +........................ +│ 2017-09-28 │ 16411 │ +│ 2017-09-29 │ 16384 │ +│ 2017-09-30 │ 12520 │ +└────────────┴─────────┘ + +273 rows in set. Elapsed: 0.072 sec. Processed 4.28 million rows, 8.55 MB (59.00 million rows/s., 118.01 MB/s.) +``` + +В этой выборке индекс не используется и ClickHouse обработал всю таблицу (`Processed 4.28 million rows`). Для подключения индекса выберем конкретную дату и выполним следующий запрос: + +``` +:) SELECT FlightDate AS k, count() FROM ontime WHERE k = '2017-09-15' GROUP BY k ORDER BY k + +SELECT + FlightDate AS k, + count() +FROM ontime +WHERE k = '2017-09-15' +GROUP BY k +ORDER BY k ASC + +┌──────────k─┬─count()─┐ +│ 2017-09-15 │ 16428 │ +└────────────┴─────────┘ + +1 rows in set. Elapsed: 0.014 sec. Processed 32.74 thousand rows, 65.49 KB (2.31 million rows/s., 4.63 MB/s.) +``` + +В последней строке выдачи видно, что благодаря использованию индекса, ClickHouse обработал значительно меньшее количество строк (`Processed 32.74 thousand rows`). + + +Теперь передадим выражение `k = '2017-09-15'` в функцию `indexHint`: + +``` +:) SELECT FlightDate AS k, count() FROM ontime WHERE indexHint(k = '2017-09-15') GROUP BY k ORDER BY k + +SELECT + FlightDate AS k, + count() +FROM ontime +WHERE indexHint(k = '2017-09-15') +GROUP BY k +ORDER BY k ASC + +┌──────────k─┬─count()─┐ +│ 2017-09-14 │ 7071 │ +│ 2017-09-15 │ 16428 │ +│ 2017-09-16 │ 1077 │ +│ 2017-09-30 │ 8167 │ +└────────────┴─────────┘ + +4 rows in set. Elapsed: 0.004 sec. Processed 32.74 thousand rows, 65.49 KB (8.97 million rows/s., 17.94 MB/s.) +``` + +В ответе на запрос видно, что ClickHouse применил индекс таким же образом, что и в предыдущий раз (`Processed 32.74 thousand rows`). Однако по результирующему набору строк видно, что выражение `k = '2017-09-15'` не использовалось при формировании результата. + +Поскольку индекс в ClickHouse разреженный, то при чтении диапазона в ответ попадают "лишние" данные, в данном случае соседние даты. Функция `indexHint` позволяет их увидеть. + +## replicate + +Создает массив, заполненный одним значением. + +Используется для внутренней реализации [arrayJoin](array_join.md#functions_arrayjoin). + +``` +replicate(x, arr) +``` + +**Параметры** + +- `arr` — Исходный массив. ClickHouse создаёт новый массив такой же длины как исходный и заполняет его значением `x`. +- `x` — Значение, которым будет заполнен результирующий массив. + +**Выходное значение** + +- Массив, заполненный значением `x`. + +**Пример** + +``` +SELECT replicate(1, ['a', 'b', 'c']) + +┌─replicate(1, ['a', 'b', 'c'])─┐ +│ [1,1,1] │ +└───────────────────────────────┘ +``` diff --git a/docs/ru/functions/type_conversion_functions.md b/docs/ru/functions/type_conversion_functions.md index 7676586db6f..3226149b715 100644 --- a/docs/ru/functions/type_conversion_functions.md +++ b/docs/ru/functions/type_conversion_functions.md @@ -113,3 +113,21 @@ SELECT ``` Преобразование в FixedString(N) работает только для аргументов типа String или FixedString(N). + +Поддержано преобразование к типу [Nullable](../data_types/nullable.md#data_type-nullable) и обратно. Пример: + +``` +SELECT toTypeName(x) FROM t_null + +┌─toTypeName(x)─┐ +│ Int8 │ +│ Int8 │ +└───────────────┘ + +SELECT toTypeName(CAST(x, 'Nullable(UInt16)')) FROM t_null + +┌─toTypeName(CAST(x, 'Nullable(UInt16)'))─┐ +│ Nullable(UInt16) │ +│ Nullable(UInt16) │ +└─────────────────────────────────────────┘ +``` diff --git a/docs/ru/operators/index.md b/docs/ru/operators/index.md index c3b0a857a79..2f9198ffa63 100644 --- a/docs/ru/operators/index.md +++ b/docs/ru/operators/index.md @@ -83,6 +83,8 @@ Условный оператор сначала вычисляет значения b и c, затем проверяет выполнение условия a, и только после этого возвращает соответствующее значение. Если в качестве b или с выступает функция arrayJoin(), то размножение каждой строки произойдет вне зависимости от условия а. + + ## Условное выражение ```sql From 6abbfbce871bae9497c82dcacf935fc0f33e16ef Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 26 Jul 2018 18:10:57 +0300 Subject: [PATCH 167/425] CLICKHOUSE-3832: Add HTTP Basic authentification in replication protocol --- .../server/InterserverIOHTTPHandler.cpp | 55 ++++++-- .../server/InterserverIOHTTPHandler.h | 2 + dbms/programs/server/Server.cpp | 11 ++ dbms/src/IO/ReadWriteBufferFromHTTP.cpp | 4 + dbms/src/IO/ReadWriteBufferFromHTTP.h | 2 + dbms/src/Interpreters/Context.cpp | 13 ++ dbms/src/Interpreters/Context.h | 5 + .../Storages/MergeTree/DataPartsExchange.cpp | 11 +- .../Storages/MergeTree/DataPartsExchange.h | 2 + .../Storages/StorageReplicatedMergeTree.cpp | 6 +- .../test_replication_credentials/__init__.py | 0 .../configs/credentials1.xml | 7 + .../configs/credentials2.xml | 7 + .../configs/no_credentials.xml | 3 + .../configs/remote_servers.xml | 58 ++++++++ .../test_replication_credentials/test.py | 132 ++++++++++++++++++ 16 files changed, 303 insertions(+), 15 deletions(-) create mode 100644 dbms/tests/integration/test_replication_credentials/__init__.py create mode 100644 dbms/tests/integration/test_replication_credentials/configs/credentials1.xml create mode 100644 dbms/tests/integration/test_replication_credentials/configs/credentials2.xml create mode 100644 dbms/tests/integration/test_replication_credentials/configs/no_credentials.xml create mode 100644 dbms/tests/integration/test_replication_credentials/configs/remote_servers.xml create mode 100644 dbms/tests/integration/test_replication_credentials/test.py diff --git a/dbms/programs/server/InterserverIOHTTPHandler.cpp b/dbms/programs/server/InterserverIOHTTPHandler.cpp index e7343989590..218ebf832c7 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.cpp +++ b/dbms/programs/server/InterserverIOHTTPHandler.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -24,27 +24,48 @@ namespace ErrorCodes extern const int TOO_MANY_SIMULTANEOUS_QUERIES; } +std::pair InterserverIOHTTPHandler::checkAuthentication(Poco::Net::HTTPServerRequest & request) const +{ + const auto & config = server.config(); + + if (config.has("interserver_http_credentials.user")) + { + if (!request.hasCredentials()) + return {"Server requires HTTP Basic authentification, but client doesn't provide it", false}; + String scheme, info; + request.getCredentials(scheme, info); + + if (scheme != "Basic") + return {"Server requires HTTP Basic authentification but client provides another method", false}; + + String user = config.getString("interserver_http_credentials.user"); + String password = config.getString("interserver_http_credentials.password", ""); + + Poco::Net::HTTPBasicCredentials credentials(info); + if (std::make_pair(user, password) != std::make_pair(credentials.getUsername(), credentials.getPassword())) + return {"Incorrect user or password in HTTP Basic authentification", false}; + } + else if (request.hasCredentials()) + { + return {"Client requires HTTP Basic authentification, but server doesn't provide it", false}; + } + return {"", true}; +} + void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response) { HTMLForm params(request); LOG_TRACE(log, "Request URI: " << request.getURI()); - const auto & config = server.config(); - - if (config.has("interserver_http_credentials.user")) - { - String user = config.getString("interserver_http_credentials.user"); - String password = config.getString("interserver_http_credentials.password", ""); - Poco::Net::HTTPCredentials creds(user, password); - creds.authenticate(request, response); - } String endpoint_name = params.get("endpoint"); bool compress = params.get("compress") == "true"; ReadBufferFromIStream body(request.stream()); + const auto & config = server.config(); + unsigned keep_alive_timeout = config.getUInt("keep_alive_timeout", 10); WriteBufferFromHTTPServerResponse out(request, response, keep_alive_timeout); @@ -73,8 +94,18 @@ void InterserverIOHTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & requ try { - processQuery(request, response); - LOG_INFO(log, "Done processing query"); + if (auto [msg, success] = checkAuthentication(request); success) + { + processQuery(request, response); + LOG_INFO(log, "Done processing query"); + } + else + { + response.setStatusAndReason(Poco::Net::HTTPServerResponse::HTTP_UNAUTHORIZED); + if (!response.sent()) + response.send() << msg << std::endl; + LOG_WARNING(log, "Query processing failed request: '" << request.getURI() << "' authentification failed"); + } } catch (Exception & e) { diff --git a/dbms/programs/server/InterserverIOHTTPHandler.h b/dbms/programs/server/InterserverIOHTTPHandler.h index bf9fef59982..fbaf432d4f9 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.h +++ b/dbms/programs/server/InterserverIOHTTPHandler.h @@ -34,6 +34,8 @@ private: CurrentMetrics::Increment metric_increment{CurrentMetrics::InterserverConnection}; void processQuery(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response); + + std::pair checkAuthentication(Poco::Net::HTTPServerRequest & request) const; }; } diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index 9a3db8bdb12..b513ae1367d 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -230,6 +230,17 @@ int Server::main(const std::vector & /*args*/) global_context->setInterserverIOAddress(this_host, port); } + if (config().has("interserver_http_credentials.user")) + { + String user = config().getString("interserver_http_credentials.user", ""); + String password = config().getString("interserver_http_credentials.password", ""); + + if (user.empty()) + throw Exception("Empty interserver_http_credentials user can't be empty"); + + global_context->setInterverserCredentials(user, password); + } + if (config().has("macros")) global_context->setMacros(std::make_unique(config(), "macros")); diff --git a/dbms/src/IO/ReadWriteBufferFromHTTP.cpp b/dbms/src/IO/ReadWriteBufferFromHTTP.cpp index af0f34babbf..52ec808bd68 100644 --- a/dbms/src/IO/ReadWriteBufferFromHTTP.cpp +++ b/dbms/src/IO/ReadWriteBufferFromHTTP.cpp @@ -18,6 +18,7 @@ ReadWriteBufferFromHTTP::ReadWriteBufferFromHTTP(const Poco::URI & uri, const std::string & method_, OutStreamCallback out_stream_callback, const ConnectionTimeouts & timeouts, + const Poco::Net::HTTPBasicCredentials & credentials, size_t buffer_size_) : ReadBuffer(nullptr, 0), uri{uri}, @@ -30,6 +31,9 @@ ReadWriteBufferFromHTTP::ReadWriteBufferFromHTTP(const Poco::URI & uri, if (out_stream_callback) request.setChunkedTransferEncoding(true); + if (!credentials.getUsername().empty()) + credentials.authenticate(request); + Poco::Net::HTTPResponse response; LOG_TRACE((&Logger::get("ReadWriteBufferFromHTTP")), "Sending request to " << uri.toString()); diff --git a/dbms/src/IO/ReadWriteBufferFromHTTP.h b/dbms/src/IO/ReadWriteBufferFromHTTP.h index 93a8232f93d..d370bb3d4c7 100644 --- a/dbms/src/IO/ReadWriteBufferFromHTTP.h +++ b/dbms/src/IO/ReadWriteBufferFromHTTP.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -32,6 +33,7 @@ public: const std::string & method = {}, OutStreamCallback out_stream_callback = {}, const ConnectionTimeouts & timeouts = {}, + const Poco::Net::HTTPBasicCredentials & credentials = {}, size_t buffer_size_ = DBMS_DEFAULT_BUFFER_SIZE); bool nextImpl() override; diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 9fed370cfbc..0561c2f11c2 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -109,6 +109,8 @@ struct ContextShared String interserver_io_host; /// The host name by which this server is available for other servers. UInt16 interserver_io_port = 0; /// and port. + String interserver_io_user; + String interserver_io_password; String path; /// Path to the data directory, with a slash at the end. String tmp_path; /// The path to the temporary files that occur when processing the request. @@ -1378,6 +1380,17 @@ void Context::setInterserverIOAddress(const String & host, UInt16 port) shared->interserver_io_port = port; } +void Context::setInterverserCredentials(const String & user, const String & password) +{ + shared->interserver_io_user = user; + shared->interserver_io_password = password; +} + +std::pair Context::getInterserverCredentials() const +{ + return { shared->interserver_io_user, shared->interserver_io_password }; +} + std::pair Context::getInterserverIOAddress() const { diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index 1c867d65e8f..38a0e7cb4bc 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -249,6 +249,11 @@ public: /// How other servers can access this for downloading replicated data. void setInterserverIOAddress(const String & host, UInt16 port); std::pair getInterserverIOAddress() const; + + // Credentials which server will use to communicate with others + void setInterverserCredentials(const String & user, const String & password); + std::pair getInterserverCredentials() const; + /// The port that the server listens for executing SQL queries. UInt16 getTCPPort() const; diff --git a/dbms/src/Storages/MergeTree/DataPartsExchange.cpp b/dbms/src/Storages/MergeTree/DataPartsExchange.cpp index 15d1c56b051..39db6142605 100644 --- a/dbms/src/Storages/MergeTree/DataPartsExchange.cpp +++ b/dbms/src/Storages/MergeTree/DataPartsExchange.cpp @@ -161,6 +161,8 @@ MergeTreeData::MutableDataPartPtr Fetcher::fetchPart( const String & host, int port, const ConnectionTimeouts & timeouts, + const String & user, + const String & password, bool to_detached, const String & tmp_prefix_) { @@ -175,7 +177,14 @@ MergeTreeData::MutableDataPartPtr Fetcher::fetchPart( {"compress", "false"} }); - ReadWriteBufferFromHTTP in{uri, Poco::Net::HTTPRequest::HTTP_POST, {}, timeouts}; + Poco::Net::HTTPBasicCredentials creds{}; + if (!user.empty()) + { + creds.setUsername(user); + creds.setPassword(password); + } + + ReadWriteBufferFromHTTP in{uri, Poco::Net::HTTPRequest::HTTP_POST, {}, timeouts, creds}; static const String TMP_PREFIX = "tmp_fetch_"; String tmp_prefix = tmp_prefix_.empty() ? TMP_PREFIX : tmp_prefix_; diff --git a/dbms/src/Storages/MergeTree/DataPartsExchange.h b/dbms/src/Storages/MergeTree/DataPartsExchange.h index 0ebc2ec358a..32eb80e96ca 100644 --- a/dbms/src/Storages/MergeTree/DataPartsExchange.h +++ b/dbms/src/Storages/MergeTree/DataPartsExchange.h @@ -54,6 +54,8 @@ public: const String & host, int port, const ConnectionTimeouts & timeouts, + const String & user, + const String & password, bool to_detached = false, const String & tmp_prefix_ = ""); diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index c8b8b6d9706..09fd8bbba8a 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -1971,9 +1971,10 @@ bool StorageReplicatedMergeTree::executeReplaceRange(const LogEntry & entry) String replica_path = zookeeper_path + "/replicas/" + part_desc->replica; ReplicatedMergeTreeAddress address(getZooKeeper()->get(replica_path + "/host")); auto timeouts = ConnectionTimeouts::getHTTPTimeouts(context.getSettingsRef()); + auto [user, password] = context.getInterserverCredentials(); part_desc->res_part = fetcher.fetchPart(part_desc->found_new_part_name, replica_path, - address.host, address.replication_port, timeouts, false, TMP_PREFIX + "fetch_"); + address.host, address.replication_port, timeouts, user, password, false, TMP_PREFIX + "fetch_"); /// TODO: check columns_version of fetched part @@ -2706,10 +2707,11 @@ bool StorageReplicatedMergeTree::fetchPart(const String & part_name, const Strin ReplicatedMergeTreeAddress address(getZooKeeper()->get(replica_path + "/host")); auto timeouts = ConnectionTimeouts::getHTTPTimeouts(context.getSettingsRef()); + auto [user, password] = context.getInterserverCredentials(); try { - part = fetcher.fetchPart(part_name, replica_path, address.host, address.replication_port, timeouts, to_detached); + part = fetcher.fetchPart(part_name, replica_path, address.host, address.replication_port, timeouts, user, password, to_detached); if (!to_detached) { diff --git a/dbms/tests/integration/test_replication_credentials/__init__.py b/dbms/tests/integration/test_replication_credentials/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dbms/tests/integration/test_replication_credentials/configs/credentials1.xml b/dbms/tests/integration/test_replication_credentials/configs/credentials1.xml new file mode 100644 index 00000000000..1a5fbd393d5 --- /dev/null +++ b/dbms/tests/integration/test_replication_credentials/configs/credentials1.xml @@ -0,0 +1,7 @@ + + 9009 + + admin + 222 + + diff --git a/dbms/tests/integration/test_replication_credentials/configs/credentials2.xml b/dbms/tests/integration/test_replication_credentials/configs/credentials2.xml new file mode 100644 index 00000000000..cf846e7a53d --- /dev/null +++ b/dbms/tests/integration/test_replication_credentials/configs/credentials2.xml @@ -0,0 +1,7 @@ + + 9009 + + root + 111 + + diff --git a/dbms/tests/integration/test_replication_credentials/configs/no_credentials.xml b/dbms/tests/integration/test_replication_credentials/configs/no_credentials.xml new file mode 100644 index 00000000000..9822058811e --- /dev/null +++ b/dbms/tests/integration/test_replication_credentials/configs/no_credentials.xml @@ -0,0 +1,3 @@ + + 9009 + diff --git a/dbms/tests/integration/test_replication_credentials/configs/remote_servers.xml b/dbms/tests/integration/test_replication_credentials/configs/remote_servers.xml new file mode 100644 index 00000000000..d8b384a6392 --- /dev/null +++ b/dbms/tests/integration/test_replication_credentials/configs/remote_servers.xml @@ -0,0 +1,58 @@ + + + + + true + + test + node1 + 9000 + + + test + node2 + 9000 + + + + true + + test + node3 + 9000 + + + test + node4 + 9000 + + + + true + + test + node5 + 9000 + + + test + node7 + 9000 + + + + true + + test + node7 + 9000 + + + test + node8 + 9000 + + + + + diff --git a/dbms/tests/integration/test_replication_credentials/test.py b/dbms/tests/integration/test_replication_credentials/test.py new file mode 100644 index 00000000000..0b2163c05ad --- /dev/null +++ b/dbms/tests/integration/test_replication_credentials/test.py @@ -0,0 +1,132 @@ +import time +import pytest + +from helpers.cluster import ClickHouseCluster + + +def _fill_nodes(nodes, shard): + for node in nodes: + node.query( + ''' + CREATE DATABASE test; + + CREATE TABLE test_table(date Date, id UInt32, dummy UInt32) + ENGINE = ReplicatedMergeTree('/clickhouse/tables/test{shard}/replicated', '{replica}', date, id, 8192); + '''.format(shard=shard, replica=node.name)) + +cluster = ClickHouseCluster(__file__, server_bin_path="/home/alesap/ClickHouse/dbms/programs/clickhouse-server") +node1 = cluster.add_instance('node1', main_configs=['configs/remote_servers.xml', 'configs/credentials1.xml'], with_zookeeper=True) +node2 = cluster.add_instance('node2', main_configs=['configs/remote_servers.xml', 'configs/credentials1.xml'], with_zookeeper=True) + + +@pytest.fixture(scope="module") +def same_credentials_cluster(): + try: + cluster.start() + + _fill_nodes([node1, node2], 1) + + yield cluster + + finally: + cluster.shutdown() + +def test_same_credentials(same_credentials_cluster): + node1.query("insert into test_table values ('2017-06-16', 111, 0)") + time.sleep(1) + + assert node1.query("SELECT id FROM test_table order by id") == '111\n' + assert node2.query("SELECT id FROM test_table order by id") == '111\n' + + node2.query("insert into test_table values ('2017-06-17', 222, 1)") + time.sleep(1) + + assert node1.query("SELECT id FROM test_table order by id") == '111\n222\n' + assert node2.query("SELECT id FROM test_table order by id") == '111\n222\n' + + +node3 = cluster.add_instance('node3', main_configs=['configs/remote_servers.xml', 'configs/no_credentials.xml'], with_zookeeper=True) +node4 = cluster.add_instance('node4', main_configs=['configs/remote_servers.xml', 'configs/no_credentials.xml'], with_zookeeper=True) + +@pytest.fixture(scope="module") +def no_credentials_cluster(): + try: + cluster.start() + + _fill_nodes([node3, node4], 2) + + yield cluster + + finally: + cluster.shutdown() + + +def test_no_credentials(no_credentials_cluster): + node3.query("insert into test_table values ('2017-06-18', 111, 0)") + time.sleep(1) + + assert node3.query("SELECT id FROM test_table order by id") == '111\n' + assert node4.query("SELECT id FROM test_table order by id") == '111\n' + + node4.query("insert into test_table values ('2017-06-19', 222, 1)") + time.sleep(1) + + assert node3.query("SELECT id FROM test_table order by id") == '111\n222\n' + assert node4.query("SELECT id FROM test_table order by id") == '111\n222\n' + +node5 = cluster.add_instance('node5', main_configs=['configs/remote_servers.xml', 'configs/credentials1.xml'], with_zookeeper=True) +node6 = cluster.add_instance('node6', main_configs=['configs/remote_servers.xml', 'configs/credentials2.xml'], with_zookeeper=True) + +@pytest.fixture(scope="module") +def different_credentials_cluster(): + try: + cluster.start() + + _fill_nodes([node5, node6], 3) + + yield cluster + + finally: + cluster.shutdown() + +def test_different_credentials(different_credentials_cluster): + node5.query("insert into test_table values ('2017-06-20', 111, 0)") + time.sleep(1) + + assert node5.query("SELECT id FROM test_table order by id") == '111\n' + assert node6.query("SELECT id FROM test_table order by id") == '' + + node6.query("insert into test_table values ('2017-06-21', 222, 1)") + time.sleep(1) + + assert node5.query("SELECT id FROM test_table order by id") == '111\n' + assert node6.query("SELECT id FROM test_table order by id") == '222\n' + +node7 = cluster.add_instance('node7', main_configs=['configs/remote_servers.xml', 'configs/credentials1.xml'], with_zookeeper=True) +node8 = cluster.add_instance('node8', main_configs=['configs/remote_servers.xml', 'configs/no_credentials.xml'], with_zookeeper=True) + +@pytest.fixture(scope="module") +def credentials_and_no_credentials_cluster(): + try: + cluster.start() + + _fill_nodes([node7, node8], 4) + + yield cluster + + finally: + cluster.shutdown() + +def test_credentials_and_no_credentials(credentials_and_no_credentials_cluster): + node7.query("insert into test_table values ('2017-06-21', 111, 0)") + time.sleep(1) + + assert node7.query("SELECT id FROM test_table order by id") == '111\n' + assert node8.query("SELECT id FROM test_table order by id") == '' + + node8.query("insert into test_table values ('2017-06-22', 222, 1)") + time.sleep(1) + + assert node7.query("SELECT id FROM test_table order by id") == '111\n' + assert node8.query("SELECT id FROM test_table order by id") == '222\n' + From bb5d8db9a185925e81c71f68de99df8416b51f18 Mon Sep 17 00:00:00 2001 From: VadimPE Date: Thu, 26 Jul 2018 18:13:00 +0300 Subject: [PATCH 168/425] CLICKHOUSE-3837 fix tests --- .../0_stateless/00675_remote_with_table_function.sql | 9 --------- ... => 00675_shard_remote_with_table_function.reference} | 0 .../00675_shard_remote_with_table_function.sql | 9 +++++++++ 3 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql rename dbms/tests/queries/0_stateless/{00675_remote_with_table_function.reference => 00675_shard_remote_with_table_function.reference} (100%) create mode 100644 dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql diff --git a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql deleted file mode 100644 index a3e46af05d2..00000000000 --- a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.sql +++ /dev/null @@ -1,9 +0,0 @@ -DROP TABLE IF EXISTS test.remote_test; -CREATE TABLE test.remote_test(a1 UInt8) ENGINE=Memory; -INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(1); -INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(2); -INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(3); -INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(4); -SELECT COUNT(*) FROM remote('127.0.0.1', test.remote_test); -SELECT count(*) FROM remote('127.0.0.1', merge(test, '^remote_test')); -DROP TABLE test.remote_test; diff --git a/dbms/tests/queries/0_stateless/00675_remote_with_table_function.reference b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.reference similarity index 100% rename from dbms/tests/queries/0_stateless/00675_remote_with_table_function.reference rename to dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.reference diff --git a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql new file mode 100644 index 00000000000..6b9856cf030 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS remote_test; +CREATE TABLE remote_test(a1 UInt8) ENGINE=Memory; +INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(1); +INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(2); +INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(3); +INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(4); +SELECT COUNT(*) FROM remote('127.0.0.{1,2}', default.remote_test); +SELECT count(*) FROM remote('127.0.0.{1,2}', merge(default, '^remote_test')); +DROP TABLE test.remote_test; From 9aec460f2efb14c32ace66e2d8d866a9a3a2db06 Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 26 Jul 2018 18:15:48 +0300 Subject: [PATCH 169/425] Fix build warning --- dbms/src/Storages/System/StorageSystemTableEngines.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/System/StorageSystemTableEngines.cpp b/dbms/src/Storages/System/StorageSystemTableEngines.cpp index 99b0a650d68..d40fc6fa49e 100644 --- a/dbms/src/Storages/System/StorageSystemTableEngines.cpp +++ b/dbms/src/Storages/System/StorageSystemTableEngines.cpp @@ -13,9 +13,9 @@ NamesAndTypesList StorageSystemTableEngines::getNamesAndTypes() void StorageSystemTableEngines::fillData(MutableColumns & res_columns, const Context &, const SelectQueryInfo &) const { const auto & storages = StorageFactory::instance().getAllStorages(); - for (const auto & [name, creator] : storages) + for (const auto & pair : storages) { - res_columns[0]->insert(name); + res_columns[0]->insert(pair.first); } } From b7f937785d896569318e678c9453265c3677f83c Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 26 Jul 2018 18:23:16 +0300 Subject: [PATCH 170/425] CLICKHOUSE-3832: Remove empty lines --- dbms/programs/server/InterserverIOHTTPHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/dbms/programs/server/InterserverIOHTTPHandler.cpp b/dbms/programs/server/InterserverIOHTTPHandler.cpp index 218ebf832c7..39d214503ba 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.cpp +++ b/dbms/programs/server/InterserverIOHTTPHandler.cpp @@ -58,14 +58,12 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque LOG_TRACE(log, "Request URI: " << request.getURI()); - String endpoint_name = params.get("endpoint"); bool compress = params.get("compress") == "true"; ReadBufferFromIStream body(request.stream()); const auto & config = server.config(); - unsigned keep_alive_timeout = config.getUInt("keep_alive_timeout", 10); WriteBufferFromHTTPServerResponse out(request, response, keep_alive_timeout); From 5c4b4e96f7f9302498334e01de5c2b81600aac0b Mon Sep 17 00:00:00 2001 From: VadimPE Date: Thu, 26 Jul 2018 18:33:07 +0300 Subject: [PATCH 171/425] CLICKHOUSE-3837 fix test --- .../00675_shard_remote_with_table_function.reference | 2 +- .../00675_shard_remote_with_table_function.sql | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.reference b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.reference index 7290ba859f4..de78180725a 100644 --- a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.reference +++ b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.reference @@ -1,2 +1,2 @@ 4 -4 +8 diff --git a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql index 6b9856cf030..0907384d8e1 100644 --- a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql +++ b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql @@ -1,9 +1,9 @@ DROP TABLE IF EXISTS remote_test; CREATE TABLE remote_test(a1 UInt8) ENGINE=Memory; -INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(1); -INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(2); -INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(3); -INSERT INTO FUNCTION remote('127.0.0.{1,2}', default.remote_test) VALUES(4); -SELECT COUNT(*) FROM remote('127.0.0.{1,2}', default.remote_test); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(1); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(2); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(3); +INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(4); +SELECT COUNT(*) FROM remote('127.0.0.1', default.remote_test); SELECT count(*) FROM remote('127.0.0.{1,2}', merge(default, '^remote_test')); DROP TABLE test.remote_test; From 02946d2bc182be7339444a9a0aee22a14b33643c Mon Sep 17 00:00:00 2001 From: Alexey Zatelepin Date: Thu, 26 Jul 2018 18:52:50 +0300 Subject: [PATCH 172/425] Revert "Set up dns server for kafka integration tests." This reverts commit 1c75c191067bfeb291bd19a2d1f81dde8d1a5b0a. --- .../tests/integration/helpers/docker_compose_kafka.yml | 10 ---------- dbms/tests/integration/test_storage_kafka/test.py | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/dbms/tests/integration/helpers/docker_compose_kafka.yml b/dbms/tests/integration/helpers/docker_compose_kafka.yml index 0afef7bcda6..42dd154b1e8 100644 --- a/dbms/tests/integration/helpers/docker_compose_kafka.yml +++ b/dbms/tests/integration/helpers/docker_compose_kafka.yml @@ -22,13 +22,3 @@ services: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 depends_on: - kafka_zookeeper - - dns-proxy-server: - image: defreitas/dns-proxy-server - hostname: dns.mageddo - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /etc/resolv.conf:/etc/resolv.conf - ports: - - 5380:5380 - network_mode: bridge diff --git a/dbms/tests/integration/test_storage_kafka/test.py b/dbms/tests/integration/test_storage_kafka/test.py index 5c73ef94962..197c52825ef 100644 --- a/dbms/tests/integration/test_storage_kafka/test.py +++ b/dbms/tests/integration/test_storage_kafka/test.py @@ -23,7 +23,7 @@ def started_cluster(): yield cluster finally: - cluster.shutdown(False) + cluster.shutdown() def test_kafka_json(started_cluster): instance.query(''' From 4fb89512b1e06a058fba58148526888f1588bb17 Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 26 Jul 2018 19:01:43 +0300 Subject: [PATCH 173/425] CLICKHOUSE-3832: Add error code to exception and change message, also change check for interserver_http_credentials --- dbms/programs/server/Server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index b513ae1367d..f6ecd783052 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -230,13 +230,13 @@ int Server::main(const std::vector & /*args*/) global_context->setInterserverIOAddress(this_host, port); } - if (config().has("interserver_http_credentials.user")) + if (config().has("interserver_http_credentials")) { String user = config().getString("interserver_http_credentials.user", ""); String password = config().getString("interserver_http_credentials.password", ""); if (user.empty()) - throw Exception("Empty interserver_http_credentials user can't be empty"); + throw Exception("Configuration parameter interserver_http_credentials user can't be empty", ErrorCode::NO_ELEMENTS_IN_CONFIG); global_context->setInterverserCredentials(user, password); } From 368face3c94de8fb7a1d14e84923cfc3a55361fa Mon Sep 17 00:00:00 2001 From: alesapin Date: Thu, 26 Jul 2018 19:10:21 +0300 Subject: [PATCH 174/425] CLICKHOUSE-3832: Fix typo --- dbms/programs/server/Server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/programs/server/Server.cpp b/dbms/programs/server/Server.cpp index f6ecd783052..c4b0c77a026 100644 --- a/dbms/programs/server/Server.cpp +++ b/dbms/programs/server/Server.cpp @@ -236,7 +236,7 @@ int Server::main(const std::vector & /*args*/) String password = config().getString("interserver_http_credentials.password", ""); if (user.empty()) - throw Exception("Configuration parameter interserver_http_credentials user can't be empty", ErrorCode::NO_ELEMENTS_IN_CONFIG); + throw Exception("Configuration parameter interserver_http_credentials user can't be empty", ErrorCodes::NO_ELEMENTS_IN_CONFIG); global_context->setInterverserCredentials(user, password); } From 894c5b356d6574652191d4984449c307ad1b0a22 Mon Sep 17 00:00:00 2001 From: VadimPE Date: Thu, 26 Jul 2018 19:15:15 +0300 Subject: [PATCH 175/425] CLICKHOUSE-3837 --- .../0_stateless/00675_shard_remote_with_table_function.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql index 0907384d8e1..e6570364e3b 100644 --- a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql +++ b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql @@ -6,4 +6,4 @@ INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(3); INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(4); SELECT COUNT(*) FROM remote('127.0.0.1', default.remote_test); SELECT count(*) FROM remote('127.0.0.{1,2}', merge(default, '^remote_test')); -DROP TABLE test.remote_test; +DROP TABLE remote_test; From 54a08ed0186358fc85918a478e077892b2e5710b Mon Sep 17 00:00:00 2001 From: Amos Bird Date: Thu, 26 Jul 2018 12:36:28 +0800 Subject: [PATCH 176/425] Use docker exec to operate on kafka. --- dbms/tests/integration/README.md | 4 ++-- dbms/tests/integration/helpers/cluster.py | 1 + .../integration/test_storage_kafka/test.py | 24 +++++++++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/dbms/tests/integration/README.md b/dbms/tests/integration/README.md index cf1df4a40e8..86808503180 100644 --- a/dbms/tests/integration/README.md +++ b/dbms/tests/integration/README.md @@ -14,9 +14,9 @@ Don't use Docker from your system repository. * [pip](https://pypi.python.org/pypi/pip). To install: `sudo apt-get install python-pip` * [py.test](https://docs.pytest.org/) testing framework. To install: `sudo -H pip install pytest` -* [docker-compose](https://docs.docker.com/compose/) and additional python libraries. To install: `sudo -H pip install docker-compose docker dicttoxml kazoo PyMySQL kafka-python` +* [docker-compose](https://docs.docker.com/compose/) and additional python libraries. To install: `sudo -H pip install docker-compose docker dicttoxml kazoo PyMySQL` -(highly not recommended) If you really want to use OS packages on modern debian/ubuntu instead of "pip": `sudo apt install -y docker docker-compose python-pytest python-dicttoxml python-docker python-pymysql python-kazoo python-kafka` +(highly not recommended) If you really want to use OS packages on modern debian/ubuntu instead of "pip": `sudo apt install -y docker docker-compose python-pytest python-dicttoxml python-docker python-pymysql python-kazoo` If you want to run the tests under a non-privileged user, you must add this user to `docker` group: `sudo usermod -aG docker $USER` and re-login. (You must close all your sessions (for example, restart your computer)) diff --git a/dbms/tests/integration/helpers/cluster.py b/dbms/tests/integration/helpers/cluster.py index 5d5f33e3392..8b5991ad117 100644 --- a/dbms/tests/integration/helpers/cluster.py +++ b/dbms/tests/integration/helpers/cluster.py @@ -144,6 +144,7 @@ class ClickHouseCluster: if self.with_kafka and self.base_kafka_cmd: subprocess.check_call(self.base_kafka_cmd + ['up', '-d', '--no-recreate']) + self.kafka_docker_id = self.get_instance_docker_id('kafka1') # Uncomment for debugging #print ' '.join(self.base_cmd + ['up', '--no-recreate']) diff --git a/dbms/tests/integration/test_storage_kafka/test.py b/dbms/tests/integration/test_storage_kafka/test.py index 197c52825ef..85d6f090d58 100644 --- a/dbms/tests/integration/test_storage_kafka/test.py +++ b/dbms/tests/integration/test_storage_kafka/test.py @@ -6,8 +6,8 @@ import pytest from helpers.cluster import ClickHouseCluster from helpers.test_tools import TSV -from kafka import KafkaProducer import json +import subprocess @@ -25,6 +25,16 @@ def started_cluster(): finally: cluster.shutdown() +def kafka_is_available(started_cluster): + p = subprocess.Popen(('docker', 'exec', '-i', started_cluster.kafka_docker_id, '/usr/bin/kafka-broker-api-versions', '--bootstrap-server', 'PLAINTEXT://localhost:9092'), stdout=subprocess.PIPE) + streamdata = p.communicate()[0] + return p.returncode == 0 + +def kafka_produce(started_cluster, topic, messages): + p = subprocess.Popen(('docker', 'exec', '-i', started_cluster.kafka_docker_id, '/usr/bin/kafka-console-producer', '--broker-list', 'localhost:9092', '--topic', topic), stdin=subprocess.PIPE) + p.communicate(messages) + p.stdin.close() + def test_kafka_json(started_cluster): instance.query(''' DROP TABLE IF EXISTS test.kafka; @@ -34,18 +44,18 @@ CREATE TABLE test.kafka (key UInt64, value UInt64) retries = 0 while True: - try: - producer = KafkaProducer() + if kafka_is_available(started_cluster): break - except: + else: retries += 1 if retries > 50: - raise + raise 'Cannot connect to kafka.' print("Waiting for kafka to be available...") time.sleep(1) + messages = '' for i in xrange(50): - producer.send('json', json.dumps({'key': i, 'value': i})) - producer.flush() + messages += json.dumps({'key': i, 'value': i}) + '\n' + kafka_produce(started_cluster, 'json', messages) time.sleep(3) result = instance.query('SELECT * FROM test.kafka;') with open(p.join(p.dirname(__file__), 'test_kafka_json.reference')) as reference: From da41c5cf47a634afbd55135ea7223cc59488d7f7 Mon Sep 17 00:00:00 2001 From: Vadim Date: Thu, 26 Jul 2018 20:49:51 +0300 Subject: [PATCH 177/425] Update 00675_shard_remote_with_table_function.sql --- .../00675_shard_remote_with_table_function.sql | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql index e6570364e3b..85cbb3b6d77 100644 --- a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql +++ b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql @@ -1,9 +1,9 @@ -DROP TABLE IF EXISTS remote_test; -CREATE TABLE remote_test(a1 UInt8) ENGINE=Memory; -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(1); -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(2); -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(3); -INSERT INTO FUNCTION remote('127.0.0.1', default.remote_test) VALUES(4); -SELECT COUNT(*) FROM remote('127.0.0.1', default.remote_test); +DROP TABLE IF EXISTS test.remote_test; +CREATE TABLE test.remote_test(a1 UInt8) ENGINE=Memory; +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(1); +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(2); +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(3); +INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(4); +SELECT COUNT(*) FROM remote('127.0.0.1', test.remote_test); SELECT count(*) FROM remote('127.0.0.{1,2}', merge(default, '^remote_test')); -DROP TABLE remote_test; +DROP TABLE test.remote_test; From ad006166b580069f3f54174b6ce8fe5977050ff6 Mon Sep 17 00:00:00 2001 From: Vadim Date: Thu, 26 Jul 2018 20:50:32 +0300 Subject: [PATCH 178/425] Update 00675_shard_remote_with_table_function.sql --- .../0_stateless/00675_shard_remote_with_table_function.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql index 85cbb3b6d77..f10ceeaa646 100644 --- a/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql +++ b/dbms/tests/queries/0_stateless/00675_shard_remote_with_table_function.sql @@ -5,5 +5,5 @@ INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(2); INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(3); INSERT INTO FUNCTION remote('127.0.0.1', test.remote_test) VALUES(4); SELECT COUNT(*) FROM remote('127.0.0.1', test.remote_test); -SELECT count(*) FROM remote('127.0.0.{1,2}', merge(default, '^remote_test')); +SELECT count(*) FROM remote('127.0.0.{1,2}', merge(test, '^remote_test')); DROP TABLE test.remote_test; From 6555b05c77d98be699a5cfeeea75fcd8139b8999 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Thu, 26 Jul 2018 21:02:40 +0300 Subject: [PATCH 179/425] Fixed links after restructurization of the documentation. --- docs/ru/interfaces/formats.md | 52 +++++++++---------- docs/ru/operations/settings/settings.md | 2 +- docs/ru/operations/table_engines/mysql.md | 2 +- docs/ru/query_language/dicts/index.md | 2 +- .../functions/functions_for_nulls.md | 6 +-- .../functions/other_functions.md | 6 +-- .../functions/type_conversion_functions.md | 2 +- docs/ru/query_language/select.md | 4 +- docs/ru/query_language/syntax.md | 4 +- docs/toc_ru.yml | 1 + 10 files changed, 41 insertions(+), 40 deletions(-) diff --git a/docs/ru/interfaces/formats.md b/docs/ru/interfaces/formats.md index 1e4aa7b5354..fcc451d2d8b 100644 --- a/docs/ru/interfaces/formats.md +++ b/docs/ru/interfaces/formats.md @@ -8,29 +8,29 @@ ClickHouse может принимать (`INSERT`) и отдавать (`SELECT Формат | INSERT | SELECT -------|--------|-------- -[TabSeparated](formats.md#tabseparated) | ✔ | ✔ | -[TabSeparatedRaw](formats.md#tabseparatedraw) | ✗ | ✔ | -[TabSeparatedWithNames](formats.md#tabseparatedwithnames) | ✔ | ✔ | -[TabSeparatedWithNamesAndTypes](formats.md#tabseparatedwithnamesandtypes) | ✔ | ✔ | -[CSV](formats.md#csv) | ✔ | ✔ | -[CSVWithNames](formats.md#csvwithnames) | ✔ | ✔ | -[Values](formats.md#values) | ✔ | ✔ | -[Vertical](formats.md#vertical) | ✗ | ✔ | -[VerticalRaw](formats.md#verticalraw) | ✗ | ✔ | -[JSON](formats.md#json) | ✗ | ✔ | -[JSONCompact](formats.md#jsoncompact) | ✗ | ✔ | -[JSONEachRow](formats.md#jsoneachrow) | ✔ | ✔ | -[TSKV](formats.md#tskv) | ✔ | ✔ | -[Pretty](formats.md#pretty) | ✗ | ✔ | -[PrettyCompact](formats.md#prettycompact) | ✗ | ✔ | -[PrettyCompactMonoBlock](formats.md#prettycompactmonoblock) | ✗ | ✔ | -[PrettyNoEscapes](formats.md#prettynoescapes) | ✗ | ✔ | -[PrettySpace](formats.md#prettyspace) | ✗ | ✔ | -[RowBinary](formats.md#rowbinary) | ✔ | ✔ | -[Native](formats.md#native) | ✔ | ✔ | -[Null](formats.md#null) | ✗ | ✔ | -[XML](formats.md#xml) | ✗ | ✔ | -[CapnProto](formats.md#capnproto) | ✔ | ✔ | +[TabSeparated](#tabseparated) | ✔ | ✔ | +[TabSeparatedRaw](#tabseparatedraw) | ✗ | ✔ | +[TabSeparatedWithNames](#tabseparatedwithnames) | ✔ | ✔ | +[TabSeparatedWithNamesAndTypes](#tabseparatedwithnamesandtypes) | ✔ | ✔ | +[CSV](#csv) | ✔ | ✔ | +[CSVWithNames](#csvwithnames) | ✔ | ✔ | +[Values](#values) | ✔ | ✔ | +[Vertical](#vertical) | ✗ | ✔ | +[VerticalRaw](#verticalraw) | ✗ | ✔ | +[JSON](#json) | ✗ | ✔ | +[JSONCompact](#jsoncompact) | ✗ | ✔ | +[JSONEachRow](#jsoneachrow) | ✔ | ✔ | +[TSKV](#tskv) | ✔ | ✔ | +[Pretty](#pretty) | ✗ | ✔ | +[PrettyCompact](#prettycompact) | ✗ | ✔ | +[PrettyCompactMonoBlock](#prettycompactmonoblock) | ✗ | ✔ | +[PrettyNoEscapes](#prettynoescapes) | ✗ | ✔ | +[PrettySpace](#prettyspace) | ✗ | ✔ | +[RowBinary](#rowbinary) | ✔ | ✔ | +[Native](#native) | ✔ | ✔ | +[Null](#null) | ✗ | ✔ | +[XML](#xml) | ✗ | ✔ | +[CapnProto](#capnproto) | ✔ | ✔ | @@ -309,7 +309,7 @@ Extremes: ## PrettyCompactMonoBlock -Отличается от [PrettyCompact](formats.md#prettycompact) тем, что строки (до 10 000 штук) буферизуются и затем выводятся в виде одной таблицы, а не по блокам. +Отличается от [PrettyCompact](#prettycompact) тем, что строки (до 10 000 штук) буферизуются и затем выводятся в виде одной таблицы, а не по блокам. ## PrettyNoEscapes @@ -335,7 +335,7 @@ watch -n1 "clickhouse-client --query='SELECT * FROM system.events FORMAT PrettyC ## PrettySpace -Отличается от [PrettyCompact](formats.md#prettycompact) тем, что вместо сетки используется пустое пространство (пробелы). +Отличается от [PrettyCompact](#prettycompact) тем, что вместо сетки используется пустое пространство (пробелы). ## RowBinary @@ -482,7 +482,7 @@ x=1 y=\N ## Values -Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату [TabSeparated](tabseparated). При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). [NULL](../query_language/syntax.md#null-literal) представляется как `NULL`. +Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату [TabSeparated](#tabseparated). При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). [NULL](../query_language/syntax.md#null-literal) представляется как `NULL`. Минимальный набор символов, которых вам необходимо экранировать при передаче в Values формате: одинарная кавычка и обратный слеш. diff --git a/docs/ru/operations/settings/settings.md b/docs/ru/operations/settings/settings.md index 15a00792b08..8d8d20a4928 100644 --- a/docs/ru/operations/settings/settings.md +++ b/docs/ru/operations/settings/settings.md @@ -352,6 +352,6 @@ ClickHouse применяет настройку в тех случаях, ко ## join_use_nulls {: #settings-join_use_nulls} -Влияет на поведение [JOIN](../../query_language/queries.md#query_language-join). +Влияет на поведение [JOIN](../../query_language/select.md#query_language-join). При `join_use_nulls=1` `JOIN` ведёт себя как в стандартном SQL, т.е. если при слиянии возникают пустые ячейки, то тип соответствующего поля преобразуется к [Nullable](../../data_types/nullable.md#data_type-nullable), а пустые ячейки заполняются значениями [NULL](../../query_language/syntax.md#null-literal). diff --git a/docs/ru/operations/table_engines/mysql.md b/docs/ru/operations/table_engines/mysql.md index 484ac87726a..b62320633ea 100644 --- a/docs/ru/operations/table_engines/mysql.md +++ b/docs/ru/operations/table_engines/mysql.md @@ -14,4 +14,4 @@ MySQL('host:port', 'database', 'table', 'user', 'password'); Остальные условия и ограничение выборки `LIMIT` будут выполнены в ClickHouse только после выполнения запроса к MySQL. -Движок `MySQL` не поддерживает тип данных [Nullable](../data_types/nullable.md#data_type-nullable), поэтому при чтении данных из таблиц MySQL `NULL` преобразуются в значения по умолчанию для заданного типа столбца, обычно это `0` или пустая строка. +Движок `MySQL` не поддерживает тип данных [Nullable](../../data_types/nullable.md#data_type-nullable), поэтому при чтении данных из таблиц MySQL `NULL` преобразуются в значения по умолчанию для заданного типа столбца, обычно это `0` или пустая строка. diff --git a/docs/ru/query_language/dicts/index.md b/docs/ru/query_language/dicts/index.md index 46a6164ec54..30d5d705b1e 100644 --- a/docs/ru/query_language/dicts/index.md +++ b/docs/ru/query_language/dicts/index.md @@ -4,7 +4,7 @@ ClickHouse поддерживает специальные функции для работы со словарями, которые можно использовать в запросах. Проще и эффективнее использовать словари с помощью функций, чем `JOIN` с таблицами-справочниками. -В словаре нельзя хранить значения [NULL](../query_language/syntax.md#null-literal). +В словаре нельзя хранить значения [NULL](../syntax.md#null-literal). ClickHouse поддерживает: diff --git a/docs/ru/query_language/functions/functions_for_nulls.md b/docs/ru/query_language/functions/functions_for_nulls.md index 88f11fca7d2..aec79e67c22 100644 --- a/docs/ru/query_language/functions/functions_for_nulls.md +++ b/docs/ru/query_language/functions/functions_for_nulls.md @@ -2,7 +2,7 @@ ## isNull -Проверяет является ли аргумент [NULL](../query_language/syntax.md#null-literal). +Проверяет является ли аргумент [NULL](../syntax.md#null-literal). ``` isNull(x) @@ -46,7 +46,7 @@ WHERE isNull(y) ## isNotNull -Проверяет не является ли аргумент [NULL](../query_language/syntax.md#null-literal). +Проверяет не является ли аргумент [NULL](../syntax.md#null-literal). ``` isNotNull(x) @@ -204,7 +204,7 @@ SELECT nullIf(1, 2) ## assumeNotNull -Приводит значение типа [Nullable](../data_types/nullable.md#data_type-nullable) к не `Nullable`, если значение не `NULL`. +Приводит значение типа [Nullable](../../data_types/nullable.md#data_type-nullable) к не `Nullable`, если значение не `NULL`. ``` assumeNotNull(x) diff --git a/docs/ru/query_language/functions/other_functions.md b/docs/ru/query_language/functions/other_functions.md index 645ab814056..f1c4fb19152 100644 --- a/docs/ru/query_language/functions/other_functions.md +++ b/docs/ru/query_language/functions/other_functions.md @@ -276,7 +276,7 @@ FROM ## getSizeOfEnumType -Возвращает количество полей в [Enum](../data_types/enum.md#data_type-enum). +Возвращает количество полей в [Enum](../../data_types/enum.md#data_type-enum). ``` getSizeOfEnumType(value) @@ -386,7 +386,7 @@ defaultValueOfArgumentType(expression) - `0` для чисел; - Пустая строка для строк; -- `ᴺᵁᴸᴸ` для [Nullable](../data_types/nullable.md#data_type-nullable). +- `ᴺᵁᴸᴸ` для [Nullable](../../data_types/nullable.md#data_type-nullable). **Пример** @@ -426,7 +426,7 @@ SELECT defaultValueOfArgumentType(CAST(1, 'Nullable(Int8)')) **Пример** -Рассмотрим таблицу с тестовыми данными [ontime](../getting_started/example_datasets/ontime.md#example_datasets-ontime). +Рассмотрим таблицу с тестовыми данными [ontime](../../getting_started/example_datasets/ontime.md#example_datasets-ontime). ``` SELECT count() FROM ontime diff --git a/docs/ru/query_language/functions/type_conversion_functions.md b/docs/ru/query_language/functions/type_conversion_functions.md index 3226149b715..21c8556f255 100644 --- a/docs/ru/query_language/functions/type_conversion_functions.md +++ b/docs/ru/query_language/functions/type_conversion_functions.md @@ -114,7 +114,7 @@ SELECT Преобразование в FixedString(N) работает только для аргументов типа String или FixedString(N). -Поддержано преобразование к типу [Nullable](../data_types/nullable.md#data_type-nullable) и обратно. Пример: +Поддержано преобразование к типу [Nullable](../../data_types/nullable.md#data_type-nullable) и обратно. Пример: ``` SELECT toTypeName(x) FROM t_null diff --git a/docs/ru/query_language/select.md b/docs/ru/query_language/select.md index d0a84ee600b..c0540a36188 100644 --- a/docs/ru/query_language/select.md +++ b/docs/ru/query_language/select.md @@ -448,9 +448,9 @@ LIMIT 10 Результат выражения должен иметь тип `UInt8`. -ClickHouse использует в выражении индексы, если это позволяет [движок таблицы](../table_engines/index.md#table_engines). +ClickHouse использует в выражении индексы, если это позволяет [движок таблицы](../operations/table_engines/index.md#table_engines). -Если в секции необходимо проверить [NULL](syntax.md#null-literal), то используйте операторы [IS NULL](../operators/index.md#operator-is-null) и [IS NOT NULL](../operators/index.md#operator-is-not-null), а также соответствующие функции `isNull` и `isNotNull`. В противном случае выражение будет считаться всегда не выполненным. +Если в секции необходимо проверить [NULL](syntax.md#null-literal), то используйте операторы [IS NULL](operators.md#operator-is-null) и [IS NOT NULL](operators.md#operator-is-not-null), а также соответствующие функции `isNull` и `isNotNull`. В противном случае выражение будет считаться всегда не выполненным. Пример проверки на `NULL`: diff --git a/docs/ru/query_language/syntax.md b/docs/ru/query_language/syntax.md index 653e24e88a3..2ae484ee957 100644 --- a/docs/ru/query_language/syntax.md +++ b/docs/ru/query_language/syntax.md @@ -75,11 +75,11 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') Чтобы в поле таблицы можно было хранить `NULL`, оно должно быть типа [Nullable](../data_types/nullable.md#data_type-nullable). -В зависимости от формата данных (входных или выходных) `NULL` может иметь различное представление. Подробнее смотрите в документации для [форматов данных](../formats/index.md#formats). +В зависимости от формата данных (входных или выходных) `NULL` может иметь различное представление. Подробнее смотрите в документации для [форматов данных](../interfaces/formats.md#formats). При обработке `NULL` есть множество особенностей. Например, если хотя бы один из аргументов операции сравнения — `NULL`, то результатом такой операции тоже будет `NULL`. Этим же свойством обладают операции умножения, сложения и пр. Подробнее читайте в документации на каждую операцию. -В запросах можно проверить `NULL` с помощью операторов [IS NULL](../operators/index.md#operator-is-null) и [IS NOT NULL](../operators/index.md#operator-is-not-null), а также соответствующих функций `isNull` и `isNotNull`. +В запросах можно проверить `NULL` с помощью операторов [IS NULL](operators.md#operator-is-null) и [IS NOT NULL](operators.md#operator-is-not-null), а также соответствующих функций `isNull` и `isNotNull`. ## Функции diff --git a/docs/toc_ru.yml b/docs/toc_ru.yml index fb7ef69a233..48d5ed481fc 100644 --- a/docs/toc_ru.yml +++ b/docs/toc_ru.yml @@ -49,6 +49,7 @@ pages: - 'hidden': 'data_types/special_data_types/index.md' - 'Expression': 'data_types/special_data_types/expression.md' - 'Set': 'data_types/special_data_types/set.md' + - 'Nothing': 'data_types/special_data_types/nothing.md' - 'Справка по SQL': - 'hidden': 'query_language/index.md' From eb6aec234873404db8d2d924074d073886350c9c Mon Sep 17 00:00:00 2001 From: Amy Krishnevsky Date: Thu, 26 Jul 2018 17:15:25 -0500 Subject: [PATCH 180/425] translated latest release notes --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23062ae1e73..54e093e4f5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +## ClickHouse release 18.1.0, 2018-07-23 + +### New features: + +* Support for the `ALTER TABLE t DELETE WHERE` query for non-replicated MergeTree tables ([#2634](https://github.com/yandex/ClickHouse/pull/2634)). +* Support for arbitrary types for the `uniq*` family of aggregate functions ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). +* Support for arbitrary types in comparison operators ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). +* The `users.xml` file allows setting a subnet mask in the format `10.0.0.1/255.255.255.0`. This is necessary for using "leaky" masks for IPv6 networks ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). +* Added the `arrayDistinct` function ([#2670](https://github.com/yandex/ClickHouse/pull/2670)). +* The SummingMergeTree engine can now work with AggregateFunction type columns ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2566)). + +### Improvements: + +* Changed the numbering scheme for release versions. Now the first part contains the year of release (A.D., Moscow timezone, minus 2000), the second part contains the number for major changes (increases for most releases), and the third part is the patch version. Releases are still backwards compatible, unless otherwise stated in the changelog. +* Faster conversions of floating-point numbers to a string ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2664)). +* If some rows were skipped during an insert due to parsing errors (this is possible with the `input_allow_errors_num` and `input_allow_errors_ratio` settings enabled), the number of skipped rows is now written to the server log ([Leonardo Cecchi](https://github.com/yandex/ClickHouse/pull/2669)). + +### Bug fixes: + +* Fixed the TRUNCATE command for temporary tables ([Amos Bird](https://github.com/yandex/ClickHouse/pull/2624)). +* Fixed a rare deadlock in the ZooKeeper client library that occurred when there was a network error while reading the response ([c315200](https://github.com/yandex/ClickHouse/commit/c315200e64b87e44bdf740707fc857d1fdf7e947)). +* Fixed an error during a CAST to Nullable types ([#1322](https://github.com/yandex/ClickHouse/issues/1322)). +* Fixed the incorrect result of the `maxIntersection()` function when the boundaries of intervals coincided ([Michael Furmur](https://github.com/yandex/ClickHouse/pull/2657)). +* Fixed incorrect transformation of the OR expression chain in a function argument ([chenxing-xc](https://github.com/yandex/ClickHouse/pull/2663)). +* Fixed performance degradation for queries containing `IN (subquery)` expressions inside another subquery ([#2571](https://github.com/yandex/ClickHouse/issues/2571)). +* Fixed incompatibility between servers with different versions in distributed queries that use a `CAST` function that isn't in uppercase letters ([fe8c4d6](https://github.com/yandex/ClickHouse/commit/fe8c4d64e434cacd4ceef34faa9005129f2190a5)). +* Added missing quoting of identifiers for queries to an external DBMS ([#2635](https://github.com/yandex/ClickHouse/issues/2635)). + +### Backward incompatible changes: + +* Converting a string containing the number zero to DateTime does not work. Example: `SELECT toDateTime('0')`. This is also the reason that `DateTime DEFAULT '0'` does not work in tables, as well as `0` in dictionaries. Solution: replace `0` with `0000-00-00 00:00:00`. + + ## ClickHouse release 1.1.54394, 2018-07-12 ### New features: From 9fad4b4e1adc03ec5e371a2be97f2986386de602 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 27 Jul 2018 01:45:33 +0300 Subject: [PATCH 181/425] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e093e4f5b..ed71baf8046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * Support for the `ALTER TABLE t DELETE WHERE` query for non-replicated MergeTree tables ([#2634](https://github.com/yandex/ClickHouse/pull/2634)). * Support for arbitrary types for the `uniq*` family of aggregate functions ([#2010](https://github.com/yandex/ClickHouse/issues/2010)). * Support for arbitrary types in comparison operators ([#2026](https://github.com/yandex/ClickHouse/issues/2026)). -* The `users.xml` file allows setting a subnet mask in the format `10.0.0.1/255.255.255.0`. This is necessary for using "leaky" masks for IPv6 networks ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). +* The `users.xml` file allows setting a subnet mask in the format `10.0.0.1/255.255.255.0`. This is necessary for using masks for IPv6 networks with zeros in the middle ([#2637](https://github.com/yandex/ClickHouse/pull/2637)). * Added the `arrayDistinct` function ([#2670](https://github.com/yandex/ClickHouse/pull/2670)). * The SummingMergeTree engine can now work with AggregateFunction type columns ([Constantin S. Pan](https://github.com/yandex/ClickHouse/pull/2566)). From 4bc916029c580183cd2fcfa61d68939459f160e9 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Fri, 27 Jul 2018 15:19:29 +0800 Subject: [PATCH 182/425] ISSUES-2700 fix windowFunnel NULL pointer Co-authored-by: zhang2014 Co-authored-by: sundy-li <543950155@qq.com> --- dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.h b/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.h index 4ad0400d160..b62755ef00c 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.h @@ -116,7 +116,7 @@ struct AggregateFunctionWindowFunnelData /// TODO Protection against huge size events_list.clear(); - events_list.resize(size); + events_list.reserve(size); UInt32 timestamp; UInt8 event; From c0f5e33fe8a6cf8d065c15c63451fa122fea1d04 Mon Sep 17 00:00:00 2001 From: alesapin Date: Fri, 27 Jul 2018 13:21:04 +0300 Subject: [PATCH 183/425] Add docs for URL table engine and url table function --- docs/en/operations/table_engines/url.md | 77 +++++++++++++++++++ docs/en/query_language/table_functions/url.md | 19 +++++ docs/ru/operations/table_engines/url.md | 74 ++++++++++++++++++ docs/ru/query_language/table_functions/url.md | 20 +++++ docs/toc_en.yml | 2 + docs/toc_ru.yml | 2 + 6 files changed, 194 insertions(+) create mode 100644 docs/en/operations/table_engines/url.md create mode 100644 docs/en/query_language/table_functions/url.md create mode 100644 docs/ru/operations/table_engines/url.md create mode 100644 docs/ru/query_language/table_functions/url.md diff --git a/docs/en/operations/table_engines/url.md b/docs/en/operations/table_engines/url.md new file mode 100644 index 00000000000..d8dec7dcabd --- /dev/null +++ b/docs/en/operations/table_engines/url.md @@ -0,0 +1,77 @@ + + +# URL(URL, Format) + +This data source operates with data on remote HTTP/HTTPS server. The engine is +similar to [`File`](./file.md#). + +## Usage in ClickHouse server + +``` +URL(URL, Format) +``` + +`Format` should be supported for `SELECT` and/or `INSERT`. For the full list of +supported formats see [Formats](../../interfaces/formats.md#formats). + +`URL` must match the format of Uniform Resource Locator. The specified +URL must address a server working with HTTP or HTTPS. The server shouldn't +require any additional HTTP-headers. + +`INSERT` and `SELECT` queries are transformed into `POST` and `GET` requests +respectively. For correct `POST`-requests handling the remote server should support +[Chunked transfer encoding](https://ru.wikipedia.org/wiki/Chunked_transfer_encoding). + +**Example:** + +**1.** Create the `url_engine_table` table: + +```sql +CREATE TABLE url_engine_table (word String, value UInt64) +ENGINE=URL('http://127.0.0.1:12345/', CSV) +``` + +**2.** Implement simple http-server using python3: + +```python3 +from http.server import BaseHTTPRequestHandler, HTTPServer + +class CSVHTTPServer(BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.send_header('Content-type', 'text/csv') + self.end_headers() + + self.wfile.write(bytes('Hello,1\nWorld,2\n', "utf-8")) + +if __name__ == "__main__": + server_address = ('127.0.0.1', 12345) + HTTPServer(server_address, CSVHTTPServer).serve_forever() +``` + +```bash +python3 server.py +``` + +**3.** Query the data: + +```sql +SELECT * FROM url_engine_table +``` + +```text +┌─word──┬─value─┐ +│ Hello │ 1 │ +│ World │ 2 │ +└───────┴───────┘ +``` + + +## Details of implementation + +- Reads and writes can be parallel +- Not supported: + - `ALTER` + - `SELECT ... SAMPLE` + - Indices + - Replication diff --git a/docs/en/query_language/table_functions/url.md b/docs/en/query_language/table_functions/url.md new file mode 100644 index 00000000000..7e30936bd45 --- /dev/null +++ b/docs/en/query_language/table_functions/url.md @@ -0,0 +1,19 @@ + + +# url + +`url(URL, format, structure)` - returns a table created from the `URL` with given +`format` and `structure`. + +URL - HTTP or HTTPS server address, which can accept `GET` and/or `POST` requests. + +format - [format](../../interfaces/formats.md#formats) of the data. + +structure - table structure in `'UserID UInt64, Name String'` format. Determines column names and types. + +**Example** + +```sql +-- getting the first 3 lines of a table that contains columns of String and UInt32 type from HTTP-server which answers in CSV format. +SELECT * FROM url('http://127.0.0.1:12345/', CSV, 'column1 String, column2 UInt32') LIMIT 3 +``` diff --git a/docs/ru/operations/table_engines/url.md b/docs/ru/operations/table_engines/url.md new file mode 100644 index 00000000000..7c105c9b7b6 --- /dev/null +++ b/docs/ru/operations/table_engines/url.md @@ -0,0 +1,74 @@ + + +# URL(URL, Format) + +Управляет данными на удаленном HTTP/HTTPS сервере. Данный движок похож +на движок [`File`](./file.md#). + +## Использование движка в сервере ClickHouse + +`Format` должен быть таким, который ClickHouse, может использовать в запросах +`SELECT` и, если есть необходимость, `INSERT`. Полный список поддерживаемых форматов смотрите в +разделе [Форматы](../../interfaces/formats.md#formats). + +`URL` должен соответствовать структуре Uniform Resource Locator. По указанному URL должен находится сервер +работающий по протоколу HTTP или HTTPS. При этом не должно требоваться никаких +дополнительных заголовков для получения ответа от сервера. + +Запросы `INSERT` и `SELECT` транслируются в `POST` и `GET` запросы +соответственно. Для обработки `POST`-запросов удаленный сервер должен поддерживать +[Chunked transfer encoding](https://ru.wikipedia.org/wiki/Chunked_transfer_encoding). + +**Пример:** + +**1.** Создадим на сервере таблицу `url_engine_table`: + +```sql +CREATE TABLE url_engine_table (word String, value UInt64) +ENGINE=URL('http://127.0.0.1:12345/', CSV) +``` + +**2.** Создадим простейший http-сервер стандартными средствами языка python3 и +запустим его: + +```python3 +from http.server import BaseHTTPRequestHandler, HTTPServer + +class CSVHTTPServer(BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.send_header('Content-type', 'text/csv') + self.end_headers() + + self.wfile.write(bytes('Hello,1\nWorld,2\n', "utf-8")) + +if __name__ == "__main__": + server_address = ('127.0.0.1', 12345) + HTTPServer(server_address, CSVHTTPServer).serve_forever() +``` + +```bash +python3 server.py +``` + +**3.** Запросим данные: + +```sql +SELECT * FROM url_engine_table +``` + +```text +┌─word──┬─value─┐ +│ Hello │ 1 │ +│ World │ 2 │ +└───────┴───────┘ +``` + +## Особенности использования + +- Поддерживается многопоточное чтение и запись. +- Не поддерживается: + - использование операций `ALTER` и `SELECT...SAMPLE`; + - индексы; + - репликация. + diff --git a/docs/ru/query_language/table_functions/url.md b/docs/ru/query_language/table_functions/url.md new file mode 100644 index 00000000000..7c5068b3caa --- /dev/null +++ b/docs/ru/query_language/table_functions/url.md @@ -0,0 +1,20 @@ + + +# url + +`url(URL, format, structure)` - возвращает таблицу со столбцами, указанными в +`structure`, созданную из данных находящихся по `URL` в формате `format`. + +URL - адрес, по которому сервер принимает `GET` и/или `POST` запросы по +протоколу HTTP или HTTPS. + +format - [формат](../../interfaces/formats.md#formats) данных. + +structure - структура таблицы в форме `'UserID UInt64, Name String'`. Определяет имена и типы столбцов. + +**Пример** + +```sql +-- получение 3-х строк таблицы, состоящей из двух колонк типа String и UInt32 от сервера, отдающего данные в формате CSV +SELECT * FROM url('http://127.0.0.1:12345/', CSV, 'column1 String, column2 UInt32') LIMIT 3 +``` diff --git a/docs/toc_en.yml b/docs/toc_en.yml index a55b7426272..7f830eac379 100644 --- a/docs/toc_en.yml +++ b/docs/toc_en.yml @@ -94,6 +94,7 @@ pages: - 'merge': 'query_language/table_functions/merge.md' - 'numbers': 'query_language/table_functions/numbers.md' - 'remote': 'query_language/table_functions/remote.md' + - 'url': 'query_language/table_functions/url.md' - 'Dictionaries': - 'Introduction': 'query_language/dicts/index.md' - 'External dictionaries': @@ -134,6 +135,7 @@ pages: - 'Null': 'operations/table_engines/null.md' - 'Set': 'operations/table_engines/set.md' - 'Join': 'operations/table_engines/join.md' + - 'URL': 'operations/table_engines/url.md' - 'View': 'operations/table_engines/view.md' - 'MaterializedView': 'operations/table_engines/materializedview.md' - 'Integrations': diff --git a/docs/toc_ru.yml b/docs/toc_ru.yml index 2b088529cbb..9e086eed378 100644 --- a/docs/toc_ru.yml +++ b/docs/toc_ru.yml @@ -97,6 +97,7 @@ pages: - 'merge': 'query_language/table_functions/merge.md' - 'numbers': 'query_language/table_functions/numbers.md' - 'remote': 'query_language/table_functions/remote.md' + - 'url': 'query_language/table_functions/url.md' - 'Словари': - 'Введение': 'query_language/dicts/index.md' - 'Внешние словари': @@ -138,6 +139,7 @@ pages: - 'Null': 'operations/table_engines/null.md' - 'Set': 'operations/table_engines/set.md' - 'Join': 'operations/table_engines/join.md' + - 'URL': 'operations/table_engines/url.md' - 'View': 'operations/table_engines/view.md' - 'MaterializedView': 'operations/table_engines/materializedview.md' - 'Интеграции': From d0507bb6394dad806079054d53360830cf3023b4 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 27 Jul 2018 14:18:54 +0300 Subject: [PATCH 184/425] Update url.md --- docs/ru/operations/table_engines/url.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/operations/table_engines/url.md b/docs/ru/operations/table_engines/url.md index 7c105c9b7b6..b3daae06169 100644 --- a/docs/ru/operations/table_engines/url.md +++ b/docs/ru/operations/table_engines/url.md @@ -7,7 +7,7 @@ ## Использование движка в сервере ClickHouse -`Format` должен быть таким, который ClickHouse, может использовать в запросах +`Format` должен быть таким, который ClickHouse может использовать в запросах `SELECT` и, если есть необходимость, `INSERT`. Полный список поддерживаемых форматов смотрите в разделе [Форматы](../../interfaces/formats.md#formats). From 20c68e5a6f5efce0f4639e61164f5a7d8676de9d Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 27 Jul 2018 14:26:20 +0300 Subject: [PATCH 185/425] WIP on docs introduction articles (#2716) * WIP on content of distinctive_features.md * WIP on content of features_considered_disadvantages.md --- docs/en/introduction/distinctive_features.md | 43 +++++++++++-------- .../features_considered_disadvantages.md | 6 +-- docs/ru/introduction/distinctive_features.md | 33 +++++++------- .../features_considered_disadvantages.md | 8 ++-- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/docs/en/introduction/distinctive_features.md b/docs/en/introduction/distinctive_features.md index f626f13c274..ad6a7efc6e0 100644 --- a/docs/en/introduction/distinctive_features.md +++ b/docs/en/introduction/distinctive_features.md @@ -2,27 +2,27 @@ ## True column-oriented DBMS -In a true column-oriented DBMS, there isn't any "garbage" stored with the values. Among other things, this means that constant-length values must be supported, to avoid storing their length "number" next to the values. As an example, a billion UInt8-type values should actually consume around 1 GB uncompressed, or this will strongly affect the CPU use. It is very important to store data compactly (without any "garbage") even when uncompressed, since the speed of decompression (CPU usage) depends mainly on the volume of uncompressed data. +In a true column-oriented DBMS, there is no excessive data stored with the values. For example, this means that constant-length values must be supported, to avoid storing their length as additional integer next to the values. In this case, a billion UInt8 values should actually consume around 1 GB uncompressed, or this will strongly affect the CPU use. It is very important to store data compactly even when uncompressed, since the speed of decompression (CPU usage) depends mainly on the volume of uncompressed data. -This is worth noting because there are systems that can store values of separate columns separately, but that can't effectively process analytical queries due to their optimization for other scenarios. Examples are HBase, BigTable, Cassandra, and HyperTable. In these systems, you will get throughput around a hundred thousand rows per second, but not hundreds of millions of rows per second. +This is worth noting because there are systems that can store values of different columns separately, but that can't effectively process analytical queries due to their optimization for other scenarios. Examples are HBase, BigTable, Cassandra, and HyperTable. In these systems, you will get throughput around a hundred thousand rows per second, but not hundreds of millions of rows per second. -Also note that ClickHouse is a DBMS, not a single database. ClickHouse allows creating tables and databases in runtime, loading data, and running queries without reconfiguring and restarting the server. +Also note that ClickHouse is a database management system, not a single database. ClickHouse allows creating tables and databases in runtime, loading data, and running queries without reconfiguring and restarting the server. ## Data compression -Some column-oriented DBMSs (InfiniDB CE and MonetDB) do not use data compression. However, data compression really improves performance. +Some column-oriented DBMSs (InfiniDB CE and MonetDB) do not use data compression. However, data compression is crucial to achieve excellent performance. ## Disk storage of data -Many column-oriented DBMSs (such as SAP HANA and Google PowerDrill) can only work in RAM. But even on thousands of servers, the RAM is too small for storing all the pageviews and sessions in Yandex.Metrica. +Many column-oriented DBMSs (such as SAP HANA and Google PowerDrill) can only work in RAM. This approach stimulates the allocation of a larger hardware budget than is actually necessary for real-time analysis. ClickHouse is designed to work on regular hard drives, which ensures low cost of ownership per gigabyte of data, but SSD and additional RAM are also utilized fully if available. ## Parallel processing on multiple cores -Large queries are parallelized in a natural way. +Large queries are parallelized in a natural way, utilizing all necessary resources that are available on the current server. ## Distributed processing on multiple servers -Almost none of the columnar DBMSs listed above have support for distributed processing. +Almost none of the columnar DBMSs mentioned above have support for distributed query processing. In ClickHouse, data can reside on different shards. Each shard can be a group of replicas that are used for fault tolerance. The query is processed on all the shards in parallel. This is transparent for the user. ## SQL support @@ -33,30 +33,37 @@ However, this is a declarative query language based on SQL that can't be differe JOINs are supported. Subqueries are supported in FROM, IN, and JOIN clauses, as well as scalar subqueries. Dependent subqueries are not supported. +ClickHouse supports declarative query language that is based on SQL and complies to SQL standard in many cases. +GROUP BY, ORDER BY, scalar subqueries and subqueries in FROM, IN and JOIN clauses are supported. +Correlated subqueries and window functions are not supported. + ## Vector engine -Data is not only stored by columns, but is processed by vectors (parts of columns). This allows us to achieve high CPU performance. +Data is not only stored by columns, but is also processed by vectors (parts of columns). This allows to achieve high CPU efficiency. ## Real-time data updates -ClickHouse supports primary key tables. In order to quickly perform queries on the range of the primary key, the data is sorted incrementally using the merge tree. Due to this, data can continually be added to the table. There is no locking when adding data. +ClickHouse supports tables with a primary key. In order to quickly perform queries on the range of the primary key, the data is sorted incrementally using the merge tree. Due to this, data can continually be added to the table. No locks are taken when new data is ingested. -## Indexes +## Index -Having a primary key makes it possible to extract data for specific clients (for instance, Yandex.Metrica tracking tags) for a specific time range, with low latency less than several dozen milliseconds. +Having a data physically sorted by primary key makes it possible to extract data for it's specific values or value ranges with low latency, less than few dozen milliseconds. ## Suitable for online queries -This lets us use the system as the back-end for a web interface. Low latency means queries can be processed without delay, while the Yandex.Metrica interface page is loading. In other words, in online mode. +Low latency means that queries can be processed without delay and without trying to prepare answer in advance, right at the same moment while user interface page is loading. In other words, online. ## Support for approximated calculations -1. The system contains aggregate functions for approximated calculation of the number of various values, medians, and quantiles. -2. Supports running a query based on a part (sample) of data and getting an approximated result. In this case, proportionally less data is retrieved from the disk. -3. Supports running an aggregation for a limited number of random keys, instead of for all keys. Under certain conditions for key distribution in the data, this provides a reasonably accurate result while using fewer resources. +ClickHouse provides various ways to trade accuracy for performance: -## Data replication and support for data integrity on replicas +1. Aggregate functions for approximated calculation of the number of distinct values, medians, and quantiles. +2. Running a query based on a part (sample) of data and getting an approximated result. In this case, proportionally less data is retrieved from the disk. +3. Running an aggregation for a limited number of random keys, instead of for all keys. Under certain conditions for key distribution in the data, this provides a reasonably accurate result while using fewer resources. -Uses asynchronous multimaster replication. After being written to any available replica, data is distributed to all the remaining replicas. The system maintains identical data on different replicas. Data is restored automatically after a failure, or using a "button" for complex cases. -For more information, see the section [Data replication](../operations/table_engines/replication.md#table_engines-replication). +## Data replication and integrity + +ClickHouse uses asynchronous multimaster replication. After being written to any available replica, data is distributed to all the other replicas in background. The system maintains identical data on different replicas. Data is restored automatically after most failures, or semiautomatically in complicated cases. + +For more information, see the [Data replication](../operations/table_engines/replication.md#table_engines-replication) section. diff --git a/docs/en/introduction/features_considered_disadvantages.md b/docs/en/introduction/features_considered_disadvantages.md index 80708c02883..54a1f2c7a69 100644 --- a/docs/en/introduction/features_considered_disadvantages.md +++ b/docs/en/introduction/features_considered_disadvantages.md @@ -1,6 +1,6 @@ # ClickHouse features that can be considered disadvantages -1. No transactions. -2. For aggregation, query results must fit in the RAM on a single server. However, the volume of source data for a query may be indefinitely large. -3. Lack of full-fledged UPDATE/DELETE implementation. +1. No full-fledged transactions. +2. Lack of ability to modify or delete already inserted data with high rate and low latency. There are batch deletes available to clean up data that is not needed anymore or to comply with [GDPR](https://gdpr-info.eu). Batch updates are in development as of July 2018. +3. Sparse index makes ClickHouse not really suitable for point queries retrieving single rows by their keys. diff --git a/docs/ru/introduction/distinctive_features.md b/docs/ru/introduction/distinctive_features.md index 031a5c7f6bb..c85d464222b 100644 --- a/docs/ru/introduction/distinctive_features.md +++ b/docs/ru/introduction/distinctive_features.md @@ -2,23 +2,23 @@ ## По-настоящему столбцовая СУБД -В по-настоящему столбцовой СУБД рядом со значениями не хранится никакого "мусора". Например, должны поддерживаться значения постоянной длины, чтобы не хранить рядом со значениями типа "число" их длины. Для примера, миллиард значений типа UInt8 должен действительно занимать в несжатом виде около 1GB, иначе это сильно ударит по эффективности использования CPU. Очень важно хранить данные компактно (без "мусора") в том числе в несжатом виде, так как скорость разжатия (использование CPU) зависит, в основном, от объёма несжатых данных. +В по-настоящему столбцовой СУБД рядом со значениями не хранится никаких лишних данных. Например, должны поддерживаться значения постоянной длины, чтобы не хранить рядом со значениями типа "число" их длины. Для примера, миллиард значений типа UInt8 должен действительно занимать в несжатом виде около 1GB, иначе это сильно ударит по эффективности использования CPU. Очень важно хранить данные компактно (без "мусора") в том числе в несжатом виде, так как скорость разжатия (использование CPU) зависит, в основном, от объёма несжатых данных. -Этот пункт пришлось выделить, так как существуют системы, которые могут хранить значения отдельных столбцов по отдельности, но не могут эффективно выполнять аналитические запросы в силу оптимизации под другой сценарий работы. Примеры: HBase, BigTable, Cassandra, HyperTable. В этих системах вы получите throughput в районе сотен тысяч строк в секунду, но не сотен миллионов строк в секунду. +Этот пункт пришлось выделить, так как существуют системы, которые могут хранить значения отдельных столбцов по отдельности, но не могут эффективно выполнять аналитические запросы в силу оптимизации под другой сценарий работы. Примеры: HBase, BigTable, Cassandra, HyperTable. В этих системах вы получите пропускную способность в районе сотен тысяч строк в секунду, но не сотен миллионов строк в секунду. -Также стоит заметить, что ClickHouse является СУБД, а не одной базой данных. То есть, ClickHouse позволяет создавать таблицы и базы данных в runtime, загружать данные и выполнять запросы без переконфигурирования и перезапуска сервера. +Также стоит заметить, что ClickHouse является системой управления базами данных, а не одной базой данных. То есть, ClickHouse позволяет создавать таблицы и базы данных в runtime, загружать данные и выполнять запросы без переконфигурирования и перезапуска сервера. ## Сжатие данных -Некоторые столбцовые СУБД (InfiniDB CE, MonetDB) не используют сжатие данных. Но сжатие данных действительно серьёзно увеличивает производительность. +Некоторые столбцовые СУБД (InfiniDB CE, MonetDB) не используют сжатие данных. Однако сжатие данных действительно играет одну из ключевых ролей в демонстрации отличной производительности. ## Хранение данных на диске -Многие столбцовые СУБД (SAP HANA, Google PowerDrill) могут работать только в оперативке. Но оперативки (даже на тысячах серверах) слишком мало для хранения всех хитов и визитов в Яндекс.Метрике. +Многие столбцовые СУБД (SAP HANA, Google PowerDrill) могут работать только в оперативной памяти. Такой подход стимулирует выделять больший бюджет на оборудование, чем фактически требуется для анализа в реальном времени. ClickHouse спроектирован для работы на обычных жестких дисках, что обеспечивает низкую стоимость хранения на гигабайт данных, но SSD b дополнительная оперативная память тоже полноценно используются, если доступны. ## Параллельная обработка запроса на многих процессорных ядрах -Большие запросы естественным образом распараллеливаются. +Большие запросы естественным образом распараллеливаются, используя все необходимые ресурсы из доступных на сервере. ## Распределённая обработка запроса на многих серверах @@ -27,11 +27,9 @@ ## Поддержка SQL -Если вы знаете, что такое стандартный SQL, то говорить о поддержке SQL всё-таки нельзя. -Все функции названы по-другому. -Тем не менее, это - декларативный язык запросов на основе SQL и во многих случаях не отличимый от SQL. -Поддерживаются JOIN-ы. Поддерживаются подзапросы в секциях FROM, IN, JOIN, а также скалярные подзапросы. -Зависимые подзапросы не поддерживаются. +ClickHouse поддерживает декларативный язык запросов на основе SQL и во многих случаях совпадающий с SQL стандартом. +Поддерживаются GROUP BY, ORDER BY, подзапросы в секциях FROM, IN, JOIN, а также скалярные подзапросы. +Зависимые подзапросы и оконные функции не поддерживаются. ## Векторный движок @@ -41,21 +39,24 @@ ClickHouse поддерживает таблицы с первичным ключом. Для того, чтобы можно было быстро выполнять запросы по диапазону первичного ключа, данные инкрементально сортируются с помощью merge дерева. За счёт этого, поддерживается постоянное добавление данных в таблицу. Блокировки при добавлении данных отсутствуют. -## Наличие индексов +## Наличие индекса -Наличие первичного ключа позволяет, например, вынимать данные для конкретных клиентов (счётчиков Метрики), для заданного диапазона времени, с низкими задержками - менее десятков миллисекунд. +Физическая сортировка данных по первичному ключу позволяет получать данные для конкретных его значений или их диапазонов с низкими задержками - менее десятков миллисекунд. ## Подходит для онлайн запросов -Это позволяет использовать систему в качестве бэкенда для веб-интерфейса. Низкие задержки позволяют не откладывать выполнение запроса, а выполнять его в момент загрузки страницы интерфейса Яндекс.Метрики. То есть, в режиме онлайн. +Низкие задержки позволяют не откладывать выполнение запроса и не подготавливать ответ заранее, а выполнять его именно в момент загрузки страницы пользовательского интерфейса. То есть, в режиме онлайн. ## Поддержка приближённых вычислений +ClickHouse предоставляет различные способы разменять точность вычислений на производительность: + 1. Система содержит агрегатные функции для приближённого вычисления количества различных значений, медианы и квантилей. 2. Поддерживается возможность выполнить запрос на основе части (выборки) данных и получить приближённый результат. При этом, с диска будет считано пропорционально меньше данных. 3. Поддерживается возможность выполнить агрегацию не для всех ключей, а для ограниченного количества первых попавшихся ключей. При выполнении некоторых условий на распределение ключей в данных, это позволяет получить достаточно точный результат с использованием меньшего количества ресурсов. -## Репликация данных, поддержка целостности данных на репликах +## Репликация данных и поддержка целостности + +Используется асинхронная multimaster репликация. После записи на любую доступную реплику, данные распространяются на все остальные реплики в фоне. Система поддерживает полную идентичность данных на разных репликах. Восстановление после большинства сбоев осуществляется автоматически, а в сложных случаях — полуавтоматически. -Используется асинхронная multimaster репликация. После записи на любую доступную реплику, данные распространяются на все остальные реплики. Система поддерживает полную идентичность данных на разных репликах. Восстановление после сбоя осуществляется автоматически, а в сложных случаях - "по кнопке". Подробнее смотрите раздел [Репликация данных](../operations/table_engines/replication.md#table_engines-replication). diff --git a/docs/ru/introduction/features_considered_disadvantages.md b/docs/ru/introduction/features_considered_disadvantages.md index c26272f4b6c..b7ac877cc32 100644 --- a/docs/ru/introduction/features_considered_disadvantages.md +++ b/docs/ru/introduction/features_considered_disadvantages.md @@ -1,6 +1,6 @@ # Особенности ClickHouse, которые могут считаться недостатками -1. Отсутствие транзакций. -2. Необходимо, чтобы результат выполнения запроса, в случае агрегации, помещался в оперативку на одном сервере. Объём исходных данных для запроса, при этом, может быть сколь угодно большим. -3. Отсутствие полноценной реализации UPDATE/DELETE. - +1. Отсутствие полноценных транзакций. +2. Возможность изменять или удалять ранее записанные данные с низкими задержками и высокой частотой запросов не предоставляется. Есть массовое удаление данных для очистки более не нужного или соответствия [GDPR](https://gdpr-info.eu). Массовое изменение данных находится в разработке (на момент июля 2018). +3. Разреженный индекс делает ClickHouse плохо пригодным для точечных чтений одиночных строк по своим +ключам. From 8879c75d8b7011aa0c5cad8dcaa00f128996bc2c Mon Sep 17 00:00:00 2001 From: BayoNet Date: Fri, 27 Jul 2018 16:00:01 +0300 Subject: [PATCH 186/425] Improvements based on comments on https://github.com/yandex/ClickHouse/pull/2730 --- docs/ru/data_types/array.md | 4 +++- docs/ru/data_types/enum.md | 6 ++---- docs/ru/data_types/nullable.md | 16 ++++++++++------ docs/ru/data_types/special_data_types/nothing.md | 2 +- docs/ru/data_types/tuple.md | 2 +- .../query_language/functions/array_functions.md | 2 -- .../functions/functions_for_nulls.md | 2 +- .../query_language/functions/other_functions.md | 2 +- docs/ru/query_language/operators.md | 4 ++-- docs/ru/query_language/select.md | 14 ++------------ docs/ru/query_language/syntax.md | 2 +- 11 files changed, 24 insertions(+), 32 deletions(-) diff --git a/docs/ru/data_types/array.md b/docs/ru/data_types/array.md index 0e3b78a9688..2e85a84d19e 100644 --- a/docs/ru/data_types/array.md +++ b/docs/ru/data_types/array.md @@ -49,7 +49,9 @@ SELECT ## Особенности работы с типами данных -При создании массива "на лету" ClickHouse автоматически определяет тип аргументов как тип, в котором можно хранить все перечисленные аргументы. Если среди аргументов есть [NULL](../query_language/syntax.md#null-literal), то тип элементов массива — [Nullable](nullable.md#data_type-nullable). +При создании массива "на лету" ClickHouse автоматически определяет тип аргументов как наиболее узкий тип данных, в котором можно хранить все перечисленные аргументы. Если среди аргументов есть [NULL](../query_language/syntax.md#null-literal) или аргумент типа [Nullable](nullable.md#data_type-nullable), то тип элементов массива — [Nullable](nullable.md#data_type-nullable). + +Если ClickHouse не смог подобрать тип данных, то он сгенерирует исключение. Это произойдёт, например, при попытке создать массив одновременно со строками и числами `SELECT array(1, 'a')`. Примеры автоматического определения типа данных: diff --git a/docs/ru/data_types/enum.md b/docs/ru/data_types/enum.md index 9f0636c36c6..dec9df575cc 100644 --- a/docs/ru/data_types/enum.md +++ b/docs/ru/data_types/enum.md @@ -4,10 +4,8 @@ Семейство типов. Включает в себя типы `Enum8` и `Enum16`. `Enum` сохраняет конечный набор пар `'строка' = целое число`. Все операции с данными типа `Enum` ClickHouse выполняет как с числами, однако пользователь при этом работает со строковыми константами. Это более эффективно с точки зрения производительности, чем работа с типом данных `String`. -Подтипы: - -- `Enum8` состоит из пар `'String' = Int8`. -- `Enum16` состоит из пар `'String' = Int16`. +- `Enum8` описывается парами `'String' = Int8`. +- `Enum16` описывается парами `'String' = Int16`. ## Примеры применения diff --git a/docs/ru/data_types/nullable.md b/docs/ru/data_types/nullable.md index 14c00257740..f098cac2f76 100644 --- a/docs/ru/data_types/nullable.md +++ b/docs/ru/data_types/nullable.md @@ -2,7 +2,7 @@ # Nullable(TypeName) -Позволяет хранить в таблице [NULL](../query_language/syntax.md#null-literal) вместо значения типа `TypeName`. Например, `Nullable(Int8)` позволяет хранить `NULL` вместо значений `Int8`. +Позволяет работать как со значением типа `TypeName` так и с отсутствием этого значения ([NULL](../query_language/syntax.md#null-literal)) в одной и той же переменной, в том числе хранить `NULL` в таблицах вместе со значения типа `TypeName`. Например, в столбце типа `Nullable(Int8)` можно хранить значения типа `Int8`, а в тех строках, где значения нет, будет храниться `NULL`. В качестве `TypeName` нельзя использовать составные типы данных [Array](array.md#data_type-array) и [Tuple](tuple.md#data_type-tuple). Составные типы данных могут содержать значения типа `Nullable`, например `Array(Nullable(Int8))`. @@ -19,12 +19,15 @@ Маска определяет, что лежит в ячейке данных: `NULL` или значение. -В случае, когда маска указывает, что в ячейке хранится `NULL`, в файле значений хранится значение по умолчанию для типа данных. Т.е. если, например, поле имеет тип `Nullable(Int8)`, то ячейка будет хранить значение по умолчанию для `Int8`. Эта особенность увеличивает размер хранилища. Также для некоторых операций возможно снижение производительности. Будьте внимательны при проектировании системы хранения. +В случае, когда маска указывает, что в ячейке хранится `NULL`, в файле значений хранится значение по умолчанию для типа данных. Т.е. если, например, поле имеет тип `Nullable(Int8)`, то ячейка будет хранить значение по умолчанию для `Int8`. Эта особенность увеличивает размер хранилища. + +!!! info + Почти всегда использование `Nullable` снижает производительность, учитывайте это при проектировании своих баз. ## Пример использования ``` -:) CREATE TABLE t_null(x Int8, y Nullable(Int8)) engine TinyLog +:) CREATE TABLE t_null(x Int8, y Nullable(Int8)) ENGINE TinyLog CREATE TABLE t_null ( @@ -45,15 +48,16 @@ Ok. 1 rows in set. Elapsed: 0.007 sec. -:) SELECT x+y from t_null +:) SELECT x + y from t_null SELECT x + y FROM t_null ┌─plus(x, y)─┐ -│ \N │ +│ ᴺᵁᴸᴸ │ +│ 5 │ └────────────┘ -1 rows in set. Elapsed: 0.009 sec. +2 rows in set. Elapsed: 0.144 sec. ``` diff --git a/docs/ru/data_types/special_data_types/nothing.md b/docs/ru/data_types/special_data_types/nothing.md index b6c9ac9887a..6b83c354d5e 100644 --- a/docs/ru/data_types/special_data_types/nothing.md +++ b/docs/ru/data_types/special_data_types/nothing.md @@ -2,7 +2,7 @@ # Nothing -Этот тип данных предназначен только для того, чтобы представлять [NULL](../../query_language/syntax.md#null-literal). +Этот тип данных предназначен только для того, чтобы представлять [NULL](../../query_language/syntax.md#null-literal), т.е. отсутствие значения. Невозможно создать значение типа `Nothing`, поэтому он используется там, где значение не подразумевается. Например, `NULL` записывается как `Nullable(Nothing)` ([Nullable](../../data_types/nullable.md#data_type-nullable) — это тип данных, позволяющий хранить `NULL` в таблицах). Также тип `Nothing` используется для обозначения пустых массивов: diff --git a/docs/ru/data_types/tuple.md b/docs/ru/data_types/tuple.md index 49852b6fe40..66aca46d939 100644 --- a/docs/ru/data_types/tuple.md +++ b/docs/ru/data_types/tuple.md @@ -2,7 +2,7 @@ # Tuple(T1, T2, ...) -Кортеж из элементов разного [типа](index.md#data_types). Тип каждого элемента может быть любым из тех, что поддерживает ClickHouse. +Кортеж из элементов любого [типа](index.md#data_types). Элементы кортежа могут быть одного или разных типов. Кортежи нельзя хранить в таблицах (кроме таблиц типа Memory). Они используется для временной группировки столбцов. Столбцы могут группироваться при использовании выражения IN в запросе, а также для указания нескольких формальных параметров лямбда-функций. Подробнее смотрите разделы [Операторы IN](../query_language/select.md#in_operators), [Функции высшего порядка](../query_language/functions/higher_order_functions.md#higher_order_functions). diff --git a/docs/ru/query_language/functions/array_functions.md b/docs/ru/query_language/functions/array_functions.md index 1ded3b458b1..4fab96f32e7 100644 --- a/docs/ru/query_language/functions/array_functions.md +++ b/docs/ru/query_language/functions/array_functions.md @@ -282,8 +282,6 @@ SELECT arrayPushBack(['a'], 'b') AS res └───────────┘ ``` - - ## arrayPushFront Добавляет один элемент в начало массива. diff --git a/docs/ru/query_language/functions/functions_for_nulls.md b/docs/ru/query_language/functions/functions_for_nulls.md index aec79e67c22..5d5314efb6b 100644 --- a/docs/ru/query_language/functions/functions_for_nulls.md +++ b/docs/ru/query_language/functions/functions_for_nulls.md @@ -90,7 +90,7 @@ WHERE isNotNull(y) ## coalesce -Последовательно проверяет являются ли переданные аргументы `NULL` и возвращает первый не `NULL`. +Последовательно слева-направо проверяет являются ли переданные аргументы `NULL` и возвращает первый не `NULL`. ``` coalesce(x,...) diff --git a/docs/ru/query_language/functions/other_functions.md b/docs/ru/query_language/functions/other_functions.md index f1c4fb19152..fb41049f23c 100644 --- a/docs/ru/query_language/functions/other_functions.md +++ b/docs/ru/query_language/functions/other_functions.md @@ -340,7 +340,7 @@ SELECT toColumnTypeName(CAST('2018-01-01 01:02:03', 'DateTime')) └───────────────────────────────────────────────────────────┘ ``` -В этом примере хорошо видно, что тип данных `DateTime` хранится в памяти как `Const(UInt32)`. +В примере видно, что тип данных `DateTime` хранится в памяти как `Const(UInt32)`. ## dumpColumnStructure diff --git a/docs/ru/query_language/operators.md b/docs/ru/query_language/operators.md index 2f9198ffa63..e143214137e 100644 --- a/docs/ru/query_language/operators.md +++ b/docs/ru/query_language/operators.md @@ -81,7 +81,7 @@ Примечание: -Условный оператор сначала вычисляет значения b и c, затем проверяет выполнение условия a, и только после этого возвращает соответствующее значение. Если в качестве b или с выступает функция arrayJoin(), то размножение каждой строки произойдет вне зависимости от условия а. +Условный оператор сначала вычисляет значения b и c, затем проверяет выполнение условия a, и только после этого возвращает соответствующее значение. Если в качестве b или с выступает функция [arrayJoin()](functions/array_join.md#functions_arrayjoin), то размножение каждой строки произойдет вне зависимости от условия а. @@ -122,7 +122,7 @@ END Для эффективности, реализованы функции `and` и `or`, принимающие произвольное количество аргументов. Соответствующие цепочки операторов `AND` и `OR`, преобразуются в один вызов этих функций. -## Проверка `NULL` +## Проверка на `NULL` ClickHouse поддерживает операторы `IS NULL` и `IS NOT NULL`. diff --git a/docs/ru/query_language/select.md b/docs/ru/query_language/select.md index c0540a36188..232386c485f 100644 --- a/docs/ru/query_language/select.md +++ b/docs/ru/query_language/select.md @@ -455,16 +455,6 @@ ClickHouse использует в выражении индексы, если Пример проверки на `NULL`: ```bash -:) SELECT * FROM t_null WHERE y=NULL - -SELECT * -FROM t_null -WHERE y = NULL - -Ok. - -0 rows in set. Elapsed: 0.002 sec. - :) SELECT * FROM t_null WHERE y IS NULL SELECT * @@ -555,7 +545,7 @@ GROUP BY вычисляет для каждого встретившегося └───┴──────┘ ``` -В результате запроса `SELECT sum(x),y FROM t_null_big GROUP BY y` мы получим: +В результате запроса `SELECT sum(x), y FROM t_null_big GROUP BY y` мы получим: ``` ┌─sum(x)─┬────y─┐ @@ -658,7 +648,7 @@ WHERE и HAVING отличаются тем, что WHERE выполняется - С модификатором `NULLS FIRST` — Сначала `NULL`, затем `NaN`, затем остальные значения. - С модификатором `NULLS LAST` — Сначала значения, затем `NaN`, затем `NULL`. -- Без модификаторов `NULLS FIRST` или `NULLS LAST` как с модификатором `NULLS LAST`. +- По умолчанию — Как с модификатором `NULLS LAST`. Пример: diff --git a/docs/ru/query_language/syntax.md b/docs/ru/query_language/syntax.md index 2ae484ee957..192b314cfbf 100644 --- a/docs/ru/query_language/syntax.md +++ b/docs/ru/query_language/syntax.md @@ -49,7 +49,7 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') - иначе - ошибка. Соответствующее значение будет иметь тип минимального размера, который вмещает значение. -Например, 1 парсится как `UInt8`, а 256 - как `UInt16`. Подробнее смотрите "Типы данных". +Например, 1 парсится как `UInt8`, а 256 - как `UInt16`. Подробнее смотрите раздел [Типы данных](../data_types/index.md#data_types). Примеры: `1`, `18446744073709551615`, `0xDEADBEEF`, `01`, `0.1`, `1e100`, `-1e-100`, `inf`, `nan`. From 92719e1f4813d860e1ca6e75a692b21c6926cf47 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 23 Jul 2018 18:54:10 +0300 Subject: [PATCH 187/425] Supported JOIN ON syntax for single and chain in expression analyzer. [#CLICKHOUSE-3761] --- dbms/src/Common/ErrorCodes.cpp | 1 + dbms/src/Interpreters/ExpressionAnalyzer.cpp | 51 ++++++++++++++++---- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index a1662563a1f..a789a602751 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -377,6 +377,7 @@ namespace ErrorCodes extern const int CANNOT_STAT = 400; extern const int FEATURE_IS_NOT_ENABLED_AT_BUILD_TIME = 401; extern const int CANNOT_IOSETUP = 402; + extern const int INVALID_JOIN_ON_EXPRESSION = 403; extern const int KEEPER_EXCEPTION = 999; diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 6497b865cea..a065d01f88c 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -61,6 +61,7 @@ #include #include #include +#include namespace DB @@ -89,6 +90,7 @@ namespace ErrorCodes extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int CONDITIONAL_TREE_PARENT_NOT_FOUND; extern const int TYPE_MISMATCH; + extern const int INVALID_JOIN_ON_EXPRESSION; } @@ -2856,22 +2858,53 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd nested_result_sample = InterpreterSelectWithUnionQuery::getSampleBlock(subquery, context); } + auto add_name_to_join_keys = [](Names & join_keys, const String & name, const char * where) + { + if (join_keys.end() == std::find(join_keys.begin(), join_keys.end(), name)) + join_keys.push_back(name); + else + throw Exception("Duplicate column " + name + " " + where, ErrorCodes::DUPLICATE_COLUMN); + }; + if (table_join.using_expression_list) { auto & keys = typeid_cast(*table_join.using_expression_list); for (const auto & key : keys.children) { - if (join_key_names_left.end() == std::find(join_key_names_left.begin(), join_key_names_left.end(), key->getColumnName())) - join_key_names_left.push_back(key->getColumnName()); - else - throw Exception("Duplicate column " + key->getColumnName() + " in USING list", ErrorCodes::DUPLICATE_COLUMN); - - if (join_key_names_right.end() == std::find(join_key_names_right.begin(), join_key_names_right.end(), key->getAliasOrColumnName())) - join_key_names_right.push_back(key->getAliasOrColumnName()); - else - throw Exception("Duplicate column " + key->getAliasOrColumnName() + " in USING list", ErrorCodes::DUPLICATE_COLUMN); + add_name_to_join_keys(join_key_names_left, key->getColumnName(), "in USING list"); + add_name_to_join_keys(join_key_names_right, key->getAliasOrColumnName(), "in USING list"); } } + else if (table_join.on_expression) + { + const auto supported_syntax = + "\nSupported syntax: JOIN ON [table.]column = [table.]column [AND [table.]column = [table.]column ...]"; + auto throwSyntaxException = [&](const String & msg) + { + throw Exception("Invalid expression for JOIN ON. " + msg + supported_syntax, ErrorCodes::INVALID_JOIN_ON_EXPRESSION); + }; + + auto add_columns_from_equals_expr = [&](const ASTPtr & expr) + { + auto * func_equals = typeid_cast(expr.get()); + if (!func_equals || func_equals->name != "equals") + throwSyntaxException("Expected equals expression, got " + queryToString(expr)); + + String left_name = func_equals->arguments->children.at(0)->getAliasOrColumnName(); + String right_name = func_equals->arguments->children.at(1)->getAliasOrColumnName(); + add_name_to_join_keys(join_key_names_left, left_name, "in JOIN ON expression for left table"); + add_name_to_join_keys(join_key_names_right, right_name, "in JOIN ON expression for right table"); + }; + + auto * func = typeid_cast(table_join.on_expression.get()); + if (func && func->name == "and") + { + for (auto expr : func->children) + add_columns_from_equals_expr(expr); + } + else + add_columns_from_equals_expr(table_join.on_expression); + } for (const auto i : ext::range(0, nested_result_sample.columns())) { From 5058d1a3455151329cef156161a7c53c10802873 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 24 Jul 2018 13:00:53 +0300 Subject: [PATCH 188/425] Added columns from join on key of right table if they have different name from left block key in merged block. [#CLICKHOUSE-3761] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 4 ++-- dbms/src/Interpreters/Join.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index a065d01f88c..72b423858b2 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -2899,7 +2899,7 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd auto * func = typeid_cast(table_join.on_expression.get()); if (func && func->name == "and") { - for (auto expr : func->children) + for (auto expr : func->arguments->children) add_columns_from_equals_expr(expr); } else @@ -2909,7 +2909,7 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd for (const auto i : ext::range(0, nested_result_sample.columns())) { const auto & col = nested_result_sample.safeGetByPosition(i); - if (join_key_names_right.end() == std::find(join_key_names_right.begin(), join_key_names_right.end(), col.name) + if (join_key_names_left.end() == std::find(join_key_names_left.begin(), join_key_names_left.end(), col.name) && !joined_columns.count(col.name)) /// Duplicate columns in the subquery for JOIN do not make sense. { joined_columns.insert(col.name); diff --git a/dbms/src/Interpreters/Join.cpp b/dbms/src/Interpreters/Join.cpp index 7409af75986..0694d58e0e6 100644 --- a/dbms/src/Interpreters/Join.cpp +++ b/dbms/src/Interpreters/Join.cpp @@ -776,6 +776,19 @@ void Join::joinBlockImpl(Block & block, const Maps & maps) const if (offsets_to_replicate) for (size_t i = 0; i < existing_columns; ++i) block.safeGetByPosition(i).column = block.safeGetByPosition(i).column->replicate(*offsets_to_replicate); + + /// Add columns from right block. + for (size_t i = 0; i < key_names_right.size(); ++i) + { + auto & right_name = key_names_right[i]; + auto & left_name = key_names_left[i]; + + if (!block.has(right_name) && block.has(left_name)) + { + const auto & col = block.getByName(left_name); + block.insert({col.column, col.type, right_name}); + } + } } From 391ff31829f17c9881c02a55c1e6ad929cd851b5 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 24 Jul 2018 15:41:35 +0300 Subject: [PATCH 189/425] Added actions for JOIN key columns. [#CLICKHOUSE-3761] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 52 +++++++++++++++++--- dbms/src/Interpreters/ExpressionAnalyzer.h | 4 ++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 72b423858b2..538d64f3e18 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -1815,16 +1815,15 @@ const Block & ScopeStack::getSampleBlock() const void ExpressionAnalyzer::getRootActions(const ASTPtr & ast, bool no_subqueries, bool only_consts, ExpressionActionsPtr & actions) { ScopeStack scopes(actions, settings); + ProjectionManipulatorPtr projection_manipulator; if (!isThereArrayJoin(ast) && settings.enable_conditional_computation && !only_consts) - { projection_manipulator = std::make_shared(scopes, context); - } else - { projection_manipulator = std::make_shared(scopes); - } + getActionsImpl(ast, no_subqueries, only_consts, scopes, projection_manipulator); + actions = scopes.popLevel(); } @@ -1983,6 +1982,48 @@ bool ExpressionAnalyzer::isThereArrayJoin(const ASTPtr & ast) } } +void ExpressionAnalyzer::getActionsFromJoinKeys(const ASTTableJoin & table_join, bool no_subqueries, bool only_consts, + ExpressionActionsPtr & actions) +{ + ScopeStack scopes(actions, settings); + + ProjectionManipulatorPtr projection_manipulator; + if (!isThereArrayJoin(ast) && settings.enable_conditional_computation && !only_consts) + projection_manipulator = std::make_shared(scopes, context); + else + projection_manipulator = std::make_shared(scopes); + + if (table_join.using_expression_list) + getActionsImpl(table_join.using_expression_list, no_subqueries, only_consts, scopes, projection_manipulator); + else if (table_join.on_expression) + { + std::function get_actions; + get_actions = [&](const ASTPtr & ast) + { + bool key_expr = false; + + if (const auto * ast_function = typeid_cast(ast.get())) + { + auto column_name = ast_function->getColumnName(); + key_expr = join_key_names_left.end() + != std::find(join_key_names_left.begin(), join_key_names_left.end(), column_name); + } + + if (key_expr) + getActionsImpl(ast, no_subqueries, only_consts, scopes, projection_manipulator); + else + { + for (auto & child : ast->children) + get_actions(child); + } + }; + + get_actions(table_join.on_expression); + } + + actions = scopes.popLevel(); +} + void ExpressionAnalyzer::getActionsImpl(const ASTPtr & ast, bool no_subqueries, bool only_consts, ScopeStack & actions_stack, ProjectionManipulatorPtr projection_manipulator) { @@ -2434,8 +2475,7 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty const ASTTableJoin & join_params = static_cast(*join_element.table_join); const ASTTableExpression & table_to_join = static_cast(*join_element.table_expression); - if (join_params.using_expression_list) - getRootActions(join_params.using_expression_list, only_types, false, step.actions); + getActionsFromJoinKeys(join_params, only_types, false, step.actions); /// Two JOINs are not supported with the same subquery, but different USINGs. auto join_hash = join_element.getTreeHash(); diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.h b/dbms/src/Interpreters/ExpressionAnalyzer.h index 4b8d21daa0f..74e782119e6 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.h +++ b/dbms/src/Interpreters/ExpressionAnalyzer.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace DB { @@ -308,6 +309,9 @@ private: void getActionsImpl(const ASTPtr & ast, bool no_subqueries, bool only_consts, ScopeStack & actions_stack, ProjectionManipulatorPtr projection_manipulator); + /// If ast is ASTSelectQuery with JOIN, add actions for JOIN key columns. + void getActionsFromJoinKeys(const ASTTableJoin & table_join, bool no_subqueries, bool only_consts, ExpressionActionsPtr & actions); + void getRootActions(const ASTPtr & ast, bool no_subqueries, bool only_consts, ExpressionActionsPtr & actions); void getActionsBeforeAggregation(const ASTPtr & ast, ExpressionActionsPtr & actions, bool no_subqueries); From cc613d7ad318baae15418f0697e657e580b9fa1e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 24 Jul 2018 19:43:33 +0300 Subject: [PATCH 190/425] Added JOIN keys to the list of needed columns for JOIN expression action. --- dbms/src/Interpreters/ExpressionActions.cpp | 8 ++++++-- dbms/src/Interpreters/ExpressionActions.h | 4 +++- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionActions.cpp b/dbms/src/Interpreters/ExpressionActions.cpp index ebf3ef3aac8..37c7b205807 100644 --- a/dbms/src/Interpreters/ExpressionActions.cpp +++ b/dbms/src/Interpreters/ExpressionActions.cpp @@ -41,6 +41,8 @@ Names ExpressionAction::getNeededColumns() const res.insert(res.end(), array_joined_columns.begin(), array_joined_columns.end()); + res.insert(res.end(), join_key_names_left.begin(), join_key_names_left.end()); + for (const auto & column : projection) res.push_back(column.first); @@ -146,11 +148,13 @@ ExpressionAction ExpressionAction::arrayJoin(const NameSet & array_joined_column return a; } -ExpressionAction ExpressionAction::ordinaryJoin(std::shared_ptr join_, const NamesAndTypesList & columns_added_by_join_) +ExpressionAction ExpressionAction::ordinaryJoin(std::shared_ptr join_, const Names & join_key_names_left, + const NamesAndTypesList & columns_added_by_join_) { ExpressionAction a; a.type = JOIN; - a.join = join_; + a.join = std::move(join_); + a.join_key_names_left = join_key_names_left; a.columns_added_by_join = columns_added_by_join_; return a; } diff --git a/dbms/src/Interpreters/ExpressionActions.h b/dbms/src/Interpreters/ExpressionActions.h index 8da5fe2a279..eff2eccb264 100644 --- a/dbms/src/Interpreters/ExpressionActions.h +++ b/dbms/src/Interpreters/ExpressionActions.h @@ -85,6 +85,7 @@ public: /// For JOIN std::shared_ptr join; + Names join_key_names_left; NamesAndTypesList columns_added_by_join; /// For PROJECT. @@ -103,7 +104,8 @@ public: static ExpressionAction project(const NamesWithAliases & projected_columns_); static ExpressionAction project(const Names & projected_columns_); static ExpressionAction arrayJoin(const NameSet & array_joined_columns, bool array_join_is_left, const Context & context); - static ExpressionAction ordinaryJoin(std::shared_ptr join_, const NamesAndTypesList & columns_added_by_join_); + static ExpressionAction ordinaryJoin(std::shared_ptr join_, const Names & join_key_names_left, + const NamesAndTypesList & columns_added_by_join_); /// Which columns necessary to perform this action. Names getNeededColumns() const; diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 538d64f3e18..9f08fe3a9dc 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -2454,11 +2454,11 @@ bool ExpressionAnalyzer::appendArrayJoin(ExpressionActionsChain & chain, bool on void ExpressionAnalyzer::addJoinAction(ExpressionActionsPtr & actions, bool only_types) const { if (only_types) - actions->add(ExpressionAction::ordinaryJoin(nullptr, columns_added_by_join)); + actions->add(ExpressionAction::ordinaryJoin(nullptr, join_key_names_left, columns_added_by_join)); else for (auto & subquery_for_set : subqueries_for_sets) if (subquery_for_set.second.join) - actions->add(ExpressionAction::ordinaryJoin(subquery_for_set.second.join, columns_added_by_join)); + actions->add(ExpressionAction::ordinaryJoin(subquery_for_set.second.join, join_key_names_left, columns_added_by_join)); } bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_types) From 98e5821769f7c19bd9d99ccb68203cb3f4e4400e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 25 Jul 2018 19:11:20 +0300 Subject: [PATCH 191/425] Resolve qualified names for JOIN ON expression. [#CLICKHOUSE-3761] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 392 +++++++++++++------ dbms/src/Interpreters/ExpressionAnalyzer.h | 13 +- 2 files changed, 291 insertions(+), 114 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 9f08fe3a9dc..8301945162d 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -258,112 +258,144 @@ ExpressionAnalyzer::ExpressionAnalyzer( analyzeAggregation(); } - -void ExpressionAnalyzer::translateQualifiedNames() +static DatabaseAndTableWithAlias getTableNameWithAliasFromTableExpression(const ASTTableExpression & table_expression, + const Context & context) { - String database_name; - String table_name; - String alias; - - if (!select_query || !select_query->tables || select_query->tables->children.empty()) - return; - - ASTTablesInSelectQueryElement & element = static_cast(*select_query->tables->children[0]); - - if (!element.table_expression) /// This is ARRAY JOIN without a table at the left side. - return; - - ASTTableExpression & table_expression = static_cast(*element.table_expression); + DatabaseAndTableWithAlias database_and_table_with_alias; if (table_expression.database_and_table_name) { - const ASTIdentifier & identifier = static_cast(*table_expression.database_and_table_name); + const auto & identifier = static_cast(*table_expression.database_and_table_name); - alias = identifier.tryGetAlias(); + database_and_table_with_alias.alias = identifier.tryGetAlias(); if (table_expression.database_and_table_name->children.empty()) { - database_name = context.getCurrentDatabase(); - table_name = identifier.name; + database_and_table_with_alias.database_name = context.getCurrentDatabase(); + database_and_table_with_alias.table_name = identifier.name; } else { if (table_expression.database_and_table_name->children.size() != 2) throw Exception("Logical error: number of components in table expression not equal to two", ErrorCodes::LOGICAL_ERROR); - database_name = static_cast(*identifier.children[0]).name; - table_name = static_cast(*identifier.children[1]).name; + database_and_table_with_alias.database_name = static_cast(*identifier.children[0]).name; + database_and_table_with_alias.table_name = static_cast(*identifier.children[1]).name; } } else if (table_expression.table_function) { - alias = table_expression.table_function->tryGetAlias(); + database_and_table_with_alias.alias = table_expression.table_function->tryGetAlias(); } else if (table_expression.subquery) { - alias = table_expression.subquery->tryGetAlias(); + database_and_table_with_alias.alias = table_expression.subquery->tryGetAlias(); } else throw Exception("Logical error: no known elements in ASTTableExpression", ErrorCodes::LOGICAL_ERROR); - translateQualifiedNamesImpl(ast, database_name, table_name, alias); + return database_and_table_with_alias; +}; + + +void ExpressionAnalyzer::translateQualifiedNames() +{ + if (!select_query || !select_query->tables || select_query->tables->children.empty()) + return; + + auto & element = static_cast(*select_query->tables->children[0]); + + if (!element.table_expression) /// This is ARRAY JOIN without a table at the left side. + return; + + ASTTableExpression & table_expression = static_cast(*element.table_expression); + + auto database_and_table_with_alias = getTableNameWithAliasFromTableExpression(table_expression, context); + + translateQualifiedNamesImpl(ast, database_and_table_with_alias); } -void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const String & database_name, const String & table_name, const String & alias) +static size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTIdentifier & identifier, + const DatabaseAndTableWithAlias & names) { - if (ASTIdentifier * ident = typeid_cast(ast.get())) + size_t num_qualifiers_to_strip = 0; + + auto get_identifier_name = [](const ASTPtr & ast) { return static_cast(*ast).name; }; + + /// It is compound identifier + if (!identifier.children.empty()) { - if (ident->kind == ASTIdentifier::Column) + size_t num_components = identifier.children.size(); + + /// database.table.column + if (num_components >= 3 + && !names.database_name.empty() + && get_identifier_name(identifier.children[0]) == names.database_name + && get_identifier_name(identifier.children[1]) == names.table_name) { - /// It is compound identifier - if (!ast->children.empty()) + num_qualifiers_to_strip = 2; + } + + /// table.column or alias.column. If num_components > 2, it is like table.nested.column. + if (num_components >= 2 + && ((!names.table_name.empty() && get_identifier_name(identifier.children[0]) == names.table_name) + || (!names.alias.empty() && get_identifier_name(identifier.children[0]) == names.alias))) + { + num_qualifiers_to_strip = 1; + } + } + + return num_qualifiers_to_strip; +} + + +static void stripIdentifier(ASTPtr & ast, size_t num_qualifiers_to_strip) +{ + ASTIdentifier * identifier = typeid_cast(ast.get()); + + if (!identifier) + throw Exception("ASTIdentifier expected for stripIdentifier", ErrorCodes::LOGICAL_ERROR); + + if (num_qualifiers_to_strip) + { + size_t num_components = identifier->children.size(); + + /// plain column + if (num_components - num_qualifiers_to_strip == 1) + { + String node_alias = identifier->tryGetAlias(); + ast = identifier->children.back(); + if (!node_alias.empty()) + ast->setAlias(node_alias); + } + else + /// nested column + { + identifier->children.erase(identifier->children.begin(), identifier->children.begin() + num_qualifiers_to_strip); + String new_name; + for (const auto & child : identifier->children) { - size_t num_components = ast->children.size(); - size_t num_qualifiers_to_strip = 0; - - /// database.table.column - if (num_components >= 3 - && !database_name.empty() - && static_cast(*ast->children[0]).name == database_name - && static_cast(*ast->children[1]).name == table_name) - { - num_qualifiers_to_strip = 2; - } - - /// table.column or alias.column. If num_components > 2, it is like table.nested.column. - if (num_components >= 2 - && ((!table_name.empty() && static_cast(*ast->children[0]).name == table_name) - || (!alias.empty() && static_cast(*ast->children[0]).name == alias))) - { - num_qualifiers_to_strip = 1; - } - - if (num_qualifiers_to_strip) - { - /// plain column - if (num_components - num_qualifiers_to_strip == 1) - { - String node_alias = ast->tryGetAlias(); - ast = ast->children.back(); - if (!node_alias.empty()) - ast->setAlias(node_alias); - } - else - /// nested column - { - ident->children.erase(ident->children.begin(), ident->children.begin() + num_qualifiers_to_strip); - String new_name; - for (const auto & child : ident->children) - { - if (!new_name.empty()) - new_name += '.'; - new_name += static_cast(*child.get()).name; - } - ident->name = new_name; - } - } + if (!new_name.empty()) + new_name += '.'; + new_name += static_cast(*child.get()).name; } + identifier->name = new_name; + } + } +} + + +void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const DatabaseAndTableWithAlias & table_names) +{ + if (auto * identifier = typeid_cast(ast.get())) + { + if (identifier->kind == ASTIdentifier::Column) + { + size_t num_qualifiers_to_strip + = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, table_names); + + stripIdentifier(ast, num_qualifiers_to_strip); } } else if (typeid_cast(ast.get())) @@ -381,12 +413,12 @@ void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const String /// database.table.*, table.* or alias.* if ( (num_components == 2 - && !database_name.empty() - && static_cast(*ident->children[0]).name == database_name - && static_cast(*ident->children[1]).name == table_name) + && !table_names.database_name.empty() + && static_cast(*ident->children[0]).name == table_names.database_name + && static_cast(*ident->children[1]).name == table_names.table_name) || (num_components == 0 - && ((!table_name.empty() && ident->name == table_name) - || (!alias.empty() && ident->name == alias)))) + && ((!table_names.table_name.empty() && ident->name == table_names.table_name) + || (!table_names.alias.empty() && ident->name == table_names.alias)))) { /// Replace to plain asterisk. ast = std::make_shared(); @@ -400,7 +432,7 @@ void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const String if (!typeid_cast(child.get()) && !typeid_cast(child.get())) { - translateQualifiedNamesImpl(child, database_name, table_name, alias); + translateQualifiedNamesImpl(child, table_names); } } } @@ -2817,6 +2849,10 @@ void ExpressionAnalyzer::collectUsedColumns() collectJoinedColumns(available_joined_columns, columns_added_by_join); NameSet required_joined_columns; + + for (const auto & left_key_ast : join_key_asts_left) + getRequiredSourceColumnsImpl(left_key_ast, available_columns, required, ignored, {}, required_joined_columns); + getRequiredSourceColumnsImpl(ast, available_columns, required, ignored, available_joined_columns, required_joined_columns); for (NamesAndTypesList::iterator it = columns_added_by_join.begin(); it != columns_added_by_join.end();) @@ -2872,6 +2908,160 @@ void ExpressionAnalyzer::collectUsedColumns() throw Exception("Unknown identifier: " + *unknown_required_source_columns.begin(), ErrorCodes::UNKNOWN_IDENTIFIER); } + +void ExpressionAnalyzer::collectJoinedColumnsFromJoinOnExpr() +{ + const auto & tables = static_cast(*select_query->tables); + const auto * left_tables_element = static_cast(tables.children.at(0).get()); + const auto * right_tables_element = select_query->join(); + + if (!left_tables_element || !right_tables_element) + return; + + const auto & table_join = static_cast(*right_tables_element->table_join); + if (!table_join.on_expression) + return; + + const auto & left_table_expression = static_cast(*left_tables_element->table_expression); + const auto & right_table_expression = static_cast(*right_tables_element->table_expression); + + auto left_source_names = getTableNameWithAliasFromTableExpression(left_table_expression, context); + auto right_source_names = getTableNameWithAliasFromTableExpression(right_table_expression, context); + + /// Stores examples of columns which are only from one table. + struct TableBelonging + { + const ASTIdentifier * example_only_from_left = nullptr; + const ASTIdentifier * example_only_from_right = nullptr; + }; + + /// Check all identifiers in ast and decide their possible table belonging. + /// Throws if there are two identifiers definitely from different tables. + std::function get_table_belonging; + get_table_belonging = [&](const ASTPtr & ast) -> TableBelonging + { + auto * identifier = typeid_cast(ast.get()); + if (identifier) + { + if (identifier->kind == ASTIdentifier::Column) + { + auto left_num_components = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, left_source_names); + auto right_num_components = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, right_source_names); + if (left_num_components > right_num_components) + return {identifier, nullptr}; + if (left_num_components < right_num_components) + return {nullptr, identifier}; + } + return {}; + } + + TableBelonging table_belonging; + for (const auto & child : ast->children) + { + auto children_belonging = get_table_belonging(child); + if (!table_belonging.example_only_from_left) + table_belonging.example_only_from_left = children_belonging.example_only_from_left; + if (!table_belonging.example_only_from_right) + table_belonging.example_only_from_right = children_belonging.example_only_from_right; + } + + if (table_belonging.example_only_from_left && table_belonging.example_only_from_right) + throw Exception("Invalid columns in JOIN ON section. Columns " + + table_belonging.example_only_from_left->getAliasOrColumnName() + " and " + + table_belonging.example_only_from_right->getAliasOrColumnName() + + " are from different tables.", ErrorCodes::INVALID_JOIN_ON_EXPRESSION); + + return table_belonging; + }; + + std::function translate_qualified_names; + translate_qualified_names = [&](ASTPtr & ast, const DatabaseAndTableWithAlias & source_names) + { + auto * identifier = typeid_cast(ast.get()); + if (identifier) + { + if (identifier->kind == ASTIdentifier::Column) + { + auto num_components = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, source_names); + stripIdentifier(ast, num_components); + } + return; + } + + for (auto & child : ast->children) + translate_qualified_names(child, source_names); + }; + + const auto supported_syntax = " Supported syntax: JOIN ON Expr([table.]column, ...) = Expr([table.]column, ...) " + "[AND Expr([table.]column, ...) = Expr([table.]column, ...) ...]"; + auto throwSyntaxException = [&](const String & msg) + { + throw Exception("Invalid expression for JOIN ON. " + msg + supported_syntax, ErrorCodes::INVALID_JOIN_ON_EXPRESSION); + }; + + /// For equal expression find out corresponding table for each part, translate qualified names and add asts to join keys. + auto add_columns_from_equals_expr = [&](const ASTPtr & expr) + { + auto * func_equals = typeid_cast(expr.get()); + if (!func_equals || func_equals->name != "equals") + throwSyntaxException("Expected equals expression, got " + queryToString(expr) + "."); + + ASTPtr left_ast = func_equals->arguments->children.at(0)->clone(); + ASTPtr right_ast = func_equals->arguments->children.at(1)->clone(); + + auto left_table_belonging = get_table_belonging(left_ast); + auto right_table_belonging = get_table_belonging(right_ast); + + bool can_be_left_part_from_left_table = left_table_belonging.example_only_from_right == nullptr; + bool can_be_left_part_from_right_table = left_table_belonging.example_only_from_left == nullptr; + bool can_be_right_part_from_left_table = right_table_belonging.example_only_from_right == nullptr; + bool can_be_right_part_from_right_table = right_table_belonging.example_only_from_left == nullptr; + + auto add_join_keys = [&](ASTPtr & ast_to_left_table, ASTPtr & ast_to_right_table) + { + translate_qualified_names(ast_to_left_table, left_source_names); + translate_qualified_names(ast_to_right_table, right_source_names); + + join_key_asts_left.push_back(ast_to_left_table); + join_key_names_left.push_back(ast_to_left_table->getColumnName()); + join_key_asts_right.push_back(ast_to_right_table); + join_key_names_right.push_back(ast_to_right_table->getAliasOrColumnName()); + }; + + /// Default variant when all identifiers may be from any table. + if (can_be_left_part_from_left_table && can_be_right_part_from_right_table) + add_join_keys(left_ast, right_ast); + else if (can_be_left_part_from_right_table && can_be_right_part_from_left_table) + add_join_keys(right_ast, left_ast); + else + { + auto * left_example = left_table_belonging.example_only_from_left ? + left_table_belonging.example_only_from_left : + left_table_belonging.example_only_from_right; + + auto * right_example = right_table_belonging.example_only_from_left ? + right_table_belonging.example_only_from_left : + right_table_belonging.example_only_from_right; + + auto left_name = queryToString(*left_example); + auto right_name = queryToString(*right_example); + auto expr_name = queryToString(expr); + + throwSyntaxException("In expression " + expr_name + " columns " + left_name + " and " + right_name + + " are from the same table but from different arguments of equal function."); + } + }; + + auto * func = typeid_cast(table_join.on_expression.get()); + if (func && func->name == "and") + { + for (const auto & expr : func->arguments->children) + add_columns_from_equals_expr(expr); + } + else + add_columns_from_equals_expr(table_join.on_expression); +} + void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAndTypesList & joined_columns_name_type) { if (!select_query) @@ -2898,12 +3088,15 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd nested_result_sample = InterpreterSelectWithUnionQuery::getSampleBlock(subquery, context); } - auto add_name_to_join_keys = [](Names & join_keys, const String & name, const char * where) + auto add_name_to_join_keys = [](Names & join_keys, ASTs & join_asts, const String & name, const ASTPtr & ast) { if (join_keys.end() == std::find(join_keys.begin(), join_keys.end(), name)) + { join_keys.push_back(name); + join_asts.push_back(ast); + } else - throw Exception("Duplicate column " + name + " " + where, ErrorCodes::DUPLICATE_COLUMN); + throw Exception("Duplicate column " + name + " in USING list", ErrorCodes::DUPLICATE_COLUMN); }; if (table_join.using_expression_list) @@ -2911,40 +3104,12 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd auto & keys = typeid_cast(*table_join.using_expression_list); for (const auto & key : keys.children) { - add_name_to_join_keys(join_key_names_left, key->getColumnName(), "in USING list"); - add_name_to_join_keys(join_key_names_right, key->getAliasOrColumnName(), "in USING list"); + add_name_to_join_keys(join_key_names_left, join_key_asts_left, key->getColumnName(), key); + add_name_to_join_keys(join_key_names_right, join_key_asts_right, key->getAliasOrColumnName(), key); } } else if (table_join.on_expression) - { - const auto supported_syntax = - "\nSupported syntax: JOIN ON [table.]column = [table.]column [AND [table.]column = [table.]column ...]"; - auto throwSyntaxException = [&](const String & msg) - { - throw Exception("Invalid expression for JOIN ON. " + msg + supported_syntax, ErrorCodes::INVALID_JOIN_ON_EXPRESSION); - }; - - auto add_columns_from_equals_expr = [&](const ASTPtr & expr) - { - auto * func_equals = typeid_cast(expr.get()); - if (!func_equals || func_equals->name != "equals") - throwSyntaxException("Expected equals expression, got " + queryToString(expr)); - - String left_name = func_equals->arguments->children.at(0)->getAliasOrColumnName(); - String right_name = func_equals->arguments->children.at(1)->getAliasOrColumnName(); - add_name_to_join_keys(join_key_names_left, left_name, "in JOIN ON expression for left table"); - add_name_to_join_keys(join_key_names_right, right_name, "in JOIN ON expression for right table"); - }; - - auto * func = typeid_cast(table_join.on_expression.get()); - if (func && func->name == "and") - { - for (auto expr : func->arguments->children) - add_columns_from_equals_expr(expr); - } - else - add_columns_from_equals_expr(table_join.on_expression); - } + collectJoinedColumnsFromJoinOnExpr(); for (const auto i : ext::range(0, nested_result_sample.columns())) { @@ -3048,7 +3213,8 @@ void ExpressionAnalyzer::getRequiredSourceColumnsImpl(const ASTPtr & ast, */ if (!typeid_cast(child.get()) && !typeid_cast(child.get()) - && !typeid_cast(child.get())) + && !typeid_cast(child.get()) + && !typeid_cast(child.get())) getRequiredSourceColumnsImpl(child, available_columns, required_source_columns, ignored_names, available_joined_columns, required_joined_columns); } diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.h b/dbms/src/Interpreters/ExpressionAnalyzer.h index 74e782119e6..1798ac37f26 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.h +++ b/dbms/src/Interpreters/ExpressionAnalyzer.h @@ -87,6 +87,13 @@ struct ScopeStack const Block & getSampleBlock() const; }; +struct DatabaseAndTableWithAlias +{ + String database_name; + String table_name; + String alias; +}; + /** Transforms an expression from a syntax tree into a sequence of actions to execute it. * * NOTE: if `ast` is a SELECT query from a table, the structure of this table should not change during the lifetime of ExpressionAnalyzer. @@ -219,6 +226,8 @@ private: */ Names join_key_names_left; Names join_key_names_right; + ASTs join_key_asts_left; + ASTs join_key_asts_right; NamesAndTypesList columns_added_by_join; @@ -253,6 +262,8 @@ private: /** Find the columns that are obtained by JOIN. */ void collectJoinedColumns(NameSet & joined_columns, NamesAndTypesList & joined_columns_name_type); + /// Parse JOIN ON expression and collect ASTs for joined columns. + void collectJoinedColumnsFromJoinOnExpr(); /** Create a dictionary of aliases. */ @@ -358,7 +369,7 @@ private: * only one ("main") table is supported. Ambiguity is not detected or resolved. */ void translateQualifiedNames(); - void translateQualifiedNamesImpl(ASTPtr & node, const String & database_name, const String & table_name, const String & alias); + void translateQualifiedNamesImpl(ASTPtr & node, const DatabaseAndTableWithAlias & table_names); /** Sometimes we have to calculate more columns in SELECT clause than will be returned from query. * This is the case when we have DISTINCT or arrayJoin: we require more columns in SELECT even if we need less columns in result. From 11d66d8733a587664de9276363219cb28591b785 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 26 Jul 2018 14:12:07 +0300 Subject: [PATCH 192/425] Support expressions for right JOIN keys. [#CLICKHOUSE-3761] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 63 +++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 8301945162d..fad0c9e176f 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -708,7 +708,7 @@ static std::pair getDatabaseAndTableNameFromIdentifier(const AST static std::shared_ptr interpretSubquery( - const ASTPtr & subquery_or_table_name, const Context & context, size_t subquery_depth, const Names & required_source_columns) + const ASTPtr & subquery_or_table_name, const Context & context, size_t subquery_depth, const Names & required_source_columns, ASTPtr select_expression_list = nullptr) { /// Subquery or table name. The name of the table is similar to the subquery `SELECT * FROM t`. const ASTSubquery * subquery = typeid_cast(subquery_or_table_name.get()); @@ -744,20 +744,24 @@ static std::shared_ptr interpretSubquery( const auto select_query = std::make_shared(); select_with_union_query->list_of_selects->children.push_back(select_query); - const auto select_expression_list = std::make_shared(); - select_query->select_expression_list = select_expression_list; - select_query->children.emplace_back(select_query->select_expression_list); - - /// get columns list for target table auto database_table = getDatabaseAndTableNameFromIdentifier(*table); - const auto & storage = context.getTable(database_table.first, database_table.second); - const auto & columns = storage->getColumns().ordinary; - select_expression_list->children.reserve(columns.size()); - /// manually substitute column names in place of asterisk - for (const auto & column : columns) - select_expression_list->children.emplace_back(std::make_shared(column.name)); + if (!select_expression_list) + { + select_expression_list = std::make_shared(); + /// get columns list for target table + const auto & storage = context.getTable(database_table.first, database_table.second); + const auto & columns = storage->getColumns().ordinary; + select_expression_list->children.reserve(columns.size()); + + /// manually substitute column names in place of asterisk + for (const auto & column : columns) + select_expression_list->children.emplace_back(std::make_shared(column.name)); + } + + select_query->select_expression_list = std::move(select_expression_list); + select_query->children.emplace_back(select_query->select_expression_list); select_query->replaceDatabaseAndTable(database_table.first, database_table.second); } else @@ -2554,13 +2558,42 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty */ if (!subquery_for_set.source) { + ASTPtr select_expression_list; + ASTPtr table; if (table_to_join.database_and_table_name) + { table = table_to_join.database_and_table_name; - else - table = table_to_join.subquery; - auto interpreter = interpretSubquery(table, context, subquery_depth, required_joined_columns); + /// Create custom expression list with join keys from right table. + select_expression_list = std::make_shared(); + for (const auto & join_right_key : join_key_asts_right) + select_expression_list->children.emplace_back(join_right_key); + } + else + { + table = table_to_join.subquery->clone(); + + ASTSubquery * subquery = typeid_cast(table.get()); + if (!subquery) + throw Exception("Expected ASTSubquery as joined subquery.", ErrorCodes::LOGICAL_ERROR); + + const auto & query_ptr = subquery->children.at(0); + ASTSelectWithUnionQuery * select_with_union = typeid_cast(query_ptr.get()); + if (!select_with_union) + throw Exception("Expected ASTSelectWithUnionQuery as joined subquery.", ErrorCodes::LOGICAL_ERROR); + + const auto & first_select = select_with_union->list_of_selects->children.at(0); + ASTSelectQuery * select_query = typeid_cast(first_select.get()); + if (!select_query) + throw Exception("Expected ASTSelectQuery as joined subquery.", ErrorCodes::LOGICAL_ERROR); + + /// Append right join keys to subquery expression list. Duplicate expressions will be removed further. + for (auto & expr : join_key_asts_right) + select_query->select_expression_list->children.emplace_back(expr); + } + + auto interpreter = interpretSubquery(table, context, subquery_depth, required_joined_columns, select_expression_list); subquery_for_set.source = std::make_shared( interpreter->getSampleBlock(), [interpreter]() mutable { return interpreter->execute().in; }); From 65dcca22a22d497c7fb3cf9f515e4c7e21e7126a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 26 Jul 2018 15:58:23 +0300 Subject: [PATCH 193/425] Substitute aliases for required columns in ExpressionAnalyzer. [#CLICKHOUSE-3761] --- dbms/src/Core/Names.h | 1 + dbms/src/Interpreters/ExpressionAnalyzer.cpp | 46 +++++++++++++++++--- dbms/src/Interpreters/ExpressionAnalyzer.h | 9 ++-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/dbms/src/Core/Names.h b/dbms/src/Core/Names.h index 5c3384112ae..ff8252084ac 100644 --- a/dbms/src/Core/Names.h +++ b/dbms/src/Core/Names.h @@ -12,5 +12,6 @@ namespace DB using Names = std::vector; using NameSet = std::unordered_set; using NameToNameMap = std::unordered_map; +using NameToNameSetMap = std::unordered_map; } diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index fad0c9e176f..cf08137d679 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -62,6 +62,8 @@ #include #include #include +#include +#include namespace DB @@ -172,7 +174,7 @@ ExpressionAnalyzer::ExpressionAnalyzer( const SubqueriesForSets & subqueries_for_set_) : ast(ast_), context(context_), settings(context.getSettings()), subquery_depth(subquery_depth_), - source_columns(source_columns_), required_result_columns(required_result_columns_.begin(), required_result_columns_.end()), + source_columns(source_columns_), storage(storage_), do_global(do_global_), subqueries_for_sets(subqueries_for_set_) { @@ -217,6 +219,9 @@ ExpressionAnalyzer::ExpressionAnalyzer( /// Common subexpression elimination. Rewrite rules. normalizeTree(); + /// Substitute aliases for required_result_columns and create set with their names. + required_result_columns = createRequiredResultColumnsMap(required_result_columns_); + /// Remove unneeded columns according to 'required_result_columns'. /// Leave all selected columns in case of DISTINCT; columns that contain arrayJoin function inside. /// Must be after 'normalizeTree' (after expanding aliases, for aliases not get lost) @@ -971,6 +976,25 @@ void ExpressionAnalyzer::addASTAliases(ASTPtr & ast, int ignore_levels) } +NameToNameSetMap ExpressionAnalyzer::createRequiredResultColumnsMap(const Names & required_result_columns) +{ + NameToNameSetMap map; + ParserExpression parser; + + for (const auto & column : required_result_columns) + { + /// TODO: it's better to change type of required_result_columns to ASTs + auto expr = parseQuery(parser, column, 0); + SetOfASTs tmp_set; + MapOfASTs tmp_map; + normalizeTreeImpl(expr, tmp_map, tmp_set, "", 0); + map[expr->getColumnName()].insert(column); + } + + return map; +} + + void ExpressionAnalyzer::normalizeTree() { SetOfASTs tmp_set; @@ -2754,12 +2778,24 @@ void ExpressionAnalyzer::appendProjectResult(ExpressionActionsChain & chain) con ASTs asts = select_query->select_expression_list->children; for (size_t i = 0; i < asts.size(); ++i) { - String result_name = asts[i]->getAliasOrColumnName(); - if (required_result_columns.empty() || required_result_columns.count(result_name)) + String result_name = asts[i]->getColumnName(); + if (required_result_columns.empty()) { - result_columns.emplace_back(asts[i]->getColumnName(), result_name); + result_columns.emplace_back(result_name, asts[i]->getAliasOrColumnName()); step.required_output.push_back(result_columns.back().second); } + else + { + auto iter = required_result_columns.find(result_name); + if (iter != required_result_columns.end()) + { + for (const auto & original_name : iter->second) + { + result_columns.emplace_back(result_name, original_name); + step.required_output.push_back(result_columns.back().second); + } + } + } } step.actions->add(ExpressionAction::project(result_columns)); @@ -3280,7 +3316,7 @@ void ExpressionAnalyzer::removeUnneededColumnsFromSelectClause() elements.erase(std::remove_if(elements.begin(), elements.end(), [this](const auto & node) { - return !required_result_columns.count(node->getAliasOrColumnName()) && !hasArrayJoin(node); + return !required_result_columns.count(node->getColumnName()) && !hasArrayJoin(node); }), elements.end()); } diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.h b/dbms/src/Interpreters/ExpressionAnalyzer.h index 1798ac37f26..1375c65baf1 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.h +++ b/dbms/src/Interpreters/ExpressionAnalyzer.h @@ -192,9 +192,9 @@ private: */ NamesAndTypesList source_columns; - /** If non-empty, ignore all expressions in not from this list. - */ - NameSet required_result_columns; + /// If non-empty, ignore all expressions in not from this list. + /// Map columns with substituted aliases to original names. + NameToNameSetMap required_result_columns; /// Columns after ARRAY JOIN, JOIN, and/or aggregation. NamesAndTypesList aggregated_columns; @@ -275,6 +275,9 @@ private: void normalizeTree(); void normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias, size_t level); + /// Substitute aliases for required_result_columns and create map with their new to original names. + NameToNameSetMap createRequiredResultColumnsMap(const Names & required_result_columns); + /// Eliminates injective function calls and constant expressions from group by statement void optimizeGroupBy(); From 5123e0f86f2dc4d48def600730888a74cc26d507 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 26 Jul 2018 18:11:53 +0300 Subject: [PATCH 194/425] Remove joined table qualifiers from column names. [#CLICKHOUSE-3761] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 205 +++++++++++++------ dbms/src/Interpreters/ExpressionAnalyzer.h | 13 +- 2 files changed, 150 insertions(+), 68 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index cf08137d679..31a6a566ae8 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -163,6 +163,34 @@ void removeDuplicateColumns(NamesAndTypesList & columns) } +String DatabaseAndTableWithAlias::getQualifiedNamePrefix() const +{ + return (!alias.empty() ? alias : (database + '.' + table)) + '.'; +} + + +void DatabaseAndTableWithAlias::makeQualifiedName(const ASTPtr & ast) const +{ + if (auto identifier = typeid_cast(ast.get())) + { + String prefix = getQualifiedNamePrefix(); + identifier->name.insert(identifier->name.begin(), prefix.begin(), prefix.end()); + + Names qualifiers; + if (!alias.empty()) + qualifiers.push_back(alias); + else + { + qualifiers.push_back(database); + qualifiers.push_back(table); + } + + for (const auto & qualifier : qualifiers) + identifier->children.emplace_back(std::make_shared(qualifier)); + } +} + + ExpressionAnalyzer::ExpressionAnalyzer( const ASTPtr & ast_, const Context & context_, @@ -276,16 +304,16 @@ static DatabaseAndTableWithAlias getTableNameWithAliasFromTableExpression(const if (table_expression.database_and_table_name->children.empty()) { - database_and_table_with_alias.database_name = context.getCurrentDatabase(); - database_and_table_with_alias.table_name = identifier.name; + database_and_table_with_alias.database = context.getCurrentDatabase(); + database_and_table_with_alias.table = identifier.name; } else { if (table_expression.database_and_table_name->children.size() != 2) throw Exception("Logical error: number of components in table expression not equal to two", ErrorCodes::LOGICAL_ERROR); - database_and_table_with_alias.database_name = static_cast(*identifier.children[0]).name; - database_and_table_with_alias.table_name = static_cast(*identifier.children[1]).name; + database_and_table_with_alias.database = static_cast(*identifier.children[0]).name; + database_and_table_with_alias.table = static_cast(*identifier.children[1]).name; } } else if (table_expression.table_function) @@ -313,11 +341,18 @@ void ExpressionAnalyzer::translateQualifiedNames() if (!element.table_expression) /// This is ARRAY JOIN without a table at the left side. return; - ASTTableExpression & table_expression = static_cast(*element.table_expression); + auto & table_expression = static_cast(*element.table_expression); + auto * join = select_query->join(); - auto database_and_table_with_alias = getTableNameWithAliasFromTableExpression(table_expression, context); + std::vector tables = {getTableNameWithAliasFromTableExpression(table_expression, context)}; - translateQualifiedNamesImpl(ast, database_and_table_with_alias); + if (join) + { + const auto & join_table_expression = static_cast(*join->table_expression); + tables.emplace_back(getTableNameWithAliasFromTableExpression(join_table_expression, context)); + } + + translateQualifiedNamesImpl(ast, tables); } @@ -335,16 +370,16 @@ static size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTId /// database.table.column if (num_components >= 3 - && !names.database_name.empty() - && get_identifier_name(identifier.children[0]) == names.database_name - && get_identifier_name(identifier.children[1]) == names.table_name) + && !names.database.empty() + && get_identifier_name(identifier.children[0]) == names.database + && get_identifier_name(identifier.children[1]) == names.table) { num_qualifiers_to_strip = 2; } /// table.column or alias.column. If num_components > 2, it is like table.nested.column. if (num_components >= 2 - && ((!names.table_name.empty() && get_identifier_name(identifier.children[0]) == names.table_name) + && ((!names.table.empty() && get_identifier_name(identifier.children[0]) == names.table) || (!names.alias.empty() && get_identifier_name(identifier.children[0]) == names.alias))) { num_qualifiers_to_strip = 1; @@ -391,16 +426,36 @@ static void stripIdentifier(ASTPtr & ast, size_t num_qualifiers_to_strip) } -void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const DatabaseAndTableWithAlias & table_names) +void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const std::vector & tables) { if (auto * identifier = typeid_cast(ast.get())) { if (identifier->kind == ASTIdentifier::Column) { - size_t num_qualifiers_to_strip - = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, table_names); + /// Select first table name with max number of qualifiers which can be stripped. + size_t max_num_qualifiers_to_strip = 0; + size_t best_table_pos = 0; - stripIdentifier(ast, num_qualifiers_to_strip); + for (size_t table_pos = 0; table_pos < tables.size(); ++table_pos) + { + const auto & table = tables[table_pos]; + auto num_qualifiers_to_strip = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, table); + + if (num_qualifiers_to_strip > max_num_qualifiers_to_strip) + { + max_num_qualifiers_to_strip = num_qualifiers_to_strip; + best_table_pos = table_pos; + } + } + + stripIdentifier(ast, max_num_qualifiers_to_strip); + + /// In case if column from the joined table are in source columns, change it's name to qualified. + if (best_table_pos && source_columns.contains(ast->getColumnName())) + { + duplicate_columns_from_joined_table.insert(ast->getColumnName()); + tables[best_table_pos].makeQualifiedName(ast); + } } } else if (typeid_cast(ast.get())) @@ -416,19 +471,28 @@ void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const Databas if (num_components > 2) throw Exception("Qualified asterisk cannot have more than two qualifiers", ErrorCodes::UNKNOWN_ELEMENT_IN_AST); - /// database.table.*, table.* or alias.* - if ( (num_components == 2 - && !table_names.database_name.empty() - && static_cast(*ident->children[0]).name == table_names.database_name - && static_cast(*ident->children[1]).name == table_names.table_name) - || (num_components == 0 - && ((!table_names.table_name.empty() && ident->name == table_names.table_name) - || (!table_names.alias.empty() && ident->name == table_names.alias)))) + for (const auto & table_names : tables) { - /// Replace to plain asterisk. - ast = std::make_shared(); + /// database.table.*, table.* or alias.* + if ((num_components == 2 + && !table_names.database.empty() + && static_cast(*ident->children[0]).name == table_names.database + && static_cast(*ident->children[1]).name == table_names.table) + || (num_components == 0 + && ((!table_names.table.empty() && ident->name == table_names.table) + || (!table_names.alias.empty() && ident->name == table_names.alias)))) + { + /// Replace to plain asterisk. + ast = std::make_shared(); + } } } + else if (auto * join = typeid_cast(ast.get())) + { + /// Don't translate on_expression hear in order to resolve equasions parts later. + if (join->using_expression_list) + translateQualifiedNamesImpl(join->using_expression_list, tables); + } else { for (auto & child : ast->children) @@ -437,7 +501,7 @@ void ExpressionAnalyzer::translateQualifiedNamesImpl(ASTPtr & ast, const Databas if (!typeid_cast(child.get()) && !typeid_cast(child.get())) { - translateQualifiedNamesImpl(child, table_names); + translateQualifiedNamesImpl(child, tables); } } } @@ -2057,28 +2121,8 @@ void ExpressionAnalyzer::getActionsFromJoinKeys(const ASTTableJoin & table_join, getActionsImpl(table_join.using_expression_list, no_subqueries, only_consts, scopes, projection_manipulator); else if (table_join.on_expression) { - std::function get_actions; - get_actions = [&](const ASTPtr & ast) - { - bool key_expr = false; - - if (const auto * ast_function = typeid_cast(ast.get())) - { - auto column_name = ast_function->getColumnName(); - key_expr = join_key_names_left.end() - != std::find(join_key_names_left.begin(), join_key_names_left.end(), column_name); - } - - if (key_expr) - getActionsImpl(ast, no_subqueries, only_consts, scopes, projection_manipulator); - else - { - for (auto & child : ast->children) - get_actions(child); - } - }; - - get_actions(table_join.on_expression); + for (const auto & ast : join_key_asts_left) + getActionsImpl(ast, no_subqueries, only_consts, scopes, projection_manipulator); } actions = scopes.popLevel(); @@ -2531,9 +2575,10 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty initChain(chain, source_columns); ExpressionActionsChain::Step & step = chain.steps.back(); - const ASTTablesInSelectQueryElement & join_element = static_cast(*select_query->join()); - const ASTTableJoin & join_params = static_cast(*join_element.table_join); - const ASTTableExpression & table_to_join = static_cast(*join_element.table_expression); + const auto & join_element = static_cast(*select_query->join()); + const auto & join_params = static_cast(*join_element.table_join); + const auto & table_to_join = static_cast(*join_element.table_expression); + const auto joined_table_name = getTableNameWithAliasFromTableExpression(table_to_join, context); getActionsFromJoinKeys(join_params, only_types, false, step.actions); @@ -2546,8 +2591,7 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty /// TODO This syntax does not support specifying a database name. if (table_to_join.database_and_table_name) { - auto database_table = getDatabaseAndTableNameFromIdentifier(static_cast(*table_to_join.database_and_table_name)); - StoragePtr table = context.tryGetTable(database_table.first, database_table.second); + StoragePtr table = context.tryGetTable(joined_table_name.database, joined_table_name.table); if (table) { @@ -2584,6 +2628,16 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty { ASTPtr select_expression_list; + auto add_aliases_to_duplicating_joined_columns = [&](const ASTPtr & expression_list) + { + for (const auto & name : duplicate_columns_from_joined_table) + { + auto identifier = std::make_shared(name); + identifier->setAlias(joined_table_name.getQualifiedNamePrefix() + name); + expression_list->children.emplace_back(std::move(identifier)); + } + }; + ASTPtr table; if (table_to_join.database_and_table_name) { @@ -2593,28 +2647,37 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty select_expression_list = std::make_shared(); for (const auto & join_right_key : join_key_asts_right) select_expression_list->children.emplace_back(join_right_key); + + for (const auto & column : columns_added_by_join) + if (join_key_names_right.end() == std::find(join_key_names_right.begin(), + join_key_names_right.end(), column.name)) + select_expression_list->children.emplace_back(std::make_shared(column.name)); + + add_aliases_to_duplicating_joined_columns(select_expression_list); } else { table = table_to_join.subquery->clone(); - ASTSubquery * subquery = typeid_cast(table.get()); + auto * subquery = typeid_cast(table.get()); if (!subquery) throw Exception("Expected ASTSubquery as joined subquery.", ErrorCodes::LOGICAL_ERROR); const auto & query_ptr = subquery->children.at(0); - ASTSelectWithUnionQuery * select_with_union = typeid_cast(query_ptr.get()); + auto * select_with_union = typeid_cast(query_ptr.get()); if (!select_with_union) throw Exception("Expected ASTSelectWithUnionQuery as joined subquery.", ErrorCodes::LOGICAL_ERROR); const auto & first_select = select_with_union->list_of_selects->children.at(0); - ASTSelectQuery * select_query = typeid_cast(first_select.get()); + auto * select_query = typeid_cast(first_select.get()); if (!select_query) throw Exception("Expected ASTSelectQuery as joined subquery.", ErrorCodes::LOGICAL_ERROR); /// Append right join keys to subquery expression list. Duplicate expressions will be removed further. for (auto & expr : join_key_asts_right) select_query->select_expression_list->children.emplace_back(expr); + + add_aliases_to_duplicating_joined_columns(select_query->select_expression_list); } auto interpreter = interpretSubquery(table, context, subquery_depth, required_joined_columns, select_expression_list); @@ -3141,14 +3204,14 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd if (!node) return; - const ASTTableJoin & table_join = static_cast(*node->table_join); - const ASTTableExpression & table_expression = static_cast(*node->table_expression); + const auto & table_join = static_cast(*node->table_join); + const auto & table_expression = static_cast(*node->table_expression); + auto joined_table_name = getTableNameWithAliasFromTableExpression(table_expression, context); Block nested_result_sample; if (table_expression.database_and_table_name) { - auto database_table = getDatabaseAndTableNameFromIdentifier(static_cast(*table_expression.database_and_table_name)); - const auto & table = context.getTable(database_table.first, database_table.second); + const auto & table = context.getTable(joined_table_name.database, joined_table_name.table); nested_result_sample = table->getSampleBlockNonMaterialized(); } else if (table_expression.subquery) @@ -3180,16 +3243,28 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAnd else if (table_join.on_expression) collectJoinedColumnsFromJoinOnExpr(); + for (const auto i : ext::range(0, nested_result_sample.columns())) { const auto & col = nested_result_sample.safeGetByPosition(i); - if (join_key_names_left.end() == std::find(join_key_names_left.begin(), join_key_names_left.end(), col.name) - && !joined_columns.count(col.name)) /// Duplicate columns in the subquery for JOIN do not make sense. + if (join_key_names_left.end() == std::find(join_key_names_left.begin(), join_key_names_left.end(), col.name)) { - joined_columns.insert(col.name); + auto name = col.name; + /// Change name for duplicate column form joined table. + if (source_columns.contains(name)) + { + duplicate_columns_from_joined_table.insert(name); + name = joined_table_name.getQualifiedNamePrefix() + name; + } - bool make_nullable = settings.join_use_nulls && (table_join.kind == ASTTableJoin::Kind::Left || table_join.kind == ASTTableJoin::Kind::Full); - joined_columns_name_type.emplace_back(col.name, make_nullable ? makeNullable(col.type) : col.type); + if (joined_columns.count(name)) /// Duplicate columns in the subquery for JOIN do not make sense. + continue; + + joined_columns.insert(name); + + bool make_nullable = settings.join_use_nulls && (table_join.kind == ASTTableJoin::Kind::Left || + table_join.kind == ASTTableJoin::Kind::Full); + joined_columns_name_type.emplace_back(name, make_nullable ? makeNullable(col.type) : col.type); } } } diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.h b/dbms/src/Interpreters/ExpressionAnalyzer.h index 1375c65baf1..e2868911ca1 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.h +++ b/dbms/src/Interpreters/ExpressionAnalyzer.h @@ -89,9 +89,15 @@ struct ScopeStack struct DatabaseAndTableWithAlias { - String database_name; - String table_name; + String database; + String table; String alias; + + /// "alias." or "database.table." if alias is empty + String getQualifiedNamePrefix() const; + + /// If ast is ASTIdentifier, prepend getQualifiedNamePrefix() to it's name. + void makeQualifiedName(const ASTPtr & ast) const; }; /** Transforms an expression from a syntax tree into a sequence of actions to execute it. @@ -228,6 +234,7 @@ private: Names join_key_names_right; ASTs join_key_asts_left; ASTs join_key_asts_right; + NameSet duplicate_columns_from_joined_table; NamesAndTypesList columns_added_by_join; @@ -372,7 +379,7 @@ private: * only one ("main") table is supported. Ambiguity is not detected or resolved. */ void translateQualifiedNames(); - void translateQualifiedNamesImpl(ASTPtr & node, const DatabaseAndTableWithAlias & table_names); + void translateQualifiedNamesImpl(ASTPtr & node, const std::vector & tables); /** Sometimes we have to calculate more columns in SELECT clause than will be returned from query. * This is the case when we have DISTINCT or arrayJoin: we require more columns in SELECT even if we need less columns in result. From a2cd7016e5d03ca1636b0623b0b8cf290a41c23b Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 27 Jul 2018 18:54:05 +0300 Subject: [PATCH 195/425] Added test for join on syntax. [#CLICKHOUSE-3761] --- .../00674_join_on_syntax.reference | 53 ++++++++++++ .../0_stateless/00674_join_on_syntax.sql | 84 +++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00674_join_on_syntax.reference create mode 100644 dbms/tests/queries/0_stateless/00674_join_on_syntax.sql diff --git a/dbms/tests/queries/0_stateless/00674_join_on_syntax.reference b/dbms/tests/queries/0_stateless/00674_join_on_syntax.reference new file mode 100644 index 00000000000..7a41a90c03f --- /dev/null +++ b/dbms/tests/queries/0_stateless/00674_join_on_syntax.reference @@ -0,0 +1,53 @@ +joind columns from right table +1 +1 2 +1 2 +1 3 +1 2 3 +join on expression +2 +2 2 +2 3 +1 +2 +1 2 2 3 +1 2 2 3 3 +1 2 2 3 +join on and chain +2 3 +2 3 +2 3 2 3 +1 +1 3 +1 2 2 3 +2 4 +join on aliases +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +1 2 2 3 +join on complex expression +2 3 +2 3 +2 3 +2 3 +2 3 +duplicate column names +{"a1":1,"test.tab1_copy.a1":2} +{"a1":1,"test.tab1_copy.a1":2} +{"a1":1,"copy.a1":2} +{"a1":1,"copy.a1":2} +{"a1":1,"copy.a1":2} diff --git a/dbms/tests/queries/0_stateless/00674_join_on_syntax.sql b/dbms/tests/queries/0_stateless/00674_join_on_syntax.sql new file mode 100644 index 00000000000..7fb60e64d04 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00674_join_on_syntax.sql @@ -0,0 +1,84 @@ +drop table if exists test.tab1; +drop table if exists test.tab2; +drop table if exists test.tab3; +drop table if exists test.tab1_copy; + +create table test.tab1 (a1 Int32, b1 Int32) engine = MergeTree order by a1; +create table test.tab2 (a2 Int32, b2 Int32) engine = MergeTree order by a2; +create table test.tab3 (a3 Int32, b3 Int32) engine = MergeTree order by a3; +create table test.tab1_copy (a1 Int32, b1 Int32) engine = MergeTree order by a1; + +insert into test.tab1 values (1, 2); +insert into test.tab2 values (2, 3); +insert into test.tab3 values (2, 3); +insert into test.tab1_copy values (2, 3); + + +select 'joind columns from right table'; +select a1 from test.tab1 any left join test.tab2 on b1 = a2; +select a1, b1 from test.tab1 any left join test.tab2 on b1 = a2; +select a1, a2 from test.tab1 any left join test.tab2 on b1 = a2; +select a1, b2 from test.tab1 any left join test.tab2 on b1 = a2; +select a1, a2, b2 from test.tab1 any left join test.tab2 on b1 = a2; + + +select 'join on expression'; +select b1 from test.tab1 any left join test.tab2 on toInt32(a1 + 1) = a2; +select b1, a2 from test.tab1 any left join test.tab2 on toInt32(a1 + 1) = a2; +select b1, b2 from test.tab1 any left join test.tab2 on toInt32(a1 + 1) = a2; +select a1 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1; +select a2 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1; +select a1, b1, a2, b2 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1; +select a1, b1, a2, b2, a2 + 1 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1; +select a1, b1, a2, b2 from test.tab1 any left join test.tab2 on a1 + 4 = b2 + 2; + + +select 'join on and chain'; +select a2, b2 from test.tab2 any left join test.tab3 on a2 = a3 and b2 = b3; +select a3, b3 from test.tab2 any left join test.tab3 on a2 = a3 and b2 = b3; +select a2, b2, a3, b3 from test.tab2 any left join test.tab3 on a2 = a3 and b2 = b3; +select a1 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1 and a1 + 4 = b2 + 2; +select a1, b2 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1 and a1 + 4 = b2 + 2; +select a1, b1, a2, b2 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1 and a1 + 4 = b2 + 2; +select a2, b2 + 1 from test.tab1 any left join test.tab2 on b1 + 1 = a2 + 1 and a1 + 4 = b2 + 2; + + +select 'join on aliases'; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on first.b1 = second.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on second.a2 = first.b1; + +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on tab1.b1 = tab2.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on tab2.a2 = tab1.b1; + +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on test.tab1.b1 = test.tab2.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on test.tab2.a2 = test.tab1.b1; + +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on first.b1 = tab2.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on tab2.a2 = first.b1; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on first.b1 = test.tab2.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on test.tab2.a2 = first.b1; + +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on tab1.b1 = second.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on second.a2 = tab1.b1; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on test.tab1.b1 = second.a2; +select a1, a2, b1, b2 from test.tab1 first any left join test.tab2 second on second.a2 = test.tab1.b1; + +select a1, a2, first.b1, second.b2 from test.tab1 first any left join test.tab2 second on b1 = a2; +select a1, a2, tab1.b1, tab2.b2 from test.tab1 first any left join test.tab2 second on b1 = a2; +select a1, a2, test.tab1.b1, test.tab2.b2 from test.tab1 first any left join test.tab2 second on b1 = a2; + + +select 'join on complex expression'; +select a2, b2 from test.tab2 any left join test.tab3 on a2 + b2 = a3 + b3; +select a2, b2 from test.tab2 any left join test.tab3 on a3 + tab3.b3 = a2 + b2; +select a2, b2 from test.tab2 second any left join test.tab3 on a3 + b3 = a2 + second.b2; +select a2, b2 from test.tab2 second any left join test.tab3 third on third.a3 + tab3.b3 = tab2.a2 + second.b2; +select a2, b2 from test.tab2 second any left join test.tab3 third on third.a3 + test.tab3.b3 = test.tab2.a2 + second.b2; + +select 'duplicate column names'; +select a1, tab1_copy.a1 from test.tab1 any left join test.tab1_copy on tab1.b1 + 3 = b1 + 2 FORMAT JSONEachRow; +select a1, test.tab1_copy.a1 from test.tab1 any left join test.tab1_copy on tab1.b1 + 3 = b1 + 2 FORMAT JSONEachRow; +select a1, copy.a1 from test.tab1 any left join test.tab1_copy copy on tab1.b1 + 3 = b1 + 2 FORMAT JSONEachRow; +select a1, tab1_copy.a1 from test.tab1 any left join test.tab1_copy copy on tab1.b1 + 3 = b1 + 2 FORMAT JSONEachRow; +select a1, test.tab1_copy.a1 from test.tab1 any left join test.tab1_copy copy on tab1.b1 + 3 = b1 + 2 FORMAT JSONEachRow; + From 7d9ebae2c2b095429f18b115a5165c11986ef91a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Fri, 27 Jul 2018 20:11:56 +0300 Subject: [PATCH 196/425] Better comments. --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 9 ++++++++- dbms/src/Interpreters/ExpressionAnalyzer.h | 2 +- dbms/src/Interpreters/Join.cpp | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index b23160f133f..2ec3da9d6ba 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -357,6 +357,7 @@ void ExpressionAnalyzer::translateQualifiedNames() } +/// Get the number of components of identifier which are correspond to 'alias.', 'table.' or 'databas.table.' from names. static size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & names) { @@ -391,6 +392,8 @@ static size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTId } +/// Checks that ast is ASTIdentifier and remove num_qualifiers_to_strip components from left. +/// Example: 'database.table.name' -> (num_qualifiers_to_strip = 2) -> 'name'. static void stripIdentifier(ASTPtr & ast, size_t num_qualifiers_to_strip) { ASTIdentifier * identifier = typeid_cast(ast.get()); @@ -777,8 +780,10 @@ static std::pair getDatabaseAndTableNameFromIdentifier(const AST } +/// If ast is ordinary table and select_expression_list is not nullptr will use it instead of list of all columns. static std::shared_ptr interpretSubquery( - const ASTPtr & subquery_or_table_name, const Context & context, size_t subquery_depth, const Names & required_source_columns, ASTPtr select_expression_list = nullptr) + const ASTPtr & subquery_or_table_name, const Context & context, size_t subquery_depth, + const Names & required_source_columns, ASTPtr select_expression_list = nullptr) { /// Subquery or table name. The name of the table is similar to the subquery `SELECT * FROM t`. const ASTSubquery * subquery = typeid_cast(subquery_or_table_name.get()); @@ -3080,6 +3085,8 @@ void ExpressionAnalyzer::collectJoinedColumnsFromJoinOnExpr() { auto left_num_components = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, left_source_names); auto right_num_components = getNumComponentsToStripInOrderToTranslateQualifiedName(*identifier, right_source_names); + + /// Assume that component from definite table if num_components is greater than for the other table. if (left_num_components > right_num_components) return {identifier, nullptr}; if (left_num_components < right_num_components) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.h b/dbms/src/Interpreters/ExpressionAnalyzer.h index e2868911ca1..2dc313216c7 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.h +++ b/dbms/src/Interpreters/ExpressionAnalyzer.h @@ -198,7 +198,7 @@ private: */ NamesAndTypesList source_columns; - /// If non-empty, ignore all expressions in not from this list. + /// If non-empty, ignore all expressions in not from this map keys. /// Map columns with substituted aliases to original names. NameToNameSetMap required_result_columns; diff --git a/dbms/src/Interpreters/Join.cpp b/dbms/src/Interpreters/Join.cpp index 0694d58e0e6..7454c374fa6 100644 --- a/dbms/src/Interpreters/Join.cpp +++ b/dbms/src/Interpreters/Join.cpp @@ -777,7 +777,7 @@ void Join::joinBlockImpl(Block & block, const Maps & maps) const for (size_t i = 0; i < existing_columns; ++i) block.safeGetByPosition(i).column = block.safeGetByPosition(i).column->replicate(*offsets_to_replicate); - /// Add columns from right block. + /// Add join key columns from right block if they has different name. for (size_t i = 0; i < key_names_right.size(); ++i) { auto & right_name = key_names_right[i]; From 6283c3f572bc46493ccef2d01f15914c3121bb15 Mon Sep 17 00:00:00 2001 From: chertus Date: Fri, 27 Jul 2018 20:19:22 +0300 Subject: [PATCH 197/425] CLICKHOUSE-2: support negative tests --- dbms/programs/client/Client.cpp | 126 +++++++++++++++++- dbms/tests/clickhouse-test | 2 +- dbms/tests/integration/helpers/client.py | 2 +- .../0_stateless/00002_system_numbers.sql | 13 +- .../queries/0_stateless/00007_array.reference | 2 + .../tests/queries/0_stateless/00007_array.sql | 4 +- 6 files changed, 140 insertions(+), 9 deletions(-) diff --git a/dbms/programs/client/Client.cpp b/dbms/programs/client/Client.cpp index eb7673c947b..f8072cc4695 100644 --- a/dbms/programs/client/Client.cpp +++ b/dbms/programs/client/Client.cpp @@ -89,6 +89,95 @@ namespace ErrorCodes } +/// Checks expected server and client error codes in testmode. +/// To enable it add special comment after the query: "-- { serverError 60 }" or "-- { clientError 20 }". +class TestHint +{ +public: + TestHint(bool enabled_, const String & query) + : enabled(enabled_), + server_error(0), + client_error(0) + { + if (!enabled_) + return; + + size_t pos = query.find("--"); + if (pos != String::npos && query.find("--", pos + 2) != String::npos) + return; /// It's not last comment. Hint belongs to commented query. + + if (pos != String::npos) + { + pos = query.find('{', pos + 2); + if (pos != String::npos) + { + String hint = query.substr(pos + 1); + pos = hint.find('}'); + hint.resize(pos); + parse(hint); + } + } + } + + void checkActual(int actual_server_error, int actual_client_error, + bool & got_exception, std::unique_ptr & last_exception) const + { + if (!enabled) + return; + + if (allErrorsExpected(actual_server_error, actual_client_error)) + { + got_exception = false; + last_exception.reset(); + } + + if (lostExpectedError(actual_server_error, actual_client_error)) + { + std::cerr << "Success when error expected. It expects server error " + << server_error << ", client error " << client_error << "." << std::endl; + got_exception = true; + } + } + + int serverError() const { return server_error; } + int clientError() const { return client_error; } + +private: + bool enabled; + int server_error; + int client_error; + + void parse(const String & hint) + { + std::stringstream ss; + ss << hint; + while (!ss.eof()) + { + String item; + ss >> item; + if (item.empty()) + break; + + if (item == "serverError") + ss >> server_error; + else if (item == "clientError") + ss >> client_error; + } + } + + bool allErrorsExpected(int actual_server_error, int actual_client_error) const + { + return (server_error == actual_server_error) && (client_error == actual_client_error); + } + + bool lostExpectedError(int actual_server_error, int actual_client_error) const + { + return (server_error && !actual_server_error) || (client_error && !actual_client_error); + } +}; + + +/// class Client : public Poco::Util::Application { public: @@ -157,6 +246,10 @@ private: /// If the last query resulted in exception. bool got_exception = false; + int expected_server_error = 0; + int expected_client_error = 0; + int actual_server_error = 0; + int actual_client_error = 0; String server_version; String server_display_name; @@ -617,10 +710,14 @@ private: } catch (const Exception & e) { - std::cerr << std::endl - << "Exception on client:" << std::endl - << "Code: " << e.code() << ". " << e.displayText() << std::endl - << std::endl; + actual_client_error = e.code(); + if (!actual_client_error || actual_client_error != expected_client_error) + { + std::cerr << std::endl + << "Exception on client:" << std::endl + << "Code: " << e.code() << ". " << e.displayText() << std::endl + << std::endl; + } /// Client-side exception during query execution can result in the loss of /// sync in the connection protocol. @@ -659,6 +756,7 @@ private: bool process(const String & text) { const auto ignore_error = config().getBool("ignore-error", false); + const bool test_mode = config().has("testmode"); if (config().has("multiquery")) { /// Several queries separated by ';'. @@ -702,6 +800,10 @@ private: while (isWhitespaceASCII(*begin) || *begin == ';') ++begin; + TestHint test_hint(test_mode, query); + expected_client_error = test_hint.clientError(); + expected_server_error = test_hint.serverError(); + try { if (!processSingleQuery(query, ast) && !ignore_error) @@ -709,10 +811,13 @@ private: } catch (...) { + actual_client_error = getCurrentExceptionCode(); std::cerr << "Error on processing query: " << query << std::endl << getCurrentExceptionMessage(true); got_exception = true; } + test_hint.checkActual(actual_server_error, actual_client_error, got_exception, last_exception); + if (got_exception && !ignore_error) { if (is_interactive) @@ -1286,6 +1391,14 @@ private: resetOutput(); got_exception = true; + actual_server_error = e.code(); + if (expected_server_error) + { + if (actual_server_error == expected_server_error) + return; + std::cerr << "Expected error code: " << expected_server_error << " but got: " << actual_server_error << "." << std::endl; + } + std::string text = e.displayText(); auto embedded_stack_trace_pos = text.find("Stack trace"); @@ -1411,7 +1524,8 @@ public: ("pager", boost::program_options::value(), "pager") ("multiline,m", "multiline") ("multiquery,n", "multiquery") - ("ignore-error", "Do not stop processing in multiquery mode") + ("testmode,T", "enable test hints in comments") + ("ignore-error", "do not stop processing in multiquery mode") ("format,f", boost::program_options::value(), "default output format") ("vertical,E", "vertical output format, same as --format=Vertical or FORMAT Vertical or \\G at end of command") ("time,t", "print query execution time to stderr in non-interactive mode (for benchmarks)") @@ -1517,6 +1631,8 @@ public: config().setBool("multiline", true); if (options.count("multiquery")) config().setBool("multiquery", true); + if (options.count("testmode")) + config().setBool("testmode", true); if (options.count("ignore-error")) config().setBool("ignore-error", true); if (options.count("format")) diff --git a/dbms/tests/clickhouse-test b/dbms/tests/clickhouse-test index f734b784f9b..403078c581b 100755 --- a/dbms/tests/clickhouse-test +++ b/dbms/tests/clickhouse-test @@ -195,7 +195,7 @@ def main(args): stderr_file = os.path.join(suite_tmp_dir, name) + '.stderr' if ext == '.sql': - command = "{0} --multiquery < {1} > {2} 2> {3}".format(args.client, case_file, stdout_file, stderr_file) + command = "{0} --testmode --multiquery < {1} > {2} 2> {3}".format(args.client, case_file, stdout_file, stderr_file) else: command = "{0} > {1} 2> {2}".format(case_file, stdout_file, stderr_file) diff --git a/dbms/tests/integration/helpers/client.py b/dbms/tests/integration/helpers/client.py index 1fa2b7c7643..2c2b397c900 100644 --- a/dbms/tests/integration/helpers/client.py +++ b/dbms/tests/integration/helpers/client.py @@ -19,7 +19,7 @@ class Client: command = self.command[:] if stdin is None: - command += ['--multiquery'] + command += ['--multiquery', '--testmode'] stdin = sql else: command += ['--query', sql] diff --git a/dbms/tests/queries/0_stateless/00002_system_numbers.sql b/dbms/tests/queries/0_stateless/00002_system_numbers.sql index bc9269495bc..d6ebf8e89ed 100644 --- a/dbms/tests/queries/0_stateless/00002_system_numbers.sql +++ b/dbms/tests/queries/0_stateless/00002_system_numbers.sql @@ -1 +1,12 @@ -SELECT * FROM system.numbers LIMIT 10 +SELECT * FROM system.numbers LIMIT 3; +SELECT sys_num.number FROM system.numbers AS sys_num WHERE number > 2 LIMIT 2; +SELECT number FROM system.numbers WHERE number >= 5 LIMIT 2; +SELECT * FROM system.numbers WHERE number == 7 LIMIT 1; +SELECT number AS n FROM system.numbers WHERE number IN(8, 9) LIMIT 2; +select number from system.numbers limit 0; +select x from system.numbers limit 1; -- { clientError 0 serverError 47 } +SELECT x, number FROM system.numbers LIMIT 1; -- { serverError 47 } +SELECT * FROM system.number LIMIT 1; -- { serverError 60 } +SELECT * FROM system LIMIT 1; -- { serverError 60 } +SELECT * FROM numbers LIMIT 1; -- { serverError 60 } +SELECT sys.number FROM system.numbers AS sys_num LIMIT 1; -- { serverError 47 } diff --git a/dbms/tests/queries/0_stateless/00007_array.reference b/dbms/tests/queries/0_stateless/00007_array.reference index 2a64c8ea7b2..62a24ffe3bf 100644 --- a/dbms/tests/queries/0_stateless/00007_array.reference +++ b/dbms/tests/queries/0_stateless/00007_array.reference @@ -1 +1,3 @@ ['Hello','Goodbye'] +['Hello'] ['Goodbye'] +[] diff --git a/dbms/tests/queries/0_stateless/00007_array.sql b/dbms/tests/queries/0_stateless/00007_array.sql index 7c1f27f1978..cf53e8f78a3 100644 --- a/dbms/tests/queries/0_stateless/00007_array.sql +++ b/dbms/tests/queries/0_stateless/00007_array.sql @@ -1 +1,3 @@ -SELECT ['Hello', 'Goodbye'] +SELECT ['Hello', 'Goodbye']; +SELECT ['Hello'], ['Goodbye']; +SELECT []; From a28cf1ed9831c3e666ba5f5ca799d015d8db590e Mon Sep 17 00:00:00 2001 From: alesapin Date: Fri, 27 Jul 2018 20:25:51 +0300 Subject: [PATCH 198/425] Remove wrong option --- dbms/tests/integration/test_replication_credentials/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/integration/test_replication_credentials/test.py b/dbms/tests/integration/test_replication_credentials/test.py index 0b2163c05ad..ad5f05e04d9 100644 --- a/dbms/tests/integration/test_replication_credentials/test.py +++ b/dbms/tests/integration/test_replication_credentials/test.py @@ -14,7 +14,7 @@ def _fill_nodes(nodes, shard): ENGINE = ReplicatedMergeTree('/clickhouse/tables/test{shard}/replicated', '{replica}', date, id, 8192); '''.format(shard=shard, replica=node.name)) -cluster = ClickHouseCluster(__file__, server_bin_path="/home/alesap/ClickHouse/dbms/programs/clickhouse-server") +cluster = ClickHouseCluster(__file__) node1 = cluster.add_instance('node1', main_configs=['configs/remote_servers.xml', 'configs/credentials1.xml'], with_zookeeper=True) node2 = cluster.add_instance('node2', main_configs=['configs/remote_servers.xml', 'configs/credentials1.xml'], with_zookeeper=True) From cac790f08f4f8310b582fecbb089b7decd68c3e8 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 27 Jul 2018 20:37:53 +0300 Subject: [PATCH 199/425] Update Client.cpp --- dbms/programs/client/Client.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/programs/client/Client.cpp b/dbms/programs/client/Client.cpp index f8072cc4695..76f6e7fb46b 100644 --- a/dbms/programs/client/Client.cpp +++ b/dbms/programs/client/Client.cpp @@ -177,7 +177,6 @@ private: }; -/// class Client : public Poco::Util::Application { public: From 845edbe2426e679296e4a3e9f6567f0599c8a602 Mon Sep 17 00:00:00 2001 From: chertus Date: Fri, 27 Jul 2018 20:19:22 +0300 Subject: [PATCH 200/425] CLICKHOUSE-2: support negative tests --- dbms/programs/client/Client.cpp | 126 +++++++++++++++++- dbms/tests/clickhouse-test | 2 +- dbms/tests/integration/helpers/client.py | 2 +- .../0_stateless/00002_system_numbers.sql | 13 +- .../queries/0_stateless/00007_array.reference | 2 + .../tests/queries/0_stateless/00007_array.sql | 4 +- 6 files changed, 140 insertions(+), 9 deletions(-) diff --git a/dbms/programs/client/Client.cpp b/dbms/programs/client/Client.cpp index eb7673c947b..f8072cc4695 100644 --- a/dbms/programs/client/Client.cpp +++ b/dbms/programs/client/Client.cpp @@ -89,6 +89,95 @@ namespace ErrorCodes } +/// Checks expected server and client error codes in testmode. +/// To enable it add special comment after the query: "-- { serverError 60 }" or "-- { clientError 20 }". +class TestHint +{ +public: + TestHint(bool enabled_, const String & query) + : enabled(enabled_), + server_error(0), + client_error(0) + { + if (!enabled_) + return; + + size_t pos = query.find("--"); + if (pos != String::npos && query.find("--", pos + 2) != String::npos) + return; /// It's not last comment. Hint belongs to commented query. + + if (pos != String::npos) + { + pos = query.find('{', pos + 2); + if (pos != String::npos) + { + String hint = query.substr(pos + 1); + pos = hint.find('}'); + hint.resize(pos); + parse(hint); + } + } + } + + void checkActual(int actual_server_error, int actual_client_error, + bool & got_exception, std::unique_ptr & last_exception) const + { + if (!enabled) + return; + + if (allErrorsExpected(actual_server_error, actual_client_error)) + { + got_exception = false; + last_exception.reset(); + } + + if (lostExpectedError(actual_server_error, actual_client_error)) + { + std::cerr << "Success when error expected. It expects server error " + << server_error << ", client error " << client_error << "." << std::endl; + got_exception = true; + } + } + + int serverError() const { return server_error; } + int clientError() const { return client_error; } + +private: + bool enabled; + int server_error; + int client_error; + + void parse(const String & hint) + { + std::stringstream ss; + ss << hint; + while (!ss.eof()) + { + String item; + ss >> item; + if (item.empty()) + break; + + if (item == "serverError") + ss >> server_error; + else if (item == "clientError") + ss >> client_error; + } + } + + bool allErrorsExpected(int actual_server_error, int actual_client_error) const + { + return (server_error == actual_server_error) && (client_error == actual_client_error); + } + + bool lostExpectedError(int actual_server_error, int actual_client_error) const + { + return (server_error && !actual_server_error) || (client_error && !actual_client_error); + } +}; + + +/// class Client : public Poco::Util::Application { public: @@ -157,6 +246,10 @@ private: /// If the last query resulted in exception. bool got_exception = false; + int expected_server_error = 0; + int expected_client_error = 0; + int actual_server_error = 0; + int actual_client_error = 0; String server_version; String server_display_name; @@ -617,10 +710,14 @@ private: } catch (const Exception & e) { - std::cerr << std::endl - << "Exception on client:" << std::endl - << "Code: " << e.code() << ". " << e.displayText() << std::endl - << std::endl; + actual_client_error = e.code(); + if (!actual_client_error || actual_client_error != expected_client_error) + { + std::cerr << std::endl + << "Exception on client:" << std::endl + << "Code: " << e.code() << ". " << e.displayText() << std::endl + << std::endl; + } /// Client-side exception during query execution can result in the loss of /// sync in the connection protocol. @@ -659,6 +756,7 @@ private: bool process(const String & text) { const auto ignore_error = config().getBool("ignore-error", false); + const bool test_mode = config().has("testmode"); if (config().has("multiquery")) { /// Several queries separated by ';'. @@ -702,6 +800,10 @@ private: while (isWhitespaceASCII(*begin) || *begin == ';') ++begin; + TestHint test_hint(test_mode, query); + expected_client_error = test_hint.clientError(); + expected_server_error = test_hint.serverError(); + try { if (!processSingleQuery(query, ast) && !ignore_error) @@ -709,10 +811,13 @@ private: } catch (...) { + actual_client_error = getCurrentExceptionCode(); std::cerr << "Error on processing query: " << query << std::endl << getCurrentExceptionMessage(true); got_exception = true; } + test_hint.checkActual(actual_server_error, actual_client_error, got_exception, last_exception); + if (got_exception && !ignore_error) { if (is_interactive) @@ -1286,6 +1391,14 @@ private: resetOutput(); got_exception = true; + actual_server_error = e.code(); + if (expected_server_error) + { + if (actual_server_error == expected_server_error) + return; + std::cerr << "Expected error code: " << expected_server_error << " but got: " << actual_server_error << "." << std::endl; + } + std::string text = e.displayText(); auto embedded_stack_trace_pos = text.find("Stack trace"); @@ -1411,7 +1524,8 @@ public: ("pager", boost::program_options::value(), "pager") ("multiline,m", "multiline") ("multiquery,n", "multiquery") - ("ignore-error", "Do not stop processing in multiquery mode") + ("testmode,T", "enable test hints in comments") + ("ignore-error", "do not stop processing in multiquery mode") ("format,f", boost::program_options::value(), "default output format") ("vertical,E", "vertical output format, same as --format=Vertical or FORMAT Vertical or \\G at end of command") ("time,t", "print query execution time to stderr in non-interactive mode (for benchmarks)") @@ -1517,6 +1631,8 @@ public: config().setBool("multiline", true); if (options.count("multiquery")) config().setBool("multiquery", true); + if (options.count("testmode")) + config().setBool("testmode", true); if (options.count("ignore-error")) config().setBool("ignore-error", true); if (options.count("format")) diff --git a/dbms/tests/clickhouse-test b/dbms/tests/clickhouse-test index f734b784f9b..403078c581b 100755 --- a/dbms/tests/clickhouse-test +++ b/dbms/tests/clickhouse-test @@ -195,7 +195,7 @@ def main(args): stderr_file = os.path.join(suite_tmp_dir, name) + '.stderr' if ext == '.sql': - command = "{0} --multiquery < {1} > {2} 2> {3}".format(args.client, case_file, stdout_file, stderr_file) + command = "{0} --testmode --multiquery < {1} > {2} 2> {3}".format(args.client, case_file, stdout_file, stderr_file) else: command = "{0} > {1} 2> {2}".format(case_file, stdout_file, stderr_file) diff --git a/dbms/tests/integration/helpers/client.py b/dbms/tests/integration/helpers/client.py index 1fa2b7c7643..2c2b397c900 100644 --- a/dbms/tests/integration/helpers/client.py +++ b/dbms/tests/integration/helpers/client.py @@ -19,7 +19,7 @@ class Client: command = self.command[:] if stdin is None: - command += ['--multiquery'] + command += ['--multiquery', '--testmode'] stdin = sql else: command += ['--query', sql] diff --git a/dbms/tests/queries/0_stateless/00002_system_numbers.sql b/dbms/tests/queries/0_stateless/00002_system_numbers.sql index bc9269495bc..d6ebf8e89ed 100644 --- a/dbms/tests/queries/0_stateless/00002_system_numbers.sql +++ b/dbms/tests/queries/0_stateless/00002_system_numbers.sql @@ -1 +1,12 @@ -SELECT * FROM system.numbers LIMIT 10 +SELECT * FROM system.numbers LIMIT 3; +SELECT sys_num.number FROM system.numbers AS sys_num WHERE number > 2 LIMIT 2; +SELECT number FROM system.numbers WHERE number >= 5 LIMIT 2; +SELECT * FROM system.numbers WHERE number == 7 LIMIT 1; +SELECT number AS n FROM system.numbers WHERE number IN(8, 9) LIMIT 2; +select number from system.numbers limit 0; +select x from system.numbers limit 1; -- { clientError 0 serverError 47 } +SELECT x, number FROM system.numbers LIMIT 1; -- { serverError 47 } +SELECT * FROM system.number LIMIT 1; -- { serverError 60 } +SELECT * FROM system LIMIT 1; -- { serverError 60 } +SELECT * FROM numbers LIMIT 1; -- { serverError 60 } +SELECT sys.number FROM system.numbers AS sys_num LIMIT 1; -- { serverError 47 } diff --git a/dbms/tests/queries/0_stateless/00007_array.reference b/dbms/tests/queries/0_stateless/00007_array.reference index 2a64c8ea7b2..62a24ffe3bf 100644 --- a/dbms/tests/queries/0_stateless/00007_array.reference +++ b/dbms/tests/queries/0_stateless/00007_array.reference @@ -1 +1,3 @@ ['Hello','Goodbye'] +['Hello'] ['Goodbye'] +[] diff --git a/dbms/tests/queries/0_stateless/00007_array.sql b/dbms/tests/queries/0_stateless/00007_array.sql index 7c1f27f1978..cf53e8f78a3 100644 --- a/dbms/tests/queries/0_stateless/00007_array.sql +++ b/dbms/tests/queries/0_stateless/00007_array.sql @@ -1 +1,3 @@ -SELECT ['Hello', 'Goodbye'] +SELECT ['Hello', 'Goodbye']; +SELECT ['Hello'], ['Goodbye']; +SELECT []; From e64c22164946cf858dcf66f75a262d07e614d7f6 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Fri, 27 Jul 2018 20:37:53 +0300 Subject: [PATCH 201/425] Update Client.cpp --- dbms/programs/client/Client.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/programs/client/Client.cpp b/dbms/programs/client/Client.cpp index f8072cc4695..76f6e7fb46b 100644 --- a/dbms/programs/client/Client.cpp +++ b/dbms/programs/client/Client.cpp @@ -177,7 +177,6 @@ private: }; -/// class Client : public Poco::Util::Application { public: From bbdd780be0be06a0f336775941cdd536878dd2c2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 27 Jul 2018 21:14:58 +0300 Subject: [PATCH 202/425] Fixed error when IN is used as an aggregation key [#CLICKHOUSE-3855] --- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index a065d01f88c..633de1aac11 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -559,7 +559,7 @@ void ExpressionAnalyzer::analyzeAggregation() const auto & col = block.getByName(column_name); /// Constant expressions have non-null column pointer at this stage. - if (const auto is_constexpr = col.column) + if (col.column && col.column->isColumnConst()) { /// But don't remove last key column if no aggregate functions, otherwise aggregation will not work. if (!aggregate_descriptions.empty() || size > 1) From 448bcdfdb445989d10e5ccfa8db769ec00dfa3d9 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 27 Jul 2018 21:17:32 +0300 Subject: [PATCH 203/425] Added a test [#CLICKHOUSE-3855] --- .../queries/0_stateless/00676_group_by_in.reference | 7 +++++++ dbms/tests/queries/0_stateless/00676_group_by_in.sql | 12 ++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00676_group_by_in.reference create mode 100644 dbms/tests/queries/0_stateless/00676_group_by_in.sql diff --git a/dbms/tests/queries/0_stateless/00676_group_by_in.reference b/dbms/tests/queries/0_stateless/00676_group_by_in.reference new file mode 100644 index 00000000000..a8a294d868d --- /dev/null +++ b/dbms/tests/queries/0_stateless/00676_group_by_in.reference @@ -0,0 +1,7 @@ +1 1 +0 1 +1 1 +0 1 +1 1 +0 8 +1 2 diff --git a/dbms/tests/queries/0_stateless/00676_group_by_in.sql b/dbms/tests/queries/0_stateless/00676_group_by_in.sql new file mode 100644 index 00000000000..9296458dfa3 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00676_group_by_in.sql @@ -0,0 +1,12 @@ +SELECT dummy IN (0) AS x, count() GROUP BY x; + +SELECT 1 IN (0) AS x, count() GROUP BY x; +SELECT 0 IN (0) AS x, count() GROUP BY x; +SELECT materialize(1) IN (0) AS x, count() GROUP BY x; +SELECT materialize(0) IN (0) AS x, count() GROUP BY x; + +SELECT + number IN (1, 2) AS x, + count() +FROM numbers(10) +GROUP BY x; From a7addb80a399936a291de8ec94fc652e0284ebd0 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Fri, 27 Jul 2018 21:45:36 +0300 Subject: [PATCH 204/425] Auto version update to [18.3.0] [54398] --- dbms/cmake/version.cmake | 10 +++++----- debian/changelog | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 9b8de90f6b7..03e1214086e 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,11 +1,11 @@ # This strings autochanged from release_lib.sh: -set(VERSION_REVISION 54397 CACHE STRING "") +set(VERSION_REVISION 54398 CACHE STRING "") set(VERSION_MAJOR 18 CACHE STRING "") -set(VERSION_MINOR 2 CACHE STRING "") +set(VERSION_MINOR 3 CACHE STRING "") set(VERSION_PATCH 0 CACHE STRING "") -set(VERSION_GITHASH 6ad677d7d6961a0c9088ccd9eff55779cfdaa654 CACHE STRING "") -set(VERSION_DESCRIBE v18.2.0-testing CACHE STRING "") -set(VERSION_STRING 18.2.0 CACHE STRING "") +set(VERSION_GITHASH 448bcdfdb445989d10e5ccfa8db769ec00dfa3d9 CACHE STRING "") +set(VERSION_DESCRIBE v18.3.0-testing CACHE STRING "") +set(VERSION_STRING 18.3.0 CACHE STRING "") # end of autochange set(VERSION_EXTRA "" CACHE STRING "") diff --git a/debian/changelog b/debian/changelog index 68f349b3c45..11c66f6b938 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (18.2.0) unstable; urgency=low +clickhouse (18.3.0) unstable; urgency=low * Modified source code - -- Mon, 23 Jul 2018 22:38:09 +0300 + -- Fri, 27 Jul 2018 21:45:36 +0300 From a2101df25a6a0fba99aa71f8793d762af2b801ee Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 27 Jul 2018 22:51:13 +0300 Subject: [PATCH 205/425] Fixed error in aggregate function "anyHeavy"; added a test [#CLICKHOUSE-3867] --- dbms/src/AggregateFunctions/AggregateFunctionMinMaxAny.h | 2 +- .../queries/0_stateless/00677_shard_any_heavy_merge.reference | 1 + dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.sql | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.reference create mode 100644 dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.sql diff --git a/dbms/src/AggregateFunctions/AggregateFunctionMinMaxAny.h b/dbms/src/AggregateFunctions/AggregateFunctionMinMaxAny.h index 4b92a6231fe..322307c2bcf 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionMinMaxAny.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionMinMaxAny.h @@ -646,7 +646,7 @@ struct AggregateFunctionAnyHeavyData : Data } else { - if (counter < to.counter) + if ((!this->has() && to.has()) || counter < to.counter) { this->change(to, arena); return true; diff --git a/dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.reference b/dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.reference new file mode 100644 index 00000000000..ec20747d6cd --- /dev/null +++ b/dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.reference @@ -0,0 +1 @@ +4 ['hello','world'] hello diff --git a/dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.sql b/dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.sql new file mode 100644 index 00000000000..f6fac23a155 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00677_shard_any_heavy_merge.sql @@ -0,0 +1 @@ +WITH arrayJoin(['hello', 'world']) AS s SELECT count(), arraySort(groupUniqArray(s)), anyHeavy(s) FROM remote('127.0.0.{2,3}', system.one); From a93a0dc84018fe0d1654601ffdf9c20628937966 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 27 Jul 2018 23:01:14 +0300 Subject: [PATCH 206/425] Removed a note about Kafka from testing documentation #2729 --- docs/en/development/tests.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/en/development/tests.md b/docs/en/development/tests.md index d6c92cf622e..ee2402aedc7 100644 --- a/docs/en/development/tests.md +++ b/docs/en/development/tests.md @@ -32,8 +32,6 @@ See `dbms/tests/integration/README.md` on how to run these tests. Note that integration of ClickHouse with third-party drivers is not tested. Also we currently don't have integration tests with our JDBC and ODBC drivers. -We don't have integration tests for `Kafka` table engine that is developed by community - this is one of the most anticipated tests (otherwise there is almost no way to be confident with `Kafka` tables). - ## Unit Tests From 8bc95412b66b360fdbef5bb0cec5217378f066a6 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 28 Jul 2018 00:33:30 +0300 Subject: [PATCH 207/425] Fixed bad code #2708 --- .../ClusterProxy/SelectStreamFactory.cpp | 10 ++++---- .../ClusterProxy/SelectStreamFactory.h | 2 +- .../evaluateConstantExpression.cpp | 5 ++-- dbms/src/Parsers/ASTSelectQuery.cpp | 6 ++--- dbms/src/Storages/StorageDistributed.cpp | 6 ++--- dbms/src/Storages/StorageDistributed.h | 4 ++-- dbms/src/Storages/StorageKafka.cpp | 5 ++-- .../Storages/getStructureOfRemoteTable.cpp | 4 ++-- .../src/TableFunctions/TableFunctionFactory.h | 2 +- .../TableFunctions/TableFunctionRemote.cpp | 24 ++++++++++--------- 10 files changed, 35 insertions(+), 33 deletions(-) diff --git a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp index eb1d54c457e..cd6bed0c1d7 100644 --- a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp +++ b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.cpp @@ -93,16 +93,16 @@ void SelectStreamFactory::createForShard( if (shard_info.isLocal()) { StoragePtr main_table_storage; - + if (table_func_ptr) { - auto table_function = static_cast(table_func_ptr.get()); + auto table_function = static_cast(table_func_ptr.get()); main_table_storage = TableFunctionFactory::instance().get(table_function->name, context)->execute(table_func_ptr, context); } - else + else main_table_storage = context.tryGetTable(main_table.database, main_table.table); - - + + if (!main_table_storage) /// Table is absent on a local server. { ProfileEvents::increment(ProfileEvents::DistributedConnectionMissingTable); diff --git a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h index 38dabf82dcc..75c6938b56b 100644 --- a/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h +++ b/dbms/src/Interpreters/ClusterProxy/SelectStreamFactory.h @@ -19,7 +19,7 @@ public: QueryProcessingStage::Enum processed_stage_, QualifiedTableName main_table_, const Tables & external_tables); - + /// TableFunction in a query. SelectStreamFactory( const Block & header_, diff --git a/dbms/src/Interpreters/evaluateConstantExpression.cpp b/dbms/src/Interpreters/evaluateConstantExpression.cpp index 6dcff35e6a4..3fee9a8e2a7 100644 --- a/dbms/src/Interpreters/evaluateConstantExpression.cpp +++ b/dbms/src/Interpreters/evaluateConstantExpression.cpp @@ -57,13 +57,12 @@ ASTPtr evaluateConstantExpressionAsLiteral(const ASTPtr & node, const Context & /// Branch with string in qery. if (typeid_cast(node.get())) return node; - + /// Branch with TableFunction in query. if (auto table_func_ptr = typeid_cast(node.get())) if (TableFunctionFactory::instance().isTableFunctionName(table_func_ptr->name)) - return node; - + return std::make_shared(evaluateConstantExpression(node, context).first); } diff --git a/dbms/src/Parsers/ASTSelectQuery.cpp b/dbms/src/Parsers/ASTSelectQuery.cpp index 8bb5f2488d8..f4b4c217de1 100644 --- a/dbms/src/Parsers/ASTSelectQuery.cpp +++ b/dbms/src/Parsers/ASTSelectQuery.cpp @@ -372,9 +372,9 @@ void ASTSelectQuery::replaceDatabaseAndTable(const String & database_name, const children.emplace_back(tables_list); table_expression = table_expr.get(); } - + ASTPtr table = std::make_shared(table_name, ASTIdentifier::Table); - + if (!database_name.empty()) { ASTPtr database = std::make_shared(database_name, ASTIdentifier::Database); @@ -405,7 +405,7 @@ void ASTSelectQuery::addTableFunction(ASTPtr & table_function_ptr) children.emplace_back(tables_list); table_expression = table_expr.get(); } - + table_expression->table_function = table_function_ptr; table_expression->database_and_table_name = nullptr; } diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 5805ea439f3..a3b2e7f31f8 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -244,19 +244,19 @@ BlockInputStreams StorageDistributed::read( processed_stage = result_size == 1 ? QueryProcessingStage::Complete : QueryProcessingStage::WithMergeableState; - + const auto & modified_query_ast = rewriteSelectQuery( query_info.query, remote_database, remote_table, remote_table_function_ptr); Block header = materializeBlock(InterpreterSelectQuery(query_info.query, context, Names{}, processed_stage).getSampleBlock()); - + ClusterProxy::SelectStreamFactory select_stream_factory = remote_table_function_ptr ? ClusterProxy::SelectStreamFactory( header, processed_stage, remote_table_function_ptr, context.getExternalTables()) : ClusterProxy::SelectStreamFactory( header, processed_stage, QualifiedTableName{remote_database, remote_table}, context.getExternalTables()); - + return ClusterProxy::executeQuery( select_stream_factory, cluster, modified_query_ast, context, settings); } diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index dda56bb3312..c4367b5a064 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -41,7 +41,7 @@ public: const String & remote_table_, /// The name of the table on the remote servers. ClusterPtr owned_cluster_, const Context & context_); - + static StoragePtr createWithOwnCluster( const std::string & table_name_, const ColumnsDescription & columns_, @@ -155,7 +155,7 @@ protected: const ASTPtr & sharding_key_, const String & data_path_, bool attach); - + StorageDistributed( const String & database_name, const String & table_name_, diff --git a/dbms/src/Storages/StorageKafka.cpp b/dbms/src/Storages/StorageKafka.cpp index 7823dfdd65a..43ed4e3b63d 100644 --- a/dbms/src/Storages/StorageKafka.cpp +++ b/dbms/src/Storages/StorageKafka.cpp @@ -128,8 +128,9 @@ class ReadBufferFromKafkaConsumer : public ReadBuffer public: ReadBufferFromKafkaConsumer(rd_kafka_t * consumer_, Poco::Logger * log_, char row_delimiter_) : ReadBuffer(nullptr, 0), consumer(consumer_), current(nullptr), - current_pending(false), log(log_), read_messages(0), row_delimiter(row_delimiter_) { - LOG_TRACE(log, "row delimiter is :" << row_delimiter); + current_pending(false), log(log_), read_messages(0), row_delimiter(row_delimiter_) + { + LOG_TRACE(log, "Row delimiter is: " << row_delimiter); } ~ReadBufferFromKafkaConsumer() { reset(); } diff --git a/dbms/src/Storages/getStructureOfRemoteTable.cpp b/dbms/src/Storages/getStructureOfRemoteTable.cpp index 37cc036c367..174ec49a4f1 100644 --- a/dbms/src/Storages/getStructureOfRemoteTable.cpp +++ b/dbms/src/Storages/getStructureOfRemoteTable.cpp @@ -29,14 +29,14 @@ ColumnsDescription getStructureOfRemoteTable( { /// Send to the first any remote shard. const auto & shard_info = cluster.getAnyShardInfo(); - + String query; if (table_func_ptr) { if (shard_info.isLocal()) { - auto table_function = static_cast(table_func_ptr.get()); + auto table_function = static_cast(table_func_ptr.get()); return TableFunctionFactory::instance().get(table_function->name, context)->execute(table_func_ptr, context)->getColumns(); } diff --git a/dbms/src/TableFunctions/TableFunctionFactory.h b/dbms/src/TableFunctions/TableFunctionFactory.h index acc08bacffa..22bc5cdb99f 100644 --- a/dbms/src/TableFunctions/TableFunctionFactory.h +++ b/dbms/src/TableFunctions/TableFunctionFactory.h @@ -42,7 +42,7 @@ public: TableFunctionPtr get( const std::string & name, const Context & context) const; - + bool isTableFunctionName(const std::string & name) const; const TableFunctions & getAllTableFunctions() const diff --git a/dbms/src/TableFunctions/TableFunctionRemote.cpp b/dbms/src/TableFunctions/TableFunctionRemote.cpp index 9bea9e881ca..4f7d1c11ac2 100644 --- a/dbms/src/TableFunctions/TableFunctionRemote.cpp +++ b/dbms/src/TableFunctions/TableFunctionRemote.cpp @@ -231,17 +231,18 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C ++arg_num; args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context); - - const auto table_function = static_cast(args[arg_num].get()); - - if (TableFunctionFactory::instance().isTableFunctionName(table_function->name)) + + const auto function = typeid_cast(args[arg_num].get()); + + if (function && TableFunctionFactory::instance().isTableFunctionName(function->name)) { remote_table_function_ptr = args[arg_num]; ++arg_num; } - else { + else + { remote_database = static_cast(*args[arg_num]).value.safeGet(); - + ++arg_num; size_t dot = remote_database.find('.'); @@ -254,12 +255,13 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C else { if (arg_num >= args.size()) + { throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + } else { args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context); remote_table = static_cast(*args[arg_num]).value.safeGet(); - remote_database = remote_database; ++arg_num; } } @@ -315,15 +317,14 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C } auto structure_remote_table = getStructureOfRemoteTable(*cluster, remote_database, remote_table, context, remote_table_function_ptr); - - StoragePtr res = remote_table_function_ptr ? - StorageDistributed::createWithOwnCluster( + + StoragePtr res = remote_table_function_ptr + ? StorageDistributed::createWithOwnCluster( getName(), structure_remote_table, remote_table_function_ptr, cluster, context) - : StorageDistributed::createWithOwnCluster( getName(), structure_remote_table, @@ -336,6 +337,7 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C return res; } + TableFunctionRemote::TableFunctionRemote(const std::string & name_) : name(name_) { From e26ba4daac5c2a4e480701cb630d1157b62e23f1 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Sat, 28 Jul 2018 00:35:05 +0300 Subject: [PATCH 208/425] Auto version update to [18.4.0] [54399] --- dbms/cmake/version.cmake | 10 +++++----- debian/changelog | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 03e1214086e..643889df9af 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,11 +1,11 @@ # This strings autochanged from release_lib.sh: -set(VERSION_REVISION 54398 CACHE STRING "") +set(VERSION_REVISION 54399 CACHE STRING "") set(VERSION_MAJOR 18 CACHE STRING "") -set(VERSION_MINOR 3 CACHE STRING "") +set(VERSION_MINOR 4 CACHE STRING "") set(VERSION_PATCH 0 CACHE STRING "") -set(VERSION_GITHASH 448bcdfdb445989d10e5ccfa8db769ec00dfa3d9 CACHE STRING "") -set(VERSION_DESCRIBE v18.3.0-testing CACHE STRING "") -set(VERSION_STRING 18.3.0 CACHE STRING "") +set(VERSION_GITHASH 8bc95412b66b360fdbef5bb0cec5217378f066a6 CACHE STRING "") +set(VERSION_DESCRIBE v18.4.0-testing CACHE STRING "") +set(VERSION_STRING 18.4.0 CACHE STRING "") # end of autochange set(VERSION_EXTRA "" CACHE STRING "") diff --git a/debian/changelog b/debian/changelog index 11c66f6b938..11678afb9c0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -clickhouse (18.3.0) unstable; urgency=low +clickhouse (18.4.0) unstable; urgency=low * Modified source code - -- Fri, 27 Jul 2018 21:45:36 +0300 + -- Sat, 28 Jul 2018 00:35:05 +0300 From 652e5ff9e2c25b88e703672b6ac7a4ce40ebc454 Mon Sep 17 00:00:00 2001 From: alesapin Date: Fri, 27 Jul 2018 18:36:21 +0300 Subject: [PATCH 209/425] CLICKHOUSE-3852: Add ability to set up config parameters from env variables. --- dbms/src/Common/Config/ConfigProcessor.cpp | 54 ++++++++++++++++------ dbms/src/Common/Config/ConfigProcessor.h | 2 + 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/dbms/src/Common/Config/ConfigProcessor.cpp b/dbms/src/Common/Config/ConfigProcessor.cpp index 1e0cb91340b..2f9e673fb7e 100644 --- a/dbms/src/Common/Config/ConfigProcessor.cpp +++ b/dbms/src/Common/Config/ConfigProcessor.cpp @@ -103,7 +103,8 @@ static ElementIdentifier getElementIdentifier(Node * element) { const Node * node = attrs->item(i); std::string name = node->nodeName(); - if (name == "replace" || name == "remove" || name == "incl" || name == "from_zk") + if (name == "replace" || name == "remove" || + std::count(ConfigProcessor::SUBSTITUTION_ATTRS.begin(), ConfigProcessor::SUBSTITUTION_ATTRS.end(), name) > 0) continue; std::string value = node->nodeValue(); attrs_kv.push_back(std::make_pair(name, value)); @@ -267,12 +268,13 @@ void ConfigProcessor::doIncludesRecursive( return; } + std::vector attr_nodes; NamedNodeMapPtr attributes = node->attributes(); - const Node * incl_attribute = attributes->getNamedItem("incl"); - const Node * from_zk_attribute = attributes->getNamedItem("from_zk"); + for (const auto & attr_name : SUBSTITUTION_ATTRS) + attr_nodes.push_back(attributes->getNamedItem(attr_name)); - if (incl_attribute && from_zk_attribute) - throw Poco::Exception("both incl and from_zk attributes set for element <" + node->nodeName() + ">"); + if (std::count(attr_nodes.begin(), attr_nodes.end(), nullptr) < 2) + throw Poco::Exception("several substitutions attributes set for element <" + node->nodeName() + ">"); /// Replace the original contents, not add to it. bool replace = attributes->getNamedItem("replace"); @@ -296,8 +298,8 @@ void ConfigProcessor::doIncludesRecursive( { Element & element = dynamic_cast(*node); - element.removeAttribute("incl"); - element.removeAttribute("from_zk"); + for (const auto & attr_name : SUBSTITUTION_ATTRS) + element.removeAttribute(attr_name); if (replace) { @@ -324,16 +326,19 @@ void ConfigProcessor::doIncludesRecursive( } }; - auto get_incl_node = [&](const std::string & name) + if (attr_nodes[0]) // we have include subst { - return include_from ? include_from->getNodeByPath("yandex/" + name) : nullptr; - }; - if (incl_attribute) - process_include(incl_attribute, get_incl_node, "Include not found: "); + auto get_incl_node = [&](const std::string & name) + { + return include_from ? include_from->getNodeByPath("yandex/" + name) : nullptr; + }; - if (from_zk_attribute) + process_include(attr_nodes[0], get_incl_node, "Include not found: "); + } + + if (attr_nodes[1]) /// we have zookeeper subst { - contributing_zk_paths.insert(from_zk_attribute->getNodeValue()); + contributing_zk_paths.insert(attr_nodes[1]->getNodeValue()); if (zk_node_cache) { @@ -349,10 +354,29 @@ void ConfigProcessor::doIncludesRecursive( return getRootNode(zk_document.get()); }; - process_include(from_zk_attribute, get_zk_node, "Could not get ZooKeeper node: "); + process_include(attr_nodes[1], get_zk_node, "Could not get ZooKeeper node: "); } } + if (attr_nodes[2]) /// we have env subst + { + XMLDocumentPtr env_document; + auto get_env_node = [&](const std::string & name) -> const Node * + { + std::string value = std::getenv(name.c_str()); + if (value.empty()) + return nullptr; + + env_document = dom_parser.parseString("" + value + ""); + + return getRootNode(env_document.get()); + }; + + process_include(attr_nodes[2], get_env_node, "Env variable is not set: "); + + } + + if (included_something) doIncludesRecursive(config, include_from, node, zk_node_cache, contributing_zk_paths); else diff --git a/dbms/src/Common/Config/ConfigProcessor.h b/dbms/src/Common/Config/ConfigProcessor.h index 8c9048bb102..8663ecb682f 100644 --- a/dbms/src/Common/Config/ConfigProcessor.h +++ b/dbms/src/Common/Config/ConfigProcessor.h @@ -95,6 +95,8 @@ public: /// Is the file named as result of config preprocessing, not as original files. static bool isPreprocessedFile(const std::string & config_path); + static inline const auto SUBSTITUTION_ATTRS = {"incl", "from_zk", "from_env"}; + private: const std::string path; const std::string preprocessed_path; From 1f32701665b5b5755d6c5e1e08805a96943b3fa0 Mon Sep 17 00:00:00 2001 From: alesapin Date: Fri, 27 Jul 2018 18:38:59 +0300 Subject: [PATCH 210/425] CLICKHOUSE-3852: Remove useless newlines --- dbms/src/Common/Config/ConfigProcessor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/dbms/src/Common/Config/ConfigProcessor.cpp b/dbms/src/Common/Config/ConfigProcessor.cpp index 2f9e673fb7e..7ae0ceffa52 100644 --- a/dbms/src/Common/Config/ConfigProcessor.cpp +++ b/dbms/src/Common/Config/ConfigProcessor.cpp @@ -373,10 +373,8 @@ void ConfigProcessor::doIncludesRecursive( }; process_include(attr_nodes[2], get_env_node, "Env variable is not set: "); - } - if (included_something) doIncludesRecursive(config, include_from, node, zk_node_cache, contributing_zk_paths); else From 744258818eede48aa728bb30b4133ed25b39a77c Mon Sep 17 00:00:00 2001 From: alesapin Date: Fri, 27 Jul 2018 20:12:01 +0300 Subject: [PATCH 211/425] CLICKHOUSE-3852: Fix PR remarks --- dbms/src/Common/Config/ConfigProcessor.cpp | 35 +++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/dbms/src/Common/Config/ConfigProcessor.cpp b/dbms/src/Common/Config/ConfigProcessor.cpp index 7ae0ceffa52..112ea7e5fdc 100644 --- a/dbms/src/Common/Config/ConfigProcessor.cpp +++ b/dbms/src/Common/Config/ConfigProcessor.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -103,8 +104,9 @@ static ElementIdentifier getElementIdentifier(Node * element) { const Node * node = attrs->item(i); std::string name = node->nodeName(); + auto subst_name_pos = std::find(ConfigProcessor::SUBSTITUTION_ATTRS.begin(), ConfigProcessor::SUBSTITUTION_ATTRS.end(), name); if (name == "replace" || name == "remove" || - std::count(ConfigProcessor::SUBSTITUTION_ATTRS.begin(), ConfigProcessor::SUBSTITUTION_ATTRS.end(), name) > 0) + subst_name_pos != ConfigProcessor::SUBSTITUTION_ATTRS.end()) continue; std::string value = node->nodeValue(); attrs_kv.push_back(std::make_pair(name, value)); @@ -268,12 +270,17 @@ void ConfigProcessor::doIncludesRecursive( return; } - std::vector attr_nodes; + std::map attr_nodes; NamedNodeMapPtr attributes = node->attributes(); + size_t substs_count = 0; for (const auto & attr_name : SUBSTITUTION_ATTRS) - attr_nodes.push_back(attributes->getNamedItem(attr_name)); + { + auto subst = attributes->getNamedItem(attr_name); + attr_nodes[attr_name] = subst; + substs_count += static_cast(subst == nullptr); + } - if (std::count(attr_nodes.begin(), attr_nodes.end(), nullptr) < 2) + if (substs_count < SUBSTITUTION_ATTRS.size() - 1) /// only one substitution is allowed throw Poco::Exception("several substitutions attributes set for element <" + node->nodeName() + ">"); /// Replace the original contents, not add to it. @@ -326,19 +333,19 @@ void ConfigProcessor::doIncludesRecursive( } }; - if (attr_nodes[0]) // we have include subst + if (attr_nodes["incl"]) // we have include subst { auto get_incl_node = [&](const std::string & name) { return include_from ? include_from->getNodeByPath("yandex/" + name) : nullptr; }; - process_include(attr_nodes[0], get_incl_node, "Include not found: "); + process_include(attr_nodes["incl"], get_incl_node, "Include not found: "); } - if (attr_nodes[1]) /// we have zookeeper subst + if (attr_nodes["from_zk"]) /// we have zookeeper subst { - contributing_zk_paths.insert(attr_nodes[1]->getNodeValue()); + contributing_zk_paths.insert(attr_nodes["from_zk"]->getNodeValue()); if (zk_node_cache) { @@ -354,25 +361,25 @@ void ConfigProcessor::doIncludesRecursive( return getRootNode(zk_document.get()); }; - process_include(attr_nodes[1], get_zk_node, "Could not get ZooKeeper node: "); + process_include(attr_nodes["from_zk"], get_zk_node, "Could not get ZooKeeper node: "); } } - if (attr_nodes[2]) /// we have env subst + if (attr_nodes["from_env"]) /// we have env subst { XMLDocumentPtr env_document; auto get_env_node = [&](const std::string & name) -> const Node * { - std::string value = std::getenv(name.c_str()); - if (value.empty()) + const char * env_val = std::getenv(name.c_str()); + if (env_val == nullptr) return nullptr; - env_document = dom_parser.parseString("" + value + ""); + env_document = dom_parser.parseString("" + std::string{env_val} + ""); return getRootNode(env_document.get()); }; - process_include(attr_nodes[2], get_env_node, "Env variable is not set: "); + process_include(attr_nodes["from_env"], get_env_node, "Env variable is not set: "); } if (included_something) From 79607b911810dd0c47c002994eb3122f8d4b664c Mon Sep 17 00:00:00 2001 From: alesapin Date: Sat, 28 Jul 2018 17:38:08 +0300 Subject: [PATCH 212/425] CLICKHOUSE-3852: Add tests for config parser --- dbms/tests/integration/helpers/cluster.py | 26 +++++++++++++---- .../test_config_substitutions/__init__.py | 0 .../configs/config_env.xml | 14 ++++++++++ .../configs/config_incl.xml | 15 ++++++++++ .../configs/config_no_substs.xml | 14 ++++++++++ .../configs/config_zk.xml | 14 ++++++++++ .../configs/max_query_size.xml | 3 ++ .../test_config_substitutions/test.py | 28 +++++++++++++++++++ 8 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 dbms/tests/integration/test_config_substitutions/__init__.py create mode 100644 dbms/tests/integration/test_config_substitutions/configs/config_env.xml create mode 100644 dbms/tests/integration/test_config_substitutions/configs/config_incl.xml create mode 100644 dbms/tests/integration/test_config_substitutions/configs/config_no_substs.xml create mode 100644 dbms/tests/integration/test_config_substitutions/configs/config_zk.xml create mode 100644 dbms/tests/integration/test_config_substitutions/configs/max_query_size.xml create mode 100644 dbms/tests/integration/test_config_substitutions/test.py diff --git a/dbms/tests/integration/helpers/cluster.py b/dbms/tests/integration/helpers/cluster.py index 8b5991ad117..0ca348c2364 100644 --- a/dbms/tests/integration/helpers/cluster.py +++ b/dbms/tests/integration/helpers/cluster.py @@ -20,8 +20,16 @@ from .client import Client, CommandRequest HELPERS_DIR = p.dirname(__file__) +DEFAULT_ENV_NAME = 'env_file' +def _create_env_file(path, variables, fname=DEFAULT_ENV_NAME): + full_path = os.path.join(path, fname) + with open(full_path, 'w') as f: + for var, value in variables.items(): + f.write("=".join([var, value]) + "\n") + return full_path + class ClickHouseCluster: """ClickHouse cluster with several instances and (possibly) ZooKeeper. @@ -55,12 +63,12 @@ class ClickHouseCluster: self.with_zookeeper = False self.with_mysql = False self.with_kafka = False - + self.docker_client = None self.is_up = False - def add_instance(self, name, config_dir=None, main_configs=[], user_configs=[], macros={}, with_zookeeper=False, with_mysql=False, with_kafka=False, clickhouse_path_dir=None, hostname=None): + def add_instance(self, name, config_dir=None, main_configs=[], user_configs=[], macros={}, with_zookeeper=False, with_mysql=False, with_kafka=False, clickhouse_path_dir=None, hostname=None, env_variables={}): """Add an instance to the cluster. name - the name of the instance directory and the value of the 'instance' macro in ClickHouse. @@ -78,7 +86,7 @@ class ClickHouseCluster: instance = ClickHouseInstance( self, self.base_dir, name, config_dir, main_configs, user_configs, macros, with_zookeeper, - self.zookeeper_config_path, with_mysql, with_kafka, self.base_configs_dir, self.server_bin_path, clickhouse_path_dir, hostname=hostname) + self.zookeeper_config_path, with_mysql, with_kafka, self.base_configs_dir, self.server_bin_path, clickhouse_path_dir, hostname=hostname, env_variables=env_variables) self.instances[name] = instance self.base_cmd.extend(['--file', instance.docker_compose_path]) @@ -87,7 +95,7 @@ class ClickHouseCluster: self.base_cmd.extend(['--file', p.join(HELPERS_DIR, 'docker_compose_zookeeper.yml')]) self.base_zookeeper_cmd = ['docker-compose', '--project-directory', self.base_dir, '--project-name', self.project_name, '--file', p.join(HELPERS_DIR, 'docker_compose_zookeeper.yml')] - + if with_mysql and not self.with_mysql: self.with_mysql = True self.base_cmd.extend(['--file', p.join(HELPERS_DIR, 'docker_compose_mysql.yml')]) @@ -219,13 +227,15 @@ services: - --log-file=/var/log/clickhouse-server/clickhouse-server.log - --errorlog-file=/var/log/clickhouse-server/clickhouse-server.err.log depends_on: {depends_on} + env_file: + - {env_file} ''' class ClickHouseInstance: def __init__( self, cluster, base_path, name, custom_config_dir, custom_main_configs, custom_user_configs, macros, - with_zookeeper, zookeeper_config_path, with_mysql, with_kafka, base_configs_dir, server_bin_path, clickhouse_path_dir, hostname=None): + with_zookeeper, zookeeper_config_path, with_mysql, with_kafka, base_configs_dir, server_bin_path, clickhouse_path_dir, hostname=None, env_variables={}): self.name = name self.base_cmd = cluster.base_cmd[:] @@ -249,6 +259,7 @@ class ClickHouseInstance: self.path = p.join(self.cluster.instances_dir, name) self.docker_compose_path = p.join(self.path, 'docker_compose.yml') + self.env_variables = env_variables self.docker_client = None self.ip_address = None @@ -396,6 +407,8 @@ class ClickHouseInstance: depends_on.append("zoo2") depends_on.append("zoo3") + env_file = _create_env_file(os.path.dirname(self.docker_compose_path), self.env_variables) + with open(self.docker_compose_path, 'w') as docker_compose: docker_compose.write(DOCKER_COMPOSE_TEMPLATE.format( name=self.name, @@ -406,7 +419,8 @@ class ClickHouseInstance: config_d_dir=config_d_dir, db_dir=db_dir, logs_dir=logs_dir, - depends_on=str(depends_on))) + depends_on=str(depends_on), + env_file=env_file)) def destroy_dir(self): diff --git a/dbms/tests/integration/test_config_substitutions/__init__.py b/dbms/tests/integration/test_config_substitutions/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dbms/tests/integration/test_config_substitutions/configs/config_env.xml b/dbms/tests/integration/test_config_substitutions/configs/config_env.xml new file mode 100644 index 00000000000..712855c47c0 --- /dev/null +++ b/dbms/tests/integration/test_config_substitutions/configs/config_env.xml @@ -0,0 +1,14 @@ + + + + + + + + + + default + default + + + diff --git a/dbms/tests/integration/test_config_substitutions/configs/config_incl.xml b/dbms/tests/integration/test_config_substitutions/configs/config_incl.xml new file mode 100644 index 00000000000..383a23af1ff --- /dev/null +++ b/dbms/tests/integration/test_config_substitutions/configs/config_incl.xml @@ -0,0 +1,15 @@ + + /etc/clickhouse-server/config.d/max_query_size.xml + + + + + + + + + default + default + + + diff --git a/dbms/tests/integration/test_config_substitutions/configs/config_no_substs.xml b/dbms/tests/integration/test_config_substitutions/configs/config_no_substs.xml new file mode 100644 index 00000000000..ea72e332626 --- /dev/null +++ b/dbms/tests/integration/test_config_substitutions/configs/config_no_substs.xml @@ -0,0 +1,14 @@ + + + + 33333 + + + + + + default + default + + + diff --git a/dbms/tests/integration/test_config_substitutions/configs/config_zk.xml b/dbms/tests/integration/test_config_substitutions/configs/config_zk.xml new file mode 100644 index 00000000000..aa589e9f9d3 --- /dev/null +++ b/dbms/tests/integration/test_config_substitutions/configs/config_zk.xml @@ -0,0 +1,14 @@ + + + + + + + + + + default + default + + + diff --git a/dbms/tests/integration/test_config_substitutions/configs/max_query_size.xml b/dbms/tests/integration/test_config_substitutions/configs/max_query_size.xml new file mode 100644 index 00000000000..9ec61368be9 --- /dev/null +++ b/dbms/tests/integration/test_config_substitutions/configs/max_query_size.xml @@ -0,0 +1,3 @@ + + 99999 + diff --git a/dbms/tests/integration/test_config_substitutions/test.py b/dbms/tests/integration/test_config_substitutions/test.py new file mode 100644 index 00000000000..8e8a2d0971b --- /dev/null +++ b/dbms/tests/integration/test_config_substitutions/test.py @@ -0,0 +1,28 @@ +import time +import pytest + +from helpers.cluster import ClickHouseCluster + +cluster = ClickHouseCluster(__file__) +node1 = cluster.add_instance('node1', main_configs=['configs/config_no_substs.xml']) # hardcoded value 33333 +node2 = cluster.add_instance('node2', main_configs=['configs/config_env.xml'], env_variables={"MAX_QUERY_SIZE": "55555"}) +node3 = cluster.add_instance('node3', main_configs=['configs/config_zk.xml'], with_zookeeper=True) +node4 = cluster.add_instance('node4', main_configs=['configs/config_incl.xml', 'configs/max_query_size.xml']) # include value 77777 + +@pytest.fixture(scope="module") +def start_cluster(): + try: + def create_zk_roots(zk): + zk.create(path="/setting/max_query_size", value="77777", makepath=True) + cluster.add_zookeeper_startup_command(create_zk_roots) + + cluster.start() + yield cluster + finally: + cluster.shutdown() + +def test_config(start_cluster): + assert node1.query("select value from system.settings where name = 'max_query_size'") == "33333\n" + assert node2.query("select value from system.settings where name = 'max_query_size'") == "55555\n" + assert node3.query("select value from system.settings where name = 'max_query_size'") == "77777\n" + assert node4.query("select value from system.settings where name = 'max_query_size'") == "99999\n" From b631924d46f58e470ea894ea9ae8290a39ff3c1c Mon Sep 17 00:00:00 2001 From: chertus Date: Mon, 30 Jul 2018 13:51:29 +0300 Subject: [PATCH 213/425] CLICKHOUSE-2 fix docs --- docs/en/interfaces/formats.md | 6 +++++- docs/ru/interfaces/formats.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/en/interfaces/formats.md b/docs/en/interfaces/formats.md index 7e45beb3e2c..13409866b13 100644 --- a/docs/en/interfaces/formats.md +++ b/docs/en/interfaces/formats.md @@ -64,7 +64,11 @@ Comma Separated Values format ([RFC](https://tools.ietf.org/html/rfc4180)). When formatting, rows are enclosed in double quotes. A double quote inside a string is output as two double quotes in a row. There are no other rules for escaping characters. Date and date-time are enclosed in double quotes. Numbers are output without quotes. Values ​​are separated by a delimiter*. Rows are separated using the Unix line feed (LF). Arrays are serialized in CSV as follows: first the array is serialized to a string as in TabSeparated format, and then the resulting string is output to CSV in double quotes. Tuples in CSV format are serialized as separate columns (that is, their nesting in the tuple is lost). -*By default — `,`. See a [format_csv_delimiter](/docs/en/operations/settings/settings/#format_csv_delimiter) setting for additional info. +``` +clickhouse-client --format_csv_delimiter="|" --query="INSERT INTO test.csv FORMAT CSV" < data.csv +``` + +*By default — `,`. See a [format_csv_delimiter](/operations/settings/settings/#format_csv_delimiter) setting for additional info. When parsing, all values can be parsed either with or without quotes. Both double and single quotes are supported. Rows can also be arranged without quotes. In this case, they are parsed up to a delimiter or line feed (CR or LF). In violation of the RFC, when parsing rows without quotes, the leading and trailing spaces and tabs are ignored. For the line feed, Unix (LF), Windows (CR LF) and Mac OS Classic (CR LF) are all supported. diff --git a/docs/ru/interfaces/formats.md b/docs/ru/interfaces/formats.md index ab6f8591f4b..56f10198236 100644 --- a/docs/ru/interfaces/formats.md +++ b/docs/ru/interfaces/formats.md @@ -66,7 +66,11 @@ struct Message { При форматировании, строки выводятся в двойных кавычках. Двойная кавычка внутри строки выводится как две двойные кавычки подряд. Других правил экранирования нет. Даты и даты-с-временем выводятся в двойных кавычках. Числа выводятся без кавычек. Значения разделяются символом-разделителем*. Строки разделяются unix переводом строки (LF). Массивы сериализуются в CSV следующим образом: сначала массив сериализуется в строку, как в формате TabSeparated, а затем полученная строка выводится в CSV в двойных кавычках. Кортежи в формате CSV сериализуются, как отдельные столбцы (то есть, теряется их вложенность в кортеж). -*По умолчанию — `,`. См. настройку [format_csv_delimiter](/docs/ru/operations/settings/settings/#format_csv_delimiter) для дополнительной информации. +``` +clickhouse-client --format_csv_delimiter="|" --query="INSERT INTO test.csv FORMAT CSV" < data.csv +``` + +*По умолчанию — `,`. См. настройку [format_csv_delimiter](/operations/settings/settings/#format_csv_delimiter) для дополнительной информации. При парсинге, все значения могут парситься как в кавычках, так и без кавычек. Поддерживаются как двойные, так и одинарные кавычки. В том числе, строки могут быть расположены без кавычек - тогда они парсятся до символа-разделителя или перевода строки (CR или LF). В нарушение RFC, в случае парсинга строк не в кавычках, начальные и конечные пробелы и табы игнорируются. В качестве перевода строки, поддерживаются как Unix (LF), так и Windows (CR LF) и Mac OS Classic (LF CR) варианты. From 68bdc4eb12848c4501255f4bb049ce81845f5bea Mon Sep 17 00:00:00 2001 From: ap11 Date: Mon, 30 Jul 2018 15:19:22 +0300 Subject: [PATCH 214/425] Add mumurhash2 --- CMakeLists.txt | 1 + contrib/CMakeLists.txt | 4 + contrib/libmurmurhash2/CMakeLists.txt | 6 + contrib/libmurmurhash2/LICENSE | 1 + contrib/libmurmurhash2/README | 6 + contrib/libmurmurhash2/include/murmurhash2.h | 35 ++ contrib/libmurmurhash2/src/murmurhash2.cpp | 421 +++++++++++++++++++ dbms/src/Functions/CMakeLists.txt | 2 +- dbms/src/Functions/FunctionsHashing.cpp | 1 + dbms/src/Functions/FunctionsHashing.h | 180 +++++++- 10 files changed, 653 insertions(+), 4 deletions(-) create mode 100644 contrib/libmurmurhash2/CMakeLists.txt create mode 100644 contrib/libmurmurhash2/LICENSE create mode 100644 contrib/libmurmurhash2/README create mode 100644 contrib/libmurmurhash2/include/murmurhash2.h create mode 100644 contrib/libmurmurhash2/src/murmurhash2.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f0ef4ed7c51..4467184517c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,7 @@ include (cmake/find_contrib_lib.cmake) find_contrib_lib(cityhash) find_contrib_lib(farmhash) find_contrib_lib(metrohash) +find_contrib_lib(murmurhash2) find_contrib_lib(btrie) find_contrib_lib(double-conversion) diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index e2e4341e1bd..9499d666cdb 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -45,6 +45,10 @@ if (USE_INTERNAL_UNWIND_LIBRARY) add_subdirectory (libunwind) endif () +if (USE_INTERNAL_MURMURHASH2_LIBRARY) + add_subdirectory (libmurmurhash2) +endif () + if (USE_INTERNAL_ZLIB_LIBRARY) add_subdirectory (${INTERNAL_ZLIB_NAME}) # todo: make pull to Dead2/zlib-ng and remove: diff --git a/contrib/libmurmurhash2/CMakeLists.txt b/contrib/libmurmurhash2/CMakeLists.txt new file mode 100644 index 00000000000..0ab0cec45bb --- /dev/null +++ b/contrib/libmurmurhash2/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(murmurhash2 + src/murmurhash2.cpp + include/murmurhash2.h) + +target_include_directories (murmurhash2 PUBLIC include) +target_include_directories (murmurhash2 PUBLIC src) \ No newline at end of file diff --git a/contrib/libmurmurhash2/LICENSE b/contrib/libmurmurhash2/LICENSE new file mode 100644 index 00000000000..87f90d37c67 --- /dev/null +++ b/contrib/libmurmurhash2/LICENSE @@ -0,0 +1 @@ +MurmurHash2 was written by Austin Appleby, and is placed in the publicdomain. The author hereby disclaims copyright to this source code. \ No newline at end of file diff --git a/contrib/libmurmurhash2/README b/contrib/libmurmurhash2/README new file mode 100644 index 00000000000..3323aa03538 --- /dev/null +++ b/contrib/libmurmurhash2/README @@ -0,0 +1,6 @@ +Original URL: https://github.com/aappleby/smhasher + +version: +commit 61a0530f28277f2e850bfc39600ce61d02b518de +authoer aappleby@gmail.com +date 2016-01-09T06:07:17Z \ No newline at end of file diff --git a/contrib/libmurmurhash2/include/murmurhash2.h b/contrib/libmurmurhash2/include/murmurhash2.h new file mode 100644 index 00000000000..e95cf2a4d85 --- /dev/null +++ b/contrib/libmurmurhash2/include/murmurhash2.h @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +#ifndef _MURMURHASH2_H_ +#define _MURMURHASH2_H_ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) && (_MSC_VER < 1600) + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; + +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#endif // !defined(_MSC_VER) + +uint32_t MurmurHash2 (const void * key, int len, uint32_t seed); +uint64_t MurmurHash64A (const void * key, int len, uint64_t seed); +uint64_t MurmurHash64B (const void * key, int len, uint64_t seed); +uint32_t MurmurHash2A (const void * key, int len, uint32_t seed); +uint32_t MurmurHashNeutral2 (const void * key, int len, uint32_t seed); +uint32_t MurmurHashAligned2 (const void * key, int len, uint32_t seed); + +#endif // _MURMURHASH2_H_ + diff --git a/contrib/libmurmurhash2/src/murmurhash2.cpp b/contrib/libmurmurhash2/src/murmurhash2.cpp new file mode 100644 index 00000000000..8a41ba02d98 --- /dev/null +++ b/contrib/libmurmurhash2/src/murmurhash2.cpp @@ -0,0 +1,421 @@ +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +// Note - This code makes a few assumptions about how your machine behaves - + +// 1. We can read a 4-byte value from any address without crashing +// 2. sizeof(int) == 4 + +// And it has a few limitations - + +// 1. It will not work incrementally. +// 2. It will not produce the same results on little-endian and big-endian +// machines. + +#include "murmurhash2.h" + +// Platform-specific functions and macros +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else // defined(_MSC_VER) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif // !defined(_MSC_VER) + + +uint32_t MurmurHash2(const void * key, int len, uint32_t seed) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + const uint32_t m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + + uint32_t h = seed ^ len; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data = reinterpret_cast(key); + + while (len >= 4) + { + uint32_t k = *reinterpret_cast(data); + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + + switch (len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +// MurmurHash2, 64-bit versions, by Austin Appleby + +// The same caveats as 32-bit MurmurHash2 apply here - beware of alignment +// and endian-ness issues if used across multiple platforms. + +// 64-bit hash for 64-bit platforms + +uint64_t MurmurHash64A(const void * key, int len, uint64_t seed) +{ + const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995); + const int r = 47; + + uint64_t h = seed ^ (len * m); + + const uint64_t * data = reinterpret_cast(key); + const uint64_t * end = data + (len/8); + + while (data != end) + { + uint64_t k = *data++; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + const unsigned char * data2 = reinterpret_cast(data); + + switch (len & 7) + { + case 7: h ^= static_cast(data2[6]) << 48; + case 6: h ^= static_cast(data2[5]) << 40; + case 5: h ^= static_cast(data2[4]) << 32; + case 4: h ^= static_cast(data2[3]) << 24; + case 3: h ^= static_cast(data2[2]) << 16; + case 2: h ^= static_cast(data2[1]) << 8; + case 1: h ^= static_cast(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} + + +// 64-bit hash for 32-bit platforms + +uint64_t MurmurHash64B(const void * key, int len, uint64_t seed) +{ + const uint32_t m = 0x5bd1e995; + const int r = 24; + + uint32_t h1 = static_cast(seed) ^ len; + uint32_t h2 = static_cast(seed >> 32); + + const uint32_t * data = reinterpret_cast(key); + + while (len >= 8) + { + uint32_t k1 = *data++; + k1 *= m; k1 ^= k1 >> r; k1 *= m; + h1 *= m; h1 ^= k1; + len -= 4; + + uint32_t k2 = *data++; + k2 *= m; k2 ^= k2 >> r; k2 *= m; + h2 *= m; h2 ^= k2; + len -= 4; + } + + if (len >= 4) + { + uint32_t k1 = *data++; + k1 *= m; k1 ^= k1 >> r; k1 *= m; + h1 *= m; h1 ^= k1; + len -= 4; + } + + switch (len) + { + case 3: h2 ^= reinterpret_cast(data)[2] << 16; + case 2: h2 ^= reinterpret_cast(data)[1] << 8; + case 1: h2 ^= reinterpret_cast(data)[0]; + h2 *= m; + }; + + h1 ^= h2 >> 18; h1 *= m; + h2 ^= h1 >> 22; h2 *= m; + h1 ^= h2 >> 17; h1 *= m; + h2 ^= h1 >> 19; h2 *= m; + + uint64_t h = h1; + + h = (h << 32) | h2; + + return h; +} + +// MurmurHash2A, by Austin Appleby + +// This is a variant of MurmurHash2 modified to use the Merkle-Damgard +// construction. Bulk speed should be identical to Murmur2, small-key speed +// will be 10%-20% slower due to the added overhead at the end of the hash. + +// This variant fixes a minor issue where null keys were more likely to +// collide with each other than expected, and also makes the function +// more amenable to incremental implementations. + +#define mmix(h,k) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } + +uint32_t MurmurHash2A(const void * key, int len, uint32_t seed) +{ + const uint32_t m = 0x5bd1e995; + const int r = 24; + uint32_t l = len; + + const unsigned char * data = reinterpret_cast(key); + + uint32_t h = seed; + + while (len >= 4) + { + uint32_t k = *reinterpret_cast(data); + mmix(h,k); + data += 4; + len -= 4; + } + + uint32_t t = 0; + + switch (len) + { + case 3: t ^= data[2] << 16; + case 2: t ^= data[1] << 8; + case 1: t ^= data[0]; + }; + + mmix(h,t); + mmix(h,l); + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +// MurmurHashNeutral2, by Austin Appleby + +// Same as MurmurHash2, but endian- and alignment-neutral. +// Half the speed though, alas. + +uint32_t MurmurHashNeutral2(const void * key, int len, uint32_t seed) +{ + const uint32_t m = 0x5bd1e995; + const int r = 24; + + uint32_t h = seed ^ len; + + const unsigned char * data = reinterpret_cast(key); + + while (len >= 4) + { + uint32_t k; + + k = data[0]; + k |= data[1] << 8; + k |= data[2] << 16; + k |= data[3] << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + switch (len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +//----------------------------------------------------------------------------- +// MurmurHashAligned2, by Austin Appleby + +// Same algorithm as MurmurHash2, but only does aligned reads - should be safer +// on certain platforms. + +// Performance will be lower than MurmurHash2 + +#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } + + +uint32_t MurmurHashAligned2(const void * key, int len, uint32_t seed) +{ + const uint32_t m = 0x5bd1e995; + const int r = 24; + + const unsigned char * data = reinterpret_cast(key); + + uint32_t h = seed ^ len; + + int align = reinterpret_cast(data) & 3; + + if (align && (len >= 4)) + { + // Pre-load the temp registers + + uint32_t t = 0, d = 0; + + switch (align) + { + case 1: t |= data[2] << 16; + case 2: t |= data[1] << 8; + case 3: t |= data[0]; + } + + t <<= (8 * align); + + data += 4-align; + len -= 4-align; + + int sl = 8 * (4-align); + int sr = 8 * align; + + // Mix + + while (len >= 4) + { + d = *(reinterpret_cast(data)); + t = (t >> sr) | (d << sl); + + uint32_t k = t; + + MIX(h,k,m); + + t = d; + + data += 4; + len -= 4; + } + + // Handle leftover data in temp registers + + d = 0; + + if (len >= align) + { + switch (align) + { + case 3: d |= data[2] << 16; + case 2: d |= data[1] << 8; + case 1: d |= data[0]; + } + + uint32_t k = (t >> sr) | (d << sl); + MIX(h,k,m); + + data += align; + len -= align; + + //---------- + // Handle tail bytes + + switch (len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + } + else + { + switch (len) + { + case 3: d |= data[2] << 16; + case 2: d |= data[1] << 8; + case 1: d |= data[0]; + case 0: h ^= (t >> sr) | (d << sl); + h *= m; + } + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } + else + { + while (len >= 4) + { + uint32_t k = *reinterpret_cast(data); + + MIX(h,k,m); + + data += 4; + len -= 4; + } + + // Handle tail bytes + + switch (len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } +} \ No newline at end of file diff --git a/dbms/src/Functions/CMakeLists.txt b/dbms/src/Functions/CMakeLists.txt index 6856cb95cf2..81b6c46eb79 100644 --- a/dbms/src/Functions/CMakeLists.txt +++ b/dbms/src/Functions/CMakeLists.txt @@ -91,7 +91,7 @@ list(REMOVE_ITEM clickhouse_functions_headers IFunction.h FunctionFactory.h Func add_library(clickhouse_functions ${clickhouse_functions_sources}) -target_link_libraries(clickhouse_functions PUBLIC dbms PRIVATE libconsistent-hashing ${FARMHASH_LIBRARIES} ${METROHASH_LIBRARIES}) +target_link_libraries(clickhouse_functions PUBLIC dbms PRIVATE libconsistent-hashing ${FARMHASH_LIBRARIES} ${METROHASH_LIBRARIES} ${MURMURHASH2_LIBRARIES}) target_include_directories (clickhouse_functions SYSTEM BEFORE PUBLIC ${DIVIDE_INCLUDE_DIR}) diff --git a/dbms/src/Functions/FunctionsHashing.cpp b/dbms/src/Functions/FunctionsHashing.cpp index 2aca07e477d..3b0a1c5d872 100644 --- a/dbms/src/Functions/FunctionsHashing.cpp +++ b/dbms/src/Functions/FunctionsHashing.cpp @@ -20,6 +20,7 @@ void registerFunctionsHashing(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + factory.registerFunction(); } template <> diff --git a/dbms/src/Functions/FunctionsHashing.h b/dbms/src/Functions/FunctionsHashing.h index 86d5274b881..5f558520295 100644 --- a/dbms/src/Functions/FunctionsHashing.h +++ b/dbms/src/Functions/FunctionsHashing.h @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -143,6 +144,7 @@ struct SipHash64Impl } }; + struct SipHash128Impl { static constexpr auto name = "sipHash128"; @@ -366,7 +368,6 @@ UInt64 toInteger(Float32 x); template <> UInt64 toInteger(Float64 x); - /** We use hash functions called CityHash, FarmHash, MetroHash. * In this regard, this template is named with the words `NeighborhoodHash`. */ @@ -614,6 +615,179 @@ public: }; +template +class FunctionStringHash32 : public IFunction +{ +public: + static constexpr auto name = Impl::name; + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override { return name; } + + bool isVariadic() const override { return false; } + + size_t getNumberOfArguments() const override { return 1; } + + DataTypePtr getReturnTypeImpl(const DataTypes & /* arguments */) const override { return std::make_shared(); } + + bool useDefaultImplementationForConstants() const override { return true; } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + size_t rows = input_rows_count; + auto col_to = ColumnUInt32::create(rows); + + ColumnUInt32::Container & vec_to = col_to->getData(); + + if (arguments.empty()) + { + /// Constant random number from /dev/urandom is used as a hash value of empty list of arguments. + vec_to.assign(rows, static_cast(0xe28dbde7fe22e41c)); + } + + /// The function supports arbitary number of arguments of arbitary types. + + for (size_t i = 0; i < arguments.size(); ++i) + { + const ColumnWithTypeAndName & col = block.getByPosition(arguments[i]); + executeForArgument(col.type.get(), col.column.get(), vec_to); + } + + block.getByPosition(result).column = std::move(col_to); + } +private: + + void executeAny(const IDataType * from_type, const IColumn * icolumn, ColumnUInt32::Container & vec_to) + { + if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); + else if (checkDataType(from_type)) executeString(icolumn, vec_to); + else if (checkDataType(from_type)) executeString(icolumn, vec_to); + else + throw Exception("Unexpected type " + from_type->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + template + void executeIntType(const IColumn * column, ColumnUInt32::Container & vec_to) + { + if (const ColumnVector * col_from = checkAndGetColumn>(column)) + { + const typename ColumnVector::Container & vec_from = col_from->getData(); + size_t size = vec_from.size(); + for (size_t i = 0; i < size; ++i) + { + vec_to[i] = IntHash32Impl::apply(toInteger(vec_from[i])); + } + } + else if (auto col_from = checkAndGetColumnConst>(column)) + { + size_t size = vec_to.size(); + for (size_t i = 0; i < size; ++i) + vec_to[i] = IntHash32Impl::apply(toInteger(col_from->template getValue())); + } + else + throw Exception("Illegal column " + column->getName() + + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + + void executeString(const IColumn * column, ColumnUInt32::Container & vec_to) + { + if (const ColumnString * col_from = checkAndGetColumn(column)) + { + const typename ColumnString::Chars_t & data = col_from->getChars(); + const typename ColumnString::Offsets & offsets = col_from->getOffsets(); + size_t size = offsets.size(); + + for (size_t i = 0; i < size; ++i) + { + vec_to[i] = Impl::Hash32( + reinterpret_cast(&data[i == 0 ? 0 : offsets[i - 1]]), + i == 0 ? offsets[i] - 1 : (offsets[i] - 1 - offsets[i - 1])); + } + } + else if (const ColumnFixedString * col_from = checkAndGetColumn(column)) + { + const typename ColumnString::Chars_t & data = col_from->getChars(); + size_t n = col_from->getN(); + size_t size = data.size() / n; + for (size_t i = 0; i < size; ++i) + vec_to[i] = Impl::Hash32(reinterpret_cast(&data[i * n]), n); + } + else if (const ColumnConst * col_from = checkAndGetColumnConstStringOrFixedString(column)) + { + String value = col_from->getValue().data(); + const size_t size = vec_to.size(); + for (size_t i = 0; i < size; ++i) + vec_to[i] = Impl::Hash32(value.data(), value.size()); + } + else + throw Exception("Illegal column " + column->getName() + + " of first argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + + /// Flattening of tuples. + void executeForArgument(const IDataType * type, const IColumn * column, ColumnUInt32::Container & vec_to) + { + /// Flattening of tuples. + if (const ColumnTuple * tuple = typeid_cast(column)) + { + const Columns & tuple_columns = tuple->getColumns(); + const DataTypes & tuple_types = typeid_cast(*type).getElements(); + size_t tuple_size = tuple_columns.size(); + for (size_t i = 0; i < tuple_size; ++i) + executeForArgument(tuple_types[i].get(), tuple_columns[i].get(), vec_to); + } + else if (const ColumnTuple * tuple = checkAndGetColumnConstData(column)) + { + const Columns & tuple_columns = tuple->getColumns(); + const DataTypes & tuple_types = typeid_cast(*type).getElements(); + size_t tuple_size = tuple_columns.size(); + for (size_t i = 0; i < tuple_size; ++i) + { + auto tmp = ColumnConst::create(tuple_columns[i], column->size()); + executeForArgument(tuple_types[i].get(), tmp.get(), vec_to); + } + } + else + { + executeAny(type, column, vec_to); + } + } +}; + + +/** Why we need MurmurHash2? +* MurmurHash2 is an outdated hash function, superseded by MurmurHash3 and subsequently by CityHash, xxHash, HighwayHash. +* Usually there is no reason to use MurmurHash. +* It is needed for the cases when you already have MurmurHash in some applications and you want to reproduce it +* in ClickHouse as is. For example, it is needed to reproduce the behaviour +* for NGINX a/b testing module: https://nginx.ru/en/docs/http/ngx_http_split_clients_module.html +*/ +struct MurmurHash2Impl +{ + static constexpr auto name = "murmurHash2"; + static UInt32 Hash32(const char * data, const size_t size) + { + return MurmurHash2(data, size, 0); + } +}; + + struct URLHashImpl { static UInt64 apply(const char * data, const size_t size) @@ -848,5 +1022,5 @@ using FunctionSipHash128 = FunctionStringHashFixedString; using FunctionCityHash64 = FunctionNeighbourhoodHash64; using FunctionFarmHash64 = FunctionNeighbourhoodHash64; using FunctionMetroHash64 = FunctionNeighbourhoodHash64; - -} +using MurmurHash2 = FunctionStringHash32; +} \ No newline at end of file From d45ce92b8978c956bada5287978b9dc5dabe0b0b Mon Sep 17 00:00:00 2001 From: ap11 Date: Mon, 30 Jul 2018 16:41:07 +0300 Subject: [PATCH 215/425] add tests for murmurhash2 --- dbms/src/Functions/FunctionsHashing.h | 75 ++----------------- .../0_stateless/00678_murmurhash2.reference | 7 ++ .../queries/0_stateless/00678_murmurhash2.sql | 9 +++ 3 files changed, 24 insertions(+), 67 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00678_murmurhash2.reference create mode 100644 dbms/tests/queries/0_stateless/00678_murmurhash2.sql diff --git a/dbms/src/Functions/FunctionsHashing.h b/dbms/src/Functions/FunctionsHashing.h index 5f558520295..7307a1aae62 100644 --- a/dbms/src/Functions/FunctionsHashing.h +++ b/dbms/src/Functions/FunctionsHashing.h @@ -634,31 +634,13 @@ public: void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override { - size_t rows = input_rows_count; - auto col_to = ColumnUInt32::create(rows); - + auto col_to = ColumnUInt32::create(input_rows_count); ColumnUInt32::Container & vec_to = col_to->getData(); - if (arguments.empty()) - { - /// Constant random number from /dev/urandom is used as a hash value of empty list of arguments. - vec_to.assign(rows, static_cast(0xe28dbde7fe22e41c)); - } + const ColumnWithTypeAndName & col = block.getByPosition(arguments[0]); + const IDataType * from_type = col.type.get(); + const IColumn * icolumn = col.column.get(); - /// The function supports arbitary number of arguments of arbitary types. - - for (size_t i = 0; i < arguments.size(); ++i) - { - const ColumnWithTypeAndName & col = block.getByPosition(arguments[i]); - executeForArgument(col.type.get(), col.column.get(), vec_to); - } - - block.getByPosition(result).column = std::move(col_to); - } -private: - - void executeAny(const IDataType * from_type, const IColumn * icolumn, ColumnUInt32::Container & vec_to) - { if (checkDataType(from_type)) executeIntType(icolumn, vec_to); else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); else if (checkDataType(from_type)) executeIntType(icolumn, vec_to); @@ -678,8 +660,10 @@ private: else throw Exception("Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - } + block.getByPosition(result).column = std::move(col_to); + } +private: template void executeIntType(const IColumn * column, ColumnUInt32::Container & vec_to) { @@ -689,15 +673,9 @@ private: size_t size = vec_from.size(); for (size_t i = 0; i < size; ++i) { - vec_to[i] = IntHash32Impl::apply(toInteger(vec_from[i])); + vec_to[i] = Impl::Hash32(reinterpret_cast(&vec_from[i]), sizeof(FromType)); } } - else if (auto col_from = checkAndGetColumnConst>(column)) - { - size_t size = vec_to.size(); - for (size_t i = 0; i < size; ++i) - vec_to[i] = IntHash32Impl::apply(toInteger(col_from->template getValue())); - } else throw Exception("Illegal column " + column->getName() + " of argument of function " + getName(), @@ -711,7 +689,6 @@ private: const typename ColumnString::Chars_t & data = col_from->getChars(); const typename ColumnString::Offsets & offsets = col_from->getOffsets(); size_t size = offsets.size(); - for (size_t i = 0; i < size; ++i) { vec_to[i] = Impl::Hash32( @@ -727,47 +704,11 @@ private: for (size_t i = 0; i < size; ++i) vec_to[i] = Impl::Hash32(reinterpret_cast(&data[i * n]), n); } - else if (const ColumnConst * col_from = checkAndGetColumnConstStringOrFixedString(column)) - { - String value = col_from->getValue().data(); - const size_t size = vec_to.size(); - for (size_t i = 0; i < size; ++i) - vec_to[i] = Impl::Hash32(value.data(), value.size()); - } else throw Exception("Illegal column " + column->getName() + " of first argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); } - - /// Flattening of tuples. - void executeForArgument(const IDataType * type, const IColumn * column, ColumnUInt32::Container & vec_to) - { - /// Flattening of tuples. - if (const ColumnTuple * tuple = typeid_cast(column)) - { - const Columns & tuple_columns = tuple->getColumns(); - const DataTypes & tuple_types = typeid_cast(*type).getElements(); - size_t tuple_size = tuple_columns.size(); - for (size_t i = 0; i < tuple_size; ++i) - executeForArgument(tuple_types[i].get(), tuple_columns[i].get(), vec_to); - } - else if (const ColumnTuple * tuple = checkAndGetColumnConstData(column)) - { - const Columns & tuple_columns = tuple->getColumns(); - const DataTypes & tuple_types = typeid_cast(*type).getElements(); - size_t tuple_size = tuple_columns.size(); - for (size_t i = 0; i < tuple_size; ++i) - { - auto tmp = ColumnConst::create(tuple_columns[i], column->size()); - executeForArgument(tuple_types[i].get(), tmp.get(), vec_to); - } - } - else - { - executeAny(type, column, vec_to); - } - } }; diff --git a/dbms/tests/queries/0_stateless/00678_murmurhash2.reference b/dbms/tests/queries/0_stateless/00678_murmurhash2.reference new file mode 100644 index 00000000000..102eed1f47e --- /dev/null +++ b/dbms/tests/queries/0_stateless/00678_murmurhash2.reference @@ -0,0 +1,7 @@ +3012058918 +1298551497 +864444010 +3759658061 +2414502773 +670491991 +1343103100 diff --git a/dbms/tests/queries/0_stateless/00678_murmurhash2.sql b/dbms/tests/queries/0_stateless/00678_murmurhash2.sql new file mode 100644 index 00000000000..7f8c4d0069f --- /dev/null +++ b/dbms/tests/queries/0_stateless/00678_murmurhash2.sql @@ -0,0 +1,9 @@ +SELECT murmurHash2(123456); +SELECT murmurHash2(CAST(3 AS UInt8)); +SELECT murmurHash2(CAST(1.2684 AS Float32)); +SELECT murmurHash2(CAST(-154477 AS Int64)); +SELECT murmurHash2('foo'); +SELECT murmurHash2(CAST('bar' AS FixedString(3))); +SELECT murmurHash2(x) FROM (SELECT CAST(1 AS Enum8('a' = 1, 'b' = 2)) as x); + + From 3a35ebd90e640f65de6a334ee43dfdd9fe0ef36e Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Mon, 30 Jul 2018 16:46:28 +0300 Subject: [PATCH 216/425] Update README --- contrib/libmurmurhash2/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/libmurmurhash2/README b/contrib/libmurmurhash2/README index 3323aa03538..92e5f7afe94 100644 --- a/contrib/libmurmurhash2/README +++ b/contrib/libmurmurhash2/README @@ -3,4 +3,4 @@ Original URL: https://github.com/aappleby/smhasher version: commit 61a0530f28277f2e850bfc39600ce61d02b518de authoer aappleby@gmail.com -date 2016-01-09T06:07:17Z \ No newline at end of file +date 2016-01-09T06:07:17Z From f6457929b60494cb492e18c7eda0b598a0659730 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Mon, 30 Jul 2018 16:47:04 +0300 Subject: [PATCH 217/425] Update LICENSE --- contrib/libmurmurhash2/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/libmurmurhash2/LICENSE b/contrib/libmurmurhash2/LICENSE index 87f90d37c67..e4f5d0c2f40 100644 --- a/contrib/libmurmurhash2/LICENSE +++ b/contrib/libmurmurhash2/LICENSE @@ -1 +1 @@ -MurmurHash2 was written by Austin Appleby, and is placed in the publicdomain. The author hereby disclaims copyright to this source code. \ No newline at end of file +MurmurHash2 was written by Austin Appleby, and is placed in the publicdomain. The author hereby disclaims copyright to this source code. From c4fec0521e3301f86cdce112a4a05a5e740964eb Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Mon, 30 Jul 2018 16:47:25 +0300 Subject: [PATCH 218/425] Update CMakeLists.txt --- contrib/libmurmurhash2/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/libmurmurhash2/CMakeLists.txt b/contrib/libmurmurhash2/CMakeLists.txt index 0ab0cec45bb..d298f167ac6 100644 --- a/contrib/libmurmurhash2/CMakeLists.txt +++ b/contrib/libmurmurhash2/CMakeLists.txt @@ -3,4 +3,4 @@ add_library(murmurhash2 include/murmurhash2.h) target_include_directories (murmurhash2 PUBLIC include) -target_include_directories (murmurhash2 PUBLIC src) \ No newline at end of file +target_include_directories (murmurhash2 PUBLIC src) From ef443b2bc560b4fcd7be22fd4149bac6873cafc1 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Mon, 30 Jul 2018 16:48:44 +0300 Subject: [PATCH 219/425] Update FunctionsHashing.h --- dbms/src/Functions/FunctionsHashing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Functions/FunctionsHashing.h b/dbms/src/Functions/FunctionsHashing.h index 7307a1aae62..9a3e2b849de 100644 --- a/dbms/src/Functions/FunctionsHashing.h +++ b/dbms/src/Functions/FunctionsHashing.h @@ -964,4 +964,4 @@ using FunctionCityHash64 = FunctionNeighbourhoodHash64; using FunctionFarmHash64 = FunctionNeighbourhoodHash64; using FunctionMetroHash64 = FunctionNeighbourhoodHash64; using MurmurHash2 = FunctionStringHash32; -} \ No newline at end of file +} From 4fe3690caddc5661f2ae044973dfe5078f40efa2 Mon Sep 17 00:00:00 2001 From: ap11 Date: Mon, 30 Jul 2018 16:50:26 +0300 Subject: [PATCH 220/425] minor changes --- dbms/src/Functions/FunctionsHashing.cpp | 2 +- dbms/src/Functions/FunctionsHashing.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Functions/FunctionsHashing.cpp b/dbms/src/Functions/FunctionsHashing.cpp index 3b0a1c5d872..3e26439cc75 100644 --- a/dbms/src/Functions/FunctionsHashing.cpp +++ b/dbms/src/Functions/FunctionsHashing.cpp @@ -20,7 +20,7 @@ void registerFunctionsHashing(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); - factory.registerFunction(); + factory.registerFunction(); } template <> diff --git a/dbms/src/Functions/FunctionsHashing.h b/dbms/src/Functions/FunctionsHashing.h index 7307a1aae62..cdac770518d 100644 --- a/dbms/src/Functions/FunctionsHashing.h +++ b/dbms/src/Functions/FunctionsHashing.h @@ -963,5 +963,5 @@ using FunctionSipHash128 = FunctionStringHashFixedString; using FunctionCityHash64 = FunctionNeighbourhoodHash64; using FunctionFarmHash64 = FunctionNeighbourhoodHash64; using FunctionMetroHash64 = FunctionNeighbourhoodHash64; -using MurmurHash2 = FunctionStringHash32; -} \ No newline at end of file +using FunctionMurmurHash2 = FunctionStringHash32; +} From 71694f0eb2398f1a3c6fd66b6fbbc1a5fba250ed Mon Sep 17 00:00:00 2001 From: alesapin Date: Mon, 30 Jul 2018 17:03:29 +0300 Subject: [PATCH 221/425] Add tag in PostgreSQL external dictionary config --- .../dicts/external_dicts_dict_sources.md | 58 ++++++++++--------- .../dicts/external_dicts_dict_sources.md | 58 ++++++++++--------- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/docs/en/query_language/dicts/external_dicts_dict_sources.md b/docs/en/query_language/dicts/external_dicts_dict_sources.md index 9a4cf5f0dc0..b60176c13fd 100644 --- a/docs/en/query_language/dicts/external_dicts_dict_sources.md +++ b/docs/en/query_language/dicts/external_dicts_dict_sources.md @@ -156,34 +156,36 @@ Configuring `/etc/odbc.ini` (or `~/.odbc.ini`): The dictionary configuration in ClickHouse: ```xml - - table_name - - - - - DSN=myconnection - postgresql_table
-
- - - 300 - 360 - - - - - - - id - - - some_column - UInt64 - 0 - - -
+ + + table_name + + + + + DSN=myconnection + postgresql_table
+
+ + + 300 + 360 + + + + + + + id + + + some_column + UInt64 + 0 + + +
+
``` You may need to edit `odbc.ini` to specify the full path to the library with the driver `DRIVER=/usr/local/lib/psqlodbcw.so`. diff --git a/docs/ru/query_language/dicts/external_dicts_dict_sources.md b/docs/ru/query_language/dicts/external_dicts_dict_sources.md index 3e30cfba845..2cb4754b934 100644 --- a/docs/ru/query_language/dicts/external_dicts_dict_sources.md +++ b/docs/ru/query_language/dicts/external_dicts_dict_sources.md @@ -156,34 +156,36 @@ Конфигурация словаря в ClickHouse: ```xml - - table_name - - - - - DSN=myconnection - postgresql_table
-
- - - 300 - 360 - - - - - - - id - - - some_column - UInt64 - 0 - - -
+ + + table_name + + + + + DSN=myconnection + postgresql_table
+
+ + + 300 + 360 + + + + + + + id + + + some_column + UInt64 + 0 + + +
+
``` Может понадобиться в `odbc.ini` указать полный путь до библиотеки с драйвером `DRIVER=/usr/local/lib/psqlodbcw.so`. From 793e0d3901b9c799ab292f6063f83a66bac5f00a Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 30 Jul 2018 18:41:41 +0300 Subject: [PATCH 222/425] Update README --- contrib/libmurmurhash2/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/libmurmurhash2/README b/contrib/libmurmurhash2/README index 92e5f7afe94..5428d30b26d 100644 --- a/contrib/libmurmurhash2/README +++ b/contrib/libmurmurhash2/README @@ -2,5 +2,5 @@ Original URL: https://github.com/aappleby/smhasher version: commit 61a0530f28277f2e850bfc39600ce61d02b518de -authoer aappleby@gmail.com +author aappleby@gmail.com date 2016-01-09T06:07:17Z From b062262b9fbf04f0b4957ff4124a2a6a6fae7c4a Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 30 Jul 2018 18:45:46 +0300 Subject: [PATCH 223/425] Update FunctionsHashing.h --- dbms/src/Functions/FunctionsHashing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Functions/FunctionsHashing.h b/dbms/src/Functions/FunctionsHashing.h index cdac770518d..cdaa2fe1fd4 100644 --- a/dbms/src/Functions/FunctionsHashing.h +++ b/dbms/src/Functions/FunctionsHashing.h @@ -721,7 +721,7 @@ private: */ struct MurmurHash2Impl { - static constexpr auto name = "murmurHash2"; + static constexpr auto name = "murmurHash2_32"; static UInt32 Hash32(const char * data, const size_t size) { return MurmurHash2(data, size, 0); From 45ce69e73d5643f73fbb51fea1c477032545926f Mon Sep 17 00:00:00 2001 From: ap11 Date: Mon, 30 Jul 2018 12:36:27 +0300 Subject: [PATCH 224/425] Add case insensitive coalesce ifnull, nullif. --- dbms/src/Functions/FunctionsNull.cpp | 6 +++--- dbms/tests/queries/0_stateless/00433_ifnull.reference | 5 +++++ dbms/tests/queries/0_stateless/00433_ifnull.sql | 2 ++ dbms/tests/queries/0_stateless/00435_coalesce.reference | 1 + dbms/tests/queries/0_stateless/00435_coalesce.sql | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/dbms/src/Functions/FunctionsNull.cpp b/dbms/src/Functions/FunctionsNull.cpp index af2831db383..979c92823ff 100644 --- a/dbms/src/Functions/FunctionsNull.cpp +++ b/dbms/src/Functions/FunctionsNull.cpp @@ -19,9 +19,9 @@ void registerFunctionsNull(FunctionFactory & factory) { factory.registerFunction(); factory.registerFunction(); - factory.registerFunction(); - factory.registerFunction(); - factory.registerFunction(); + factory.registerFunction(FunctionFactory::CaseInsensitive); + factory.registerFunction(FunctionFactory::CaseInsensitive); + factory.registerFunction(FunctionFactory::CaseInsensitive); factory.registerFunction(); factory.registerFunction(); } diff --git a/dbms/tests/queries/0_stateless/00433_ifnull.reference b/dbms/tests/queries/0_stateless/00433_ifnull.reference index c1a59dec60e..4cf982b2116 100644 --- a/dbms/tests/queries/0_stateless/00433_ifnull.reference +++ b/dbms/tests/queries/0_stateless/00433_ifnull.reference @@ -28,3 +28,8 @@ x Nullable(String) 1 UInt8 1 UInt8 \N Nullable(Nothing) +0 Nullable(String) +-1 Nullable(String) +2 Nullable(String) +3 Nullable(String) +4 Nullable(String) diff --git a/dbms/tests/queries/0_stateless/00433_ifnull.sql b/dbms/tests/queries/0_stateless/00433_ifnull.sql index cad3eeba534..9071305a87a 100644 --- a/dbms/tests/queries/0_stateless/00433_ifnull.sql +++ b/dbms/tests/queries/0_stateless/00433_ifnull.sql @@ -17,3 +17,5 @@ SELECT ifNull(nullIf(toString(number), '1'), nullIf(toString(-number), '-3')) AS SELECT ifNull(NULL, 1) AS res, toTypeName(res); SELECT ifNull(1, NULL) AS res, toTypeName(res); SELECT ifNull(NULL, NULL) AS res, toTypeName(res); + +SELECT IFNULL(NULLIF(toString(number), '1'), NULLIF(toString(-number), '-3')) AS res, toTypeName(res) FROM system.numbers LIMIT 5; diff --git a/dbms/tests/queries/0_stateless/00435_coalesce.reference b/dbms/tests/queries/0_stateless/00435_coalesce.reference index 20b8288b09c..b236c89c865 100644 --- a/dbms/tests/queries/0_stateless/00435_coalesce.reference +++ b/dbms/tests/queries/0_stateless/00435_coalesce.reference @@ -1,4 +1,5 @@ \N \N \N 1 1 1 1 +\N \N 1 0 Nullable(UInt64) \N Nullable(UInt64) 2 Nullable(UInt64) diff --git a/dbms/tests/queries/0_stateless/00435_coalesce.sql b/dbms/tests/queries/0_stateless/00435_coalesce.sql index 7c1c519bcb2..3744f5ff290 100644 --- a/dbms/tests/queries/0_stateless/00435_coalesce.sql +++ b/dbms/tests/queries/0_stateless/00435_coalesce.sql @@ -1,6 +1,8 @@ SELECT coalesce(), coalesce(NULL), coalesce(NULL, NULL), coalesce(1), coalesce(1, NULL), coalesce(NULL, 1), coalesce(NULL, 1, NULL); +SELECT COALESCE(), COALESCE(NULL), COALESCE(1, NULL); + SELECT coalesce(number % 2 = 0 ? number : NULL, number % 3 = 0 ? number : NULL, number % 5 = 0 ? number : NULL) AS res, toTypeName(res) FROM system.numbers LIMIT 15; SELECT coalesce(number % 2 = 0 ? number : NULL, number % 3 = 0 ? number : NULL, number) AS res, toTypeName(res) FROM system.numbers LIMIT 15; SELECT coalesce(number % 2 = 0 ? number : NULL, number % 3 = 0 ? number : NULL, 100) AS res, toTypeName(res) FROM system.numbers LIMIT 15; From 9e052b13d10ace738913a4c69ecf7552102cb018 Mon Sep 17 00:00:00 2001 From: zhang2014 Date: Mon, 30 Jul 2018 15:28:58 +0800 Subject: [PATCH 225/425] ISSUES-2700 add funnel window crash test --- .../0_stateless/00678_shard_funnel_window.reference | 3 +++ .../queries/0_stateless/00678_shard_funnel_window.sql | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00678_shard_funnel_window.reference create mode 100644 dbms/tests/queries/0_stateless/00678_shard_funnel_window.sql diff --git a/dbms/tests/queries/0_stateless/00678_shard_funnel_window.reference b/dbms/tests/queries/0_stateless/00678_shard_funnel_window.reference new file mode 100644 index 00000000000..a36d5b17632 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00678_shard_funnel_window.reference @@ -0,0 +1,3 @@ +1 10000 +1 10000 +1 10000 diff --git a/dbms/tests/queries/0_stateless/00678_shard_funnel_window.sql b/dbms/tests/queries/0_stateless/00678_shard_funnel_window.sql new file mode 100644 index 00000000000..e2405bcbc92 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00678_shard_funnel_window.sql @@ -0,0 +1,7 @@ +DROP TABLE IF EXISTS test.remote_test; +CREATE TABLE test.remote_test(uid String, its UInt32, action_code String, day Date) ENGINE = MergeTree(day, (uid, its), 8192); +INSERT INTO test.remote_test SELECT toString(number) AS uid, number % 3 AS its, toString(number % 3) AS action_code, '2000-01-01' FROM system.numbers LIMIT 10000; +SELECT level, COUNT() FROM (SELECT uid, windowFunnel(3600)(toUInt32(its), action_code != '', action_code = '2') AS level FROM remote('127.0.0.{2,3}', test.remote_test) GROUP BY uid) GROUP BY level; +SELECT level, COUNT() FROM (SELECT uid, windowFunnel(3600)(toUInt32(its), action_code != '', action_code = '2') AS level FROM remote('127.0.0.{2,3}', test.remote_test) GROUP BY uid) GROUP BY level; +SELECT level, COUNT() FROM (SELECT uid, windowFunnel(3600)(toUInt32(its), action_code != '', action_code = '2') AS level FROM remote('127.0.0.{2,3}', test.remote_test) GROUP BY uid) GROUP BY level; +DROP TABLE IF EXISTS test.remote_test; From 115ff2d7311129ac6c26090c5cb360ea81f81df7 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Mon, 30 Jul 2018 18:59:03 +0300 Subject: [PATCH 226/425] Fixed error in website [#CLICKHOUSE-3] --- website/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/index.html b/website/index.html index 8d2ed3ec7ce..bf92f9fe01c 100644 --- a/website/index.html +++ b/website/index.html @@ -390,7 +390,7 @@
 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E0C56BD4    # optional
 
-sudo echo "deb http://repo.yandex.ru/clickhouse/deb/stable/ main/" > /etc/apt/sources.list.d/clickhouse.list
+echo "deb http://repo.yandex.ru/clickhouse/deb/stable/ main/" | sudo tee /etc/apt/sources.list.d/clickhouse.list
 sudo apt-get update
 
 sudo apt-get install -y clickhouse-server clickhouse-client

From 7fe1914a635b99ce311d9ddf766d7d3cfe859f93 Mon Sep 17 00:00:00 2001
From: Alexey Milovidov 
Date: Mon, 30 Jul 2018 19:07:20 +0300
Subject: [PATCH 227/425] Whitespaces #2756

---
 dbms/src/Functions/FunctionsHashing.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/dbms/src/Functions/FunctionsHashing.h b/dbms/src/Functions/FunctionsHashing.h
index cdaa2fe1fd4..2a4f3196b5f 100644
--- a/dbms/src/Functions/FunctionsHashing.h
+++ b/dbms/src/Functions/FunctionsHashing.h
@@ -708,23 +708,23 @@ private:
             throw Exception("Illegal column " + column->getName()
                     + " of first argument of function " + getName(),
                 ErrorCodes::ILLEGAL_COLUMN);
-    }  
+    }
 };
 
 
 /** Why we need MurmurHash2?
-*   MurmurHash2 is an outdated hash function, superseded by MurmurHash3 and subsequently by CityHash, xxHash, HighwayHash. 
-*   Usually there is no reason to use MurmurHash.
-*   It is needed for the cases when you already have MurmurHash in some applications and you want to reproduce it 
-*   in ClickHouse as is. For example, it is needed to reproduce the behaviour 
-*   for NGINX a/b testing module: https://nginx.ru/en/docs/http/ngx_http_split_clients_module.html
-*/
+  * MurmurHash2 is an outdated hash function, superseded by MurmurHash3 and subsequently by CityHash, xxHash, HighwayHash.
+  * Usually there is no reason to use MurmurHash.
+  * It is needed for the cases when you already have MurmurHash in some applications and you want to reproduce it
+  * in ClickHouse as is. For example, it is needed to reproduce the behaviour
+  * for NGINX a/b testing module: https://nginx.ru/en/docs/http/ngx_http_split_clients_module.html
+  */
 struct MurmurHash2Impl
 {
     static constexpr auto name = "murmurHash2_32";
-    static UInt32 Hash32(const char * data, const size_t size) 
+    static UInt32 Hash32(const char * data, const size_t size)
     {
-        return MurmurHash2(data, size, 0);  
+        return MurmurHash2(data, size, 0);
     }
 };
 

From b589903680e359781b410eb1e13a43c01f2e67fa Mon Sep 17 00:00:00 2001
From: Ivan Blinkov 
Date: Mon, 30 Jul 2018 19:34:55 +0300
Subject: [PATCH 228/425] WIP on docs (#2753)

* Some improvements for introduction/performance.md

* Minor improvements for example_datasets

* Add website/package-lock.json to .gitignore

* YT paragraph was badly outdated and there is no real reason to write a new one

* Use weird introduction article as a starting point for F.A.Q.

* Some refactoring of first half of ya_metrika_task.md

* minor

* Weird docs footer bugfix
---
 .gitignore                                     |  1 +
 docs/en/faq/general.md                         | 12 ++++++++++++
 .../example_datasets/nyc_taxi.md               | 11 +++++------
 .../getting_started/example_datasets/ontime.md | 18 +++++++++---------
 .../features_considered_disadvantages.md       |  2 +-
 docs/en/introduction/performance.md            | 12 +++++++-----
 .../introduction/possible_silly_questions.md   | 15 ---------------
 docs/en/introduction/ya_metrika_task.md        |  7 ++++---
 docs/ru/faq/general.md                         | 12 ++++++++++++
 .../example_datasets/nyc_taxi.md               | 11 +++++------
 .../getting_started/example_datasets/ontime.md | 18 +++++++++---------
 docs/ru/introduction/performance.md            |  8 +++++---
 .../introduction/possible_silly_questions.md   | 14 --------------
 docs/ru/introduction/ya_metrika_task.md        |  7 ++++---
 docs/toc_en.yml                                |  6 ++++--
 docs/toc_ru.yml                                |  6 ++++--
 .../mkdocs-material-theme/partials/footer.html |  4 ++--
 17 files changed, 84 insertions(+), 80 deletions(-)
 create mode 100644 docs/en/faq/general.md
 delete mode 100644 docs/en/introduction/possible_silly_questions.md
 create mode 100644 docs/ru/faq/general.md
 delete mode 100644 docs/ru/introduction/possible_silly_questions.md

diff --git a/.gitignore b/.gitignore
index 59a2d633361..291eb35c67a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -241,5 +241,6 @@ node_modules
 public
 website/docs
 website/presentations
+website/package-lock.json
 .DS_Store
 */.DS_Store
diff --git a/docs/en/faq/general.md b/docs/en/faq/general.md
new file mode 100644
index 00000000000..64267c12625
--- /dev/null
+++ b/docs/en/faq/general.md
@@ -0,0 +1,12 @@
+# General questions
+
+## Why not use something like MapReduce?
+
+We can refer to systems like MapReduce as distributed computing systems in which the reduce operation is based on a distributed sort. The most common opensource solution of this kind is [Apache Hadoop](http://hadoop.apache.org), while Yandex internally uses it's own MapReduce implementation — YT.
+
+The systems of this kind are not suitable for online queries due to their high latency. In other words, they can't be used as the back-end for a web interface.
+
+Distributed sorting isn't the best way to perform reduce operations if the result of the operation and all the intermediate results (if there are any) are located in the RAM of a single server, which is usually the case for online queries. In such a case, a hash table is the optimal way to perform reduce operations. A common approach to optimizing MapReduce tasks is pre-aggregation (partial reduce) using a hash table in RAM. The user performs this optimization manually.
+Distributed sorting is one of the main causes of reduced performance when running simple MapReduce tasks.
+
+Most MapReduce implementations allow executing any code on the cluster. But a declarative query language is better suited to OLAP in order to run experiments quickly. For example, Hadoop has Hive and Pig. Also consider Cloudera Impala, Shark (outdated) for Spark, and Spark SQL, Presto, and Apache Drill. Performance when running such tasks is highly sub-optimal compared to specialized systems, but relatively high latency makes it unrealistic to use these systems as the backend for a web interface.
diff --git a/docs/en/getting_started/example_datasets/nyc_taxi.md b/docs/en/getting_started/example_datasets/nyc_taxi.md
index 04bb31cc7a6..c44670476aa 100644
--- a/docs/en/getting_started/example_datasets/nyc_taxi.md
+++ b/docs/en/getting_started/example_datasets/nyc_taxi.md
@@ -360,9 +360,8 @@ We ran queries using a client located in a Yandex datacenter in Finland on a clu
 
 ## Summary
 
-```text
-nodes   Q1     Q2     Q3     Q4
-  1  0.490  1.224  2.104  3.593
-  3  0.212  0.438  0.733  1.241
-140  0.028  0.043  0.051  0.072
-```
+| nodes | Q1    | Q2    | Q3    | Q4    |
+| ----- | ----- | ----- | ----- | ----- |
+|     1 | 0.490 | 1.224 | 2.104 | 3.593 |
+|     3 | 0.212 | 0.438 | 0.733 | 1.241 |
+|   140 | 0.028 | 0.043 | 0.051 | 0.072 |
diff --git a/docs/en/getting_started/example_datasets/ontime.md b/docs/en/getting_started/example_datasets/ontime.md
index 150fc8bb5bd..14c7af3f876 100644
--- a/docs/en/getting_started/example_datasets/ontime.md
+++ b/docs/en/getting_started/example_datasets/ontime.md
@@ -2,15 +2,6 @@
 
 # OnTime
 
-This performance test was created by Vadim Tkachenko. See:
-
-- 
-- 
-- 
-- 
-- 
-- 
-
 Downloading data:
 
 ```bash
@@ -316,3 +307,12 @@ SELECT OriginCityName, DestCityName, count() AS c FROM ontime GROUP BY OriginCit
 
 SELECT OriginCityName, count() AS c FROM ontime GROUP BY OriginCityName ORDER BY c DESC LIMIT 10;
 ```
+
+This performance test was created by Vadim Tkachenko. For mode details see:
+
+- 
+- 
+- 
+- 
+- 
+- 
diff --git a/docs/en/introduction/features_considered_disadvantages.md b/docs/en/introduction/features_considered_disadvantages.md
index 54a1f2c7a69..010fdf7c9ec 100644
--- a/docs/en/introduction/features_considered_disadvantages.md
+++ b/docs/en/introduction/features_considered_disadvantages.md
@@ -1,6 +1,6 @@
 # ClickHouse features that can be considered disadvantages
 
 1. No full-fledged transactions.
-2. Lack of ability to modify or delete already inserted data with high rate and low latency. There are batch deletes available to clean up data that is not needed anymore or to comply with [GDPR](https://gdpr-info.eu). Batch updates are in development as of July 2018.
+2. Lack of ability to modify or delete already inserted data with high rate and low latency. There are batch deletes available to clean up data that is not needed anymore or to comply with [GDPR](https://gdpr-info.eu). Batch updates are currently in development as of July 2018.
 3. Sparse index makes ClickHouse not really suitable for point queries retrieving single rows by their keys.
 
diff --git a/docs/en/introduction/performance.md b/docs/en/introduction/performance.md
index d8958431dfe..4050cceb642 100644
--- a/docs/en/introduction/performance.md
+++ b/docs/en/introduction/performance.md
@@ -1,22 +1,24 @@
 # Performance
 
-According to internal testing results, ClickHouse shows the best performance for comparable operating scenarios among systems of its class that were available for testing. This includes the highest throughput for long queries, and the lowest latency on short queries. Testing results are shown on a separate page.
+According to internal testing results by Yandex, ClickHouse shows the best performance for comparable operating scenarios among systems of its class that were available for testing. This includes the highest throughput for long queries, and the lowest latency on short queries. Testing results are shown on a [separate page](https://clickhouse.yandex/benchmark.html).
+
+There are a lot of independent benchmarks that confirm this as well. You can look it up on your own or here is the small [collection of independent benchmark links](https://clickhouse.yandex/#independent-benchmarks).
 
 ## Throughput for a single large query
 
-Throughput can be measured in rows per second or in megabytes per second. If the data is placed in the page cache, a query that is not too complex is processed on modern hardware at a speed of approximately 2-10 GB/s of uncompressed data on a single server (for the simplest cases, the speed may reach 30 GB/s). If data is not placed in the page cache, the speed depends on the disk subsystem and the data compression rate. For example, if the disk subsystem allows reading data at 400 MB/s, and the data compression rate is 3, the speed will be around 1.2 GB/s. To get the speed in rows per second, divide the speed in bytes per second by the total size of the columns used in the query. For example, if 10 bytes of columns are extracted, the speed will be around 100-200 million rows per second.
+Throughput can be measured in rows per second or in megabytes per second. If the data is placed in the page cache, a query that is not too complex is processed on modern hardware at a speed of approximately 2-10 GB/s of uncompressed data on a single server (for the simplest cases, the speed may reach 30 GB/s). If data is not placed in the page cache, the speed is bound by the disk subsystem and how well the data has been compressed. For example, if the disk subsystem allows reading data at 400 MB/s, and the data compression rate is 3, the speed will be around 1.2 GB/s. To get the speed in rows per second, divide the speed in bytes per second by the total size of the columns used in the query. For example, if 10 bytes of columns are extracted, the speed will be around 100-200 million rows per second.
 
 The processing speed increases almost linearly for distributed processing, but only if the number of rows resulting from aggregation or sorting is not too large.
 
 ## Latency when processing short queries
 
-If a query uses a primary key and does not select too many rows to process (hundreds of thousands), and does not use too many columns, we can expect less than 50 milliseconds of latency (single digits of milliseconds in the best case) if data is placed in the page cache. Otherwise, latency is calculated from the number of seeks. If you use rotating drives, for a system that is not overloaded, the latency is calculated by this formula: seek time (10 ms) \* number of columns queried \* number of data parts.
+If a query uses a primary key and does not select too many rows to process (hundreds of thousands), and does not use too many columns, we can expect less than 50 milliseconds of latency (single digits of milliseconds in the best case) if data is placed in the page cache. Otherwise, latency is calculated from the number of seeks. If you use rotating drives, for a system that is not overloaded, the approximate latency can be calculated by this formula: seek time (10 ms) \* number of columns queried \* number of data parts.
 
 ## Throughput when processing a large quantity of short queries
 
-Under the same conditions, ClickHouse can handle several hundred queries per second on a single server (up to several thousand in the best case). Since this scenario is not typical for analytical DBMSs, we recommend expecting a maximum of 100 queries per second.
+Under the same circumstances, ClickHouse can handle several hundred queries per second on a single server (up to several thousands in the best case). Since this scenario is not typical for analytical DBMSs, it is better to  expect a maximum of hundreds of queries per second.
 
 ## Performance when inserting data
 
-We recommend inserting data in packets of at least 1000 rows, or no more than a single request per second. When inserting to a MergeTree table from a tab-separated dump, the insertion speed will be from 50 to 200 MB/s. If the inserted rows are around 1 Kb in size, the speed will be from 50,000 to 200,000 rows per second. If the rows are small, the performance will be higher in rows per second (on Banner System data -`>` 500,000 rows per second; on Graphite data -`>` 1,000,000 rows per second). To improve performance, you can make multiple INSERT queries in parallel, and performance will increase linearly.
+It is recommended to insert data in batches of at least 1000 rows, or no more than a single request per second. When inserting to a MergeTree table from a tab-separated dump, the insertion speed will be from 50 to 200 MB/s. If the inserted rows are around 1 Kb in size, the speed will be from 50,000 to 200,000 rows per second. If the rows are small, the performance will be higher in rows per second (on Banner System data -`>` 500,000 rows per second; on Graphite data -`>` 1,000,000 rows per second). To improve performance, you can make multiple INSERT queries in parallel, and performance will increase linearly.
 
diff --git a/docs/en/introduction/possible_silly_questions.md b/docs/en/introduction/possible_silly_questions.md
deleted file mode 100644
index cf7b2c48032..00000000000
--- a/docs/en/introduction/possible_silly_questions.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Questions you were afraid to ask
-
-## Why not use something like MapReduce?
-
-We can refer to systems like map-reduce as distributed computing systems in which the reduce operation is based on distributed sorting. In this sense, they include Hadoop, and YT (YT is developed at Yandex for internal use).
-
-These systems aren't appropriate for online queries due to their high latency. In other words, they can't be used as the back-end for a web interface.
-These types of systems aren't useful for real-time data updates.
-Distributed sorting isn't the best way to perform reduce operations if the result of the operation and all the intermediate results (if there are any) are located in the RAM of a single server, which is usually the case for online queries. In such a case, a hash table is the optimal way to perform reduce operations. A common approach to optimizing map-reduce tasks is pre-aggregation (partial reduce) using a hash table in RAM. The user performs this optimization manually.
-Distributed sorting is one of the main causes of reduced performance when running simple map-reduce tasks.
-
-Systems like map-reduce allow executing any code on the cluster. But a declarative query language is better suited to OLAP in order to run experiments quickly. For example, Hadoop has Hive and Pig. Also consider Cloudera Impala, Shark (outdated) for Spark, and Spark SQL, Presto, and Apache Drill. Performance when running such tasks is highly sub-optimal compared to specialized systems, but relatively high latency makes it unrealistic to use these systems as the backend for a web interface.
-
-YT allows storing groups of columns separately. But YT can't be considered a true column-based system because it doesn't have fixed-length data types (for efficiently storing numbers without extra "garbage"), and also due to its lack of a vector engine. Tasks are performed  in YT using custom code in streaming mode, so they cannot be optimized enough (up to hundreds of millions of rows per second per server). "Dynamic table sorting" is under development in YT using MergeTree, strict value typing, and a query language similar to SQL. Dynamically sorted tables are not appropriate for OLAP tasks because the data is stored by row. The YT query language is still under development, so we can't yet rely on this functionality. YT developers are considering using dynamically sorted tables in OLTP and Key-Value scenarios.
-
diff --git a/docs/en/introduction/ya_metrika_task.md b/docs/en/introduction/ya_metrika_task.md
index 9c16b4e708b..ffc11afe8fa 100644
--- a/docs/en/introduction/ya_metrika_task.md
+++ b/docs/en/introduction/ya_metrika_task.md
@@ -1,9 +1,10 @@
 # Yandex.Metrica use case
 
-ClickHouse currently powers [Yandex.Metrica](https://metrica.yandex.com/), [the second largest web analytics platform in the world](http://w3techs.com/technologies/overview/traffic_analysis/all). With more than 13 trillion records in the database and more than 20 billion events daily, ClickHouse allows you generating custom reports on the fly directly from non-aggregated data.
+ClickHouse has been initially developed to power [Yandex.Metrica](https://metrica.yandex.com/), [the second largest web analytics platform in the world](http://w3techs.com/technologies/overview/traffic_analysis/all), and continues to be it's core component. With more than 13 trillion records in the database and more than 20 billion events daily, ClickHouse allows generating custom reports on the fly directly from non-aggregated data. This article gives a historical background on what was the main goal of ClickHouse before it became an opensource product.
 
-We need to get custom reports based on hits and sessions, with custom segments set by the user. Data for the reports is updated in real-time. Queries must be run immediately (in online mode). We must be able to build reports for any time period. Complex aggregates must be calculated, such as the number of unique visitors.
-At this time (April 2014), Yandex.Metrica receives approximately 12 billion events (pageviews and mouse clicks) daily. All these events must be stored in order to build custom reports. A single query may require scanning hundreds of millions of rows over a few seconds, or millions of rows in no more than a few hundred milliseconds.
+Yandex.Metrica generates custom reports based on hits and sessions on the fly, with arbitrary segments and time periods chosen by the end user. Complex aggregates are often required, such as the number of unique visitors. New data for the reports arrives in real-time.
+
+As of April 2014, Yandex.Metrica received approximately 12 billion events (page views and clicks) daily. All these events must be stored in order to build those custom reports. A single query may require scanning millions of rows in no more than a few hundred milliseconds, or hundreds of millions of rows over a few seconds.
 
 ## Usage in Yandex.Metrica and other Yandex services
 
diff --git a/docs/ru/faq/general.md b/docs/ru/faq/general.md
new file mode 100644
index 00000000000..15a19bbeb85
--- /dev/null
+++ b/docs/ru/faq/general.md
@@ -0,0 +1,12 @@
+# Общие вопросы
+
+## Почему бы не использовать системы типа MapReduce?
+
+Системами типа MapReduce будем называть системы распределённых вычислений, в которых операция reduce сделана на основе распределённой сортировки. Наиболее распространённым opensource решением данного класса является [Apache Hadoop](http://hadoop.apache.org), а в Яндексе используется внутрення разработка — YT.
+
+Такие системы не подходят для онлайн запросов в силу слишком большой latency. То есть, не могут быть использованы в качестве бэкенда для веб-интерфейса.
+Такие системы не подходят для обновления данных в реальном времени.
+Распределённая сортировка не является оптимальным способом выполнения операции reduce, если результат выполнения операции и все промежуточные результаты, при их наличии, помещаются в оперативку на одном сервере, как обычно бывает в запросах, выполняющихся в режиме онлайн. В таком случае, оптимальным способом выполнения операции reduce является хэш-таблица. Частым способом оптимизации map-reduce задач является предагрегация (частичный reduce) с использованием хэш-таблицы в оперативной памяти. Эта оптимизация делается пользователем в ручном режиме.
+Распределённая сортировка является основной причиной тормозов при выполнении несложных map-reduce задач.
+
+Большинство реализаций MapReduce позволяют выполнять произвольный код на кластере. Но для OLAP задач лучше подходит декларативный язык запросов, который позволяет быстро проводить исследования. Для примера, для Hadoop существует Hive и Pig. Также смотрите Cloudera Impala, Shark (устаревший) для Spark, а также Spark SQL, Presto, Apache Drill. Впрочем, производительность при выполнении таких задач является сильно неоптимальной по сравнению со специализированными системами, а сравнительно высокая latency не позволяет использовать эти системы в качестве бэкенда для веб-интерфейса.
\ No newline at end of file
diff --git a/docs/ru/getting_started/example_datasets/nyc_taxi.md b/docs/ru/getting_started/example_datasets/nyc_taxi.md
index 859f77c6ef4..f66f37de89a 100644
--- a/docs/ru/getting_started/example_datasets/nyc_taxi.md
+++ b/docs/ru/getting_started/example_datasets/nyc_taxi.md
@@ -361,9 +361,8 @@ Q4: 0.072 sec.
 
 ## Резюме
 
-```text
-nodes   Q1     Q2     Q3     Q4
-  1  0.490  1.224  2.104  3.593
-  3  0.212  0.438  0.733  1.241
-140  0.028  0.043  0.051  0.072
-```
+| серверов| Q1    | Q2    | Q3    | Q4    |
+| ------- | ----- | ----- | ----- | ----- |
+|       1 | 0.490 | 1.224 | 2.104 | 3.593 |
+|       3 | 0.212 | 0.438 | 0.733 | 1.241 |
+|     140 | 0.028 | 0.043 | 0.051 | 0.072 |
diff --git a/docs/ru/getting_started/example_datasets/ontime.md b/docs/ru/getting_started/example_datasets/ontime.md
index 923c33befa1..afd4de06893 100644
--- a/docs/ru/getting_started/example_datasets/ontime.md
+++ b/docs/ru/getting_started/example_datasets/ontime.md
@@ -2,15 +2,6 @@
 
 # OnTime
 
-Данный тест производительности был создан Вадимом Ткаченко, см:
-
--   
--   
--   
--   
--   
--   
-
 Скачивание данных:
 
 ```bash
@@ -316,3 +307,12 @@ SELECT OriginCityName, DestCityName, count() AS c FROM ontime GROUP BY OriginCit
 
 SELECT OriginCityName, count() AS c FROM ontime GROUP BY OriginCityName ORDER BY c DESC LIMIT 10;
 ```
+
+Данный тест производительности был создан Вадимом Ткаченко, статьи по теме:
+
+-   
+-   
+-   
+-   
+-   
+-   
diff --git a/docs/ru/introduction/performance.md b/docs/ru/introduction/performance.md
index f513881dcfc..95e1d1cd008 100644
--- a/docs/ru/introduction/performance.md
+++ b/docs/ru/introduction/performance.md
@@ -1,10 +1,12 @@
 # Производительность
 
-По результатам внутреннего тестирования, ClickHouse обладает наиболее высокой производительностью (как наиболее высоким throughput на длинных запросах, так и наиболее низкой latency на коротких запросах), при соответствующем сценарии работы, среди доступных для тестирования систем подобного класса. Результаты тестирования можно посмотреть на отдельной странице.
+По результатам внутреннего тестирования в Яндексе, ClickHouse обладает наиболее высокой производительностью (как наиболее высокой пропускной способностью на длинных запросах, так и наиболее низкой задержкой на коротких запросах), при соответствующем сценарии работы, среди доступных для тестирования систем подобного класса. Результаты тестирования можно посмотреть на [отдельной странице](https://clickhouse.yandex/benchmark.html).
+
+Также это подтверждают многочисленные независимые бенчмарки. Их не сложно найти в Интернете самостоятельно, либо можно воспользоваться [небольшой коллекцией ссылок по теме](https://clickhouse.yandex/#independent-benchmarks).
 
 ## Пропускная способность при обработке одного большого запроса
 
-Пропускную способность можно измерять в строчках в секунду и в мегабайтах в секунду. При условии, что данные помещаются в page cache, не слишком сложный запрос обрабатывается на современном железе со скоростью около 2-10 GB/sec. несжатых данных на одном сервере (в простейшем случае скорость может достигать 30 GB/sec). Если данные не помещаются в page cache, то скорость работы зависит от скорости дисковой подсистемы и коэффициента сжатия данных. Например, если дисковая подсистема позволяет читать данные со скоростью 400 MB/sec., а коэффициент сжатия данных составляет 3, то скорость будет около 1.2GB/sec. Для получения скорости в строчках в секунду, следует поделить скорость в байтах в секунду на суммарный размер используемых в запросе столбцов. Например, если вынимаются столбцы на 10 байт, то скорость будет в районе 100-200 млн. строчек в секунду.
+Пропускную способность можно измерять в строчках в секунду и в мегабайтах в секунду. При условии, что данные помещаются в page cache, не слишком сложный запрос обрабатывается на современном железе со скоростью около 2-10 GB/sec. несжатых данных на одном сервере (в простейшем случае скорость может достигать 30 GB/sec). Если данные не помещаются в page cache, то скорость работы зависит от скорости дисковой подсистемы и коэффициента сжатия данных. Например, если дисковая подсистема позволяет читать данные со скоростью 400 MB/sec., а коэффициент сжатия данных составляет 3, то скорость будет около 1.2GB/sec. Для получения скорости в строчках в секунду, следует поделить скорость в байтах в секунду на суммарный размер используемых в запросе столбцов. Например, если вынимаются столбцы на 10 байт, то скорость будет в районе 100-200 млн. строк в секунду.
 
 При распределённой обработке запроса, скорость обработки запроса растёт почти линейно, но только при условии, что в результате агрегации или при сортировке получается не слишком большое множество строчек.
 
@@ -12,7 +14,7 @@
 
 Если запрос использует первичный ключ, и выбирает для обработки не слишком большое количество строчек (сотни тысяч), и использует не слишком большое количество столбцов, то вы можете рассчитывать на latency менее 50 миллисекунд (от единиц миллисекунд в лучшем случае), при условии, что данные помещаются в page cache. Иначе latency вычисляется из количества seek-ов. Если вы используйте вращающиеся диски, то на не слишком сильно нагруженной системе, latency вычисляется по формуле: seek time (10 мс.) \* количество столбцов в запросе \* количество кусков с данными.
 
-## Пропускная способность при обработке большого количества коротких запросов
+## Пропускная способность при обработке многочисленных коротких запросов
 
 При тех же условиях, ClickHouse может обработать несколько сотен (до нескольких тысяч в лучшем случае) запросов в секунду на одном сервере. Так как такой сценарий работы не является типичным для аналитических СУБД, рекомендуется рассчитывать не более чем на 100 запросов в секунду.
 
diff --git a/docs/ru/introduction/possible_silly_questions.md b/docs/ru/introduction/possible_silly_questions.md
deleted file mode 100644
index fc2eb6f24e4..00000000000
--- a/docs/ru/introduction/possible_silly_questions.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Возможные глупые вопросы
-
-## Почему бы не использовать системы типа MapReduce?
-
-Системами типа map-reduce будем называть системы распределённых вычислений, в которых операция reduce сделана на основе распределённой сортировки. Таким образом, к ним относятся Hadoop и YT (YT является внутренней разработкой Яндекса).
-
-Такие системы не подходят для онлайн запросов в силу слишком большой latency. То есть, не могут быть использованы в качестве бэкенда для веб-интерфейса.
-Такие системы не подходят для обновления данных в реальном времени.
-Распределённая сортировка не является оптимальным способом выполнения операции reduce, если результат выполнения операции и все промежуточные результаты, при их наличии, помещаются в оперативку на одном сервере, как обычно бывает в запросах, выполняющихся в режиме онлайн. В таком случае, оптимальным способом выполнения операции reduce является хэш-таблица. Частым способом оптимизации map-reduce задач является предагрегация (частичный reduce) с использованием хэш-таблицы в оперативке. Эта оптимизация делается пользователем в ручном режиме.
-Распределённая сортировка является основной причиной тормозов при выполнении несложных map-reduce задач.
-
-Системы типа map-reduce позволяют выполнять произвольный код на кластере. Но для OLAP задач лучше подходит декларативный язык запросов, который позволяет быстро проводить исследования. Для примера, для Hadoop существует Hive и Pig. Также смотрите Cloudera Impala, Shark (устаревший) для Spark а также Spark SQL, Presto, Apache Drill. Впрочем, производительность при выполнении таких задач является сильно неоптимальной по сравнению со специализированными системами, а сравнительно высокая latency не позволяет использовать эти системы в качестве бэкенда для веб-интерфейса.
-
-YT позволяет хранить группы столбцов по отдельности. Но YT нельзя назвать по-настоящему столбцовой системой, так как в системе отсутствуют типы данных постоянной длины (чтобы можно было эффективно хранить числа без "мусора"), а также за счёт отсутствия векторного движка. Задачи в YT выполняются с помощью произвольного кода в режиме streaming, то есть, не могут быть достаточно оптимизированы (до сотен миллионов строк в секунду на один сервер). В YT в 2014-2016 годах находится в разработке функциональность "динамических сортированных таблиц" с использованием Merge Tree, строгой типизацией значений и языком запросов типа SQL. Динамические сортированные таблицы не подходят для OLAP задач, так как данные в них хранятся по строкам. Разработка языка запросов в YT всё ещё находится в зачаточной стадии, что не позволяет ориентироваться на эту функциональность. Разработчики YT рассматривают динамические сортированные таблицы для применения в OLTP и Key-Value сценариях работы.
diff --git a/docs/ru/introduction/ya_metrika_task.md b/docs/ru/introduction/ya_metrika_task.md
index 6e23491a465..44bf683c0b4 100644
--- a/docs/ru/introduction/ya_metrika_task.md
+++ b/docs/ru/introduction/ya_metrika_task.md
@@ -1,9 +1,10 @@
 # Постановка задачи в Яндекс.Метрике
 
-ClickHouse на данный момент обеспечивает работу [Яндекс.Метрики](https://metrika.yandex.ru/), [второй крупнейшей в мире](http://w3techs.com/technologies/overview/traffic_analysis/all) платформы для веб аналитики. При более 13 триллионах записей в базе данных и более 20 миллиардах событий в сутки, ClickHouse позволяет генерировать индивидуально настроенные отчёты на лету напрямую из неагрегированных данных.
+ClickHouse изначально разрабатывался для обеспечения работы [Яндекс.Метрики](https://metrika.yandex.ru/), [второй крупнейшей в мире](http://w3techs.com/technologies/overview/traffic_analysis/all) платформы для веб аналитики, и продолжает быть её ключевым компонентом. При более 13 триллионах записей в базе данных и более 20 миллиардах событий в сутки, ClickHouse позволяет генерировать индивидуально настроенные отчёты на лету напрямую из неагрегированных данных. Данная статья вкратце демонстрирует какие цели исторически стояли перед ClickHouse на ранних этапах его развития.
 
-Нужно получать произвольные отчёты на основе хитов и визитов, с произвольными сегментами, задаваемыми пользователем. Данные для отчётов обновляются в реальном времени. Запросы должны выполняться сразу (в режиме онлайн). Отчёты должно быть возможно строить за произвольный период. Требуется вычислять сложные агрегаты типа количества уникальных посетителей.
-На данный момент (апрель 2014), каждый день в Яндекс.Метрику поступает около 12 миллиардов событий (хитов и кликов мыши). Все эти события должны быть сохранены для возможности строить произвольные отчёты. Один запрос может потребовать просканировать сотни миллионов строк за время не более нескольких секунд, или миллионы строк за время не более нескольких сотен миллисекунд.
+Яндекс.Метрика на лету строит индивидуальные отчёты на основе хитов и визитов, с периодом и произвольными сегментами, задаваемыми конечным пользователем. Часто требуется построение сложных агрегатов, например числа уникальных пользлователей. Новые данные для построения отчета поступают в реальном времени.
+
+На апрель 2014, в Яндекс.Метрику поступало около 12 миллиардов событий (показов страниц и кликов мыши) ежедневно. Все эти события должны быть сохранены для возможности строить произвольные отчёты. Один запрос может потребовать просканировать миллионы строк за время не более нескольких сотен миллисекунд, или сотни миллионов строк за время не более нескольких секунд.
 
 ## Использование в Яндекс.Метрике и других отделах Яндекса
 
diff --git a/docs/toc_en.yml b/docs/toc_en.yml
index 7f830eac379..689af51c24d 100644
--- a/docs/toc_en.yml
+++ b/docs/toc_en.yml
@@ -3,9 +3,8 @@ pages:
   - 'Overview': 'index.md'
   - 'Distinctive features of ClickHouse': 'introduction/distinctive_features.md'
   - 'ClickHouse features that can be considered disadvantages': 'introduction/features_considered_disadvantages.md'
-  - 'The Yandex.Metrica task': 'introduction/ya_metrika_task.md'
-  - 'Everything you were afraid to ask': 'introduction/possible_silly_questions.md'
   - 'Performance': 'introduction/performance.md'
+  - 'The Yandex.Metrica task': 'introduction/ya_metrika_task.md'
 
 - 'Getting started':
   - 'Deploying and running': 'getting_started/index.md'
@@ -160,6 +159,9 @@ pages:
     - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md'
     - 'clickhouse-local': 'operations/utils/clickhouse-local.md'
 
+- 'F.A.Q.':
+  - 'General questions': 'faq/general.md'
+
 - 'Development':
   - 'hidden': 'development/index.md'
   - 'Overview of ClickHouse architecture': 'development/architecture.md'
diff --git a/docs/toc_ru.yml b/docs/toc_ru.yml
index 9e086eed378..93acc6cc951 100644
--- a/docs/toc_ru.yml
+++ b/docs/toc_ru.yml
@@ -4,9 +4,8 @@ pages:
   - 'Обзор': 'index.md'
   - 'Отличительные возможности ClickHouse': 'introduction/distinctive_features.md'
   - 'Особенности ClickHouse, которые могут считаться недостатками': 'introduction/features_considered_disadvantages.md'
-  - 'Постановка задачи в Яндекс.Метрике': 'introduction/ya_metrika_task.md'
-  - 'Возможные глупые вопросы': 'introduction/possible_silly_questions.md'
   - 'Производительность': 'introduction/performance.md'
+  - 'Постановка задачи в Яндекс.Метрике': 'introduction/ya_metrika_task.md'
 
 - 'Начало работы':
   - 'Установка и запуск': 'getting_started/index.md'
@@ -163,6 +162,9 @@ pages:
     - 'clickhouse-copier': 'operations/utils/clickhouse-copier.md'
     - 'clickhouse-local': 'operations/utils/clickhouse-local.md'
 
+- 'F.A.Q.':
+  - 'Общие вопросы': 'faq/general.md'
+
 - 'Разработка':
   - 'hidden': 'development/index.md'
   - 'Overview of ClickHouse architecture': 'development/architecture.md'
diff --git a/docs/tools/mkdocs-material-theme/partials/footer.html b/docs/tools/mkdocs-material-theme/partials/footer.html
index 6bdac35413a..f8edf2ef005 100644
--- a/docs/tools/mkdocs-material-theme/partials/footer.html
+++ b/docs/tools/mkdocs-material-theme/partials/footer.html
@@ -5,7 +5,7 @@