mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 08:40:50 +00:00
Update mergetree.md
This commit is contained in:
parent
b39fa2027d
commit
b1967ff0d5
@ -2,45 +2,45 @@
|
|||||||
|
|
||||||
# MergeTree
|
# MergeTree
|
||||||
|
|
||||||
Движок MergeTree поддерживает индекс по первичному ключу и по дате, и обеспечивает возможность обновления данных в реальном времени.
|
Движок MergeTree поддерживает индекс по первичному ключу и по дате и обеспечивает возможность обновления данных в реальном времени.
|
||||||
Это наиболее продвинутый движок таблиц в ClickHouse. Не путайте с движком Merge.
|
Это наиболее продвинутый движок таблиц в ClickHouse. Не путайте с движком Merge.
|
||||||
|
|
||||||
Движок принимает параметры: имя столбца типа Date, содержащего дату; выражение для семплирования (не обязательно); кортеж, определяющий первичный ключ таблицы; гранулированность индекса. Пример:
|
Движок принимает параметры: имя столбца типа Date, содержащего дату; выражение для семплирования (не обязательно); кортеж, определяющий первичный ключ таблицы; гранулированность индекса.
|
||||||
|
|
||||||
Пример без поддержки сэмплирования:
|
Пример без поддержки сэмплирования.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
MergeTree(EventDate, (CounterID, EventDate), 8192)
|
MergeTree(EventDate, (CounterID, EventDate), 8192)
|
||||||
```
|
```
|
||||||
|
|
||||||
Пример с поддержкой сэмплирования:
|
Пример с поддержкой сэмплирования.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
|
MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
|
||||||
```
|
```
|
||||||
|
|
||||||
В таблице типа MergeTree обязательно должен быть отдельный столбец, содержащий дату. В этом примере, это - столбец EventDate. Тип столбца с датой - обязательно Date (а не DateTime).
|
В таблице типа MergeTree обязательно должен быть отдельный столбец, содержащий дату, здесь это столбец EventDate. Тип столбца с датой — обязательно Date (а не DateTime).
|
||||||
|
|
||||||
Первичным ключом может быть кортеж из произвольных выражений (обычно это просто кортеж столбцов) или одно выражение.
|
Первичным ключом может быть кортеж из произвольных выражений (обычно это просто кортеж столбцов) или одно выражение.
|
||||||
|
|
||||||
Выражение для сэмплирования (использовать не обязательно) - произвольное выражение. Оно должно также присутствовать в первичном ключе. В примере используется хэширование по идентификатору посетителя, чтобы псевдослучайно перемешать данные в таблице для каждого CounterID и EventDate. То есть, при использовании секции SAMPLE в запросе, вы получите равномерно-псевдослучайную выборку данных для подмножества посетителей.
|
Выражение для сэмплирования (использовать не обязательно) — произвольное выражение. Оно должно также присутствовать в первичном ключе. В примере используется хэширование по идентификатору посетителя, чтобы псевдослучайно перемешать данные в таблице для каждого CounterID и EventDate. То есть, при использовании секции SAMPLE в запросе вы получите равномерно-псевдослучайную выборку данных для подмножества посетителей.
|
||||||
|
|
||||||
Таблица реализована, как набор кусочков. Каждый кусочек сортирован по первичному ключу. Также, для каждого кусочка прописана минимальная и максимальная дата. При вставке в таблицу, создаётся новый сортированный кусочек. В фоне, периодически инициируется процесс слияния. При слиянии, выбирается несколько кусочков, обычно наименьших, и сливаются в один большой сортированный кусочек.
|
Таблица реализована как набор кусочков. Каждый кусочек сортирован по первичному ключу. Также для каждого кусочка прописана минимальная и максимальная дата. При вставке в таблицу создаётся новый сортированный кусочек. В фоне периодически инициируется процесс слияния. При слиянии выбирается несколько кусочков, обычно наименьших, и сливаются в один большой сортированный кусочек.
|
||||||
|
|
||||||
То есть, при вставке в таблицу производится инкрементальная сортировка. Слияние реализовано таким образом, что таблица постоянно состоит из небольшого количества сортированных кусочков, а также само слияние делает не слишком много работы.
|
То есть, при вставке в таблицу производится инкрементальная сортировка. Слияние реализовано таким образом, что таблица постоянно состоит из небольшого количества сортированных кусочков, а также само слияние делает не слишком много работы.
|
||||||
|
|
||||||
При вставке, данные относящиеся к разным месяцам, разбиваются на разные кусочки. Кусочки, соответствующие разным месяцам, никогда не объединяются. Это сделано, чтобы обеспечить локальность модификаций данных (для упрощения бэкапов).
|
При вставке данные, относящиеся к разным месяцам, разбиваются на разные кусочки. Кусочки, соответствующие разным месяцам, никогда не объединяются. Это сделано, чтобы обеспечить локальность модификаций данных (для упрощения бэкапов).
|
||||||
|
|
||||||
Кусочки объединяются до некоторого предельного размера - чтобы не было слишком длительных слияний.
|
Кусочки объединяются до некоторого предельного размера, чтобы не было слишком длительных слияний.
|
||||||
|
|
||||||
Для каждого кусочка также пишется индексный файл. Индексный файл содержит значение первичного ключа для каждой index_granularity строки таблицы. То есть, это - разреженный индекс сортированных данных.
|
Для каждого кусочка также пишется индексный файл. Индексный файл содержит значение первичного ключа для каждой index_granularity строки таблицы. То есть, это разреженный индекс сортированных данных.
|
||||||
|
|
||||||
Для столбцов также пишутся "засечки" каждую index_granularity строку, чтобы данные можно было читать в определённом диапазоне.
|
Для столбцов также пишутся «засечки» каждую index_granularity строку, чтобы данные можно было читать в определённом диапазоне.
|
||||||
|
|
||||||
При чтении из таблицы, запрос SELECT анализируется на предмет того, можно ли использовать индексы.
|
При чтении из таблицы, запрос SELECT анализируется на предмет того, можно ли использовать индексы.
|
||||||
Индекс может использоваться, если в секции WHERE/PREWHERE, в качестве одного из элементов конъюнкции, или целиком, есть выражение, представляющее операции сравнения на равенства, неравенства, а также IN над столбцами, входящими в первичный ключ / дату, а также логические связки над ними.
|
Индекс может использоваться, если в секции WHERE/PREWHERE, в качестве одного из элементов конъюнкции, или целиком, есть выражение, представляющее операции сравнения на равенства, неравенства, а также IN над столбцами, входящими в первичный ключ / дату, а также логические связки над ними.
|
||||||
|
|
||||||
Таким образом, обеспечивается возможность быстро выполнять запросы по одному или многим диапазонам первичного ключа. Например, в указанном примере, будут быстро работать запросы для конкретного счётчика; для конкретного счётчика и диапазона дат; для конкретного счётчика и даты, для нескольких счётчиков и диапазона дат и т. п.
|
Таким образом, обеспечивается возможность быстро выполнять запросы по одному или многим диапазонам первичного ключа. Например, в указанном примере будут быстро работать запросы для конкретного счётчика; для конкретного счётчика и диапазона дат; для конкретного счётчика и даты, для нескольких счётчиков и диапазона дат и т. п.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT count() FROM table WHERE EventDate = toDate(now()) AND CounterID = 34
|
SELECT count() FROM table WHERE EventDate = toDate(now()) AND CounterID = 34
|
||||||
@ -50,22 +50,22 @@ SELECT count() FROM table WHERE ((EventDate >= toDate('2014-01-01') AND EventDat
|
|||||||
|
|
||||||
Во всех этих случаях будет использоваться индекс по дате и по первичному ключу. Видно, что индекс используется даже для достаточно сложных выражений. Чтение из таблицы организовано так, что использование индекса не может быть медленнее full scan-а.
|
Во всех этих случаях будет использоваться индекс по дате и по первичному ключу. Видно, что индекс используется даже для достаточно сложных выражений. Чтение из таблицы организовано так, что использование индекса не может быть медленнее full scan-а.
|
||||||
|
|
||||||
В этом примере, индекс не может использоваться:
|
В этом примере индекс не может использоваться.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%'
|
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](../operations/settings/settings.md#settings-settings-force_index_by_date) и [force_primary_key](../operations/settings/settings.md#settings-settings-force_primary_key).
|
||||||
|
|
||||||
Индекс по дате обеспечивает чтение только кусков, содержащих даты из нужного диапазона. При этом, кусок данных может содержать данные за многие даты (до целого месяца), а в пределах одного куска, данные лежат упорядоченными по первичному ключу, который может не содержать дату в качестве первого столбца. В связи с этим, при использовании запроса с указанием условия только на дату, но не на префикс первичного ключа, будет читаться данных больше, чем за одну дату.
|
Индекс по дате обеспечивает чтение только кусков, содержащих даты из нужного диапазона. При этом кусок данных может содержать данные за многие даты (до целого месяца), а в пределах одного куска данные лежат упорядоченными по первичному ключу, который может не содержать дату в качестве первого столбца. В связи с этим, при использовании запроса с указанием условия только на дату, но не на префикс первичного ключа, будет читаться данных больше, чем за одну дату.
|
||||||
|
|
||||||
Для конкуррентного доступа к таблице, используется мульти-версионность. То есть, при одновременном чтении и обновлении таблицы, данные будут читаться из набора кусочков, актуального на момент запроса. Длинных блокировок нет. Вставки никак не мешают чтениям.
|
Для конкуррентного доступа к таблице используется мультиверсионность. То есть, при одновременном чтении и обновлении таблицы, данные будут читаться из набора кусочков, актуального на момент запроса. Длинных блокировок нет. Вставки никак не мешают чтениям.
|
||||||
|
|
||||||
Чтения из таблицы автоматически распараллеливаются.
|
Чтения из таблицы автоматически распараллеливаются.
|
||||||
|
|
||||||
Поддерживается запрос `OPTIMIZE`, который вызывает один внеочередной шаг слияния.
|
Поддерживается запрос `OPTIMIZE`, который вызывает один внеочередной шаг слияния.
|
||||||
|
|
||||||
Вы можете использовать одну большую таблицу, постоянно добавляя в неё данные небольшими пачками - именно для этого предназначен движок MergeTree.
|
Вы можете использовать одну большую таблицу, постоянно добавляя в неё данные небольшими пачками, именно для этого предназначен движок MergeTree.
|
||||||
|
|
||||||
Для всех типов таблиц семейства MergeTree возможна репликация данных - смотрите раздел "Репликация данных".
|
Для всех типов таблиц семейства MergeTree возможна репликация данных — смотрите раздел «Репликация данных».
|
||||||
|
Loading…
Reference in New Issue
Block a user