.. _dicts-external_dicts_dict_layout: ************************** Хранение словарей в памяти ************************** Словари можно размещать в памяти :ref:`множеством способов `. Рекомендуем :ref:`dicts-external_dicts_dict_layout-flat`, :ref:`dicts-external_dicts_dict_layout-hashed` и :ref:`dicts-external_dicts_dict_layout-complex_key_hashed`. Скорость обработки словарей при этом максимальна. Размещение с кэшированием не рекомендуется использовать из-за потенциально низкой производительности и сложностей в подборе оптимальных параметров. Читайте об этом подробнее в разделе ":ref:`dicts-external_dicts_dict_layout-cache`". Повысить производительнось словарей можно следующими способами: * Вызывать функцию для работы со словарём после ``GROUP BY``. * Помечать извлекаемые атрибуты как инъективные. Атрибут называется инъективным, если разным ключам соответствуют разные значения атрибута. Тогда при использовании в ``GROUP BY`` функции, достающей значение атрибута по ключу, эта функция автоматически выносится из ``GROUP BY``. ClickHouse периодически обновляет словари. Сначала проверяется время модификации файла/таблицы, затем, если файл/таблица обновились, обновляется словарь. Если словарь хранится в таблице типа MyISAM, то время модификации проверяется запросом ``SHOW TABLE STATUS``. Для таблиц InnoDB нельзя получить время модификации, поэтому словарь обновляется каждый раз. Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы - во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей. При ошибках работы со словарями ClickHouse генерирует исключения. Например, в следующих ситуациях: * При обращении к словарю, который не удалось загрузить. * При ошибке запроса к ``cached``-словарю. Список внешних словарей и их статус можно посмотреть в таблице ``system.dictionaries``. Общий вид конфигурации: .. code-block:: xml ... ... .. _dicts-external_dicts_dict_layout-manner: Способы размещения словарей в памяти ==================================== * :ref:`dicts-external_dicts_dict_layout-flat` * :ref:`dicts-external_dicts_dict_layout-hashed` * :ref:`dicts-external_dicts_dict_layout-cache` * :ref:`dicts-external_dicts_dict_layout-range_hashed` * :ref:`dicts-external_dicts_dict_layout-complex_key_hashed` * :ref:`dicts-external_dicts_dict_layout-complex_key_cache` .. _dicts-external_dicts_dict_layout-flat: flat ---- Словарь полностью хранится в оперативной памяти в виде плоских массивов. Объем памяти, занимаемой словарем? пропорционален размеру самого большого (по размеру) ключа. Ключ словаря имеет тип ``UInt64`` и его величина ограничена 500 000. Если при создании словаря обнаружен ключ больше, то ClickHouse бросает исключение и не создает словарь. Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. Это метод обеспечивает максимальную производительность среди всех доступных способов размещения словаря. Пример конфигурации: .. code-block:: xml .. _dicts-external_dicts_dict_layout-hashed: hashed ------ Словарь полностью хранится в оперативной памяти в виде хэш-таблиц. Словарь может содержать произвольное количество элементов с произвольными идентификаторами. На практике, количество ключей может достигать десятков миллионов элементов. Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. Пример конфигурации: .. code-block:: xml .. _dicts-external_dicts_dict_layout-complex_key_hashed: complex_key_hashed ------------------ Тип размещения предназначен для использования с составными :ref:`ключами `. Аналогичен hashed. Пример конфигурации: .. code-block:: xml .. _dicts-external_dicts_dict_layout-range_hashed: range_hashed ------------ Словарь хранится в оперативной памяти в виде хэш-таблицы с упорядоченным массивом диапазонов и соответствующих им значений. Этот способ размещения работает также как и hashed и позволяет дополнительно к ключу использовать дипазоны по дате/времени, если они указаны в словаре. Пример: таблица содержит скидки для каждого рекламодателя в виде: +------------------+-----------------------------+------------+----------+ | id рекламодателя | дата начала действия скидки | дата конца | величина | +==================+=============================+============+==========+ | 123 | 2015-01-01 | 2015-01-15 | 0.15 | +------------------+-----------------------------+------------+----------+ | 123 | 2015-01-16 | 2015-01-31 | 0.25 | +------------------+-----------------------------+------------+----------+ | 456 | 2015-01-01 | 2015-01-15 | 0.05 | +------------------+-----------------------------+------------+----------+ Столбцы с датами в словаре должны иметь тип ``Date``. Чтобы использовать выборку по диапазонам дат, необходимо в :ref:`structure ` определить элементы ``range_min``, ``range_max``. Пример: .. code-block:: xml Id first last ... Для работы с такими словарями в функцию ``dictGetT`` необходимо передавать дополнительный аргумент - дату: :: dictGetT('dict_name', 'attr_name', id, date) Функция возвращает значение для заданных ``id`` и диапазона дат, в который входит переданная дата. Особенности алгоритма: * Если не найден ``id`` или для найденного ``id`` не найден диапазон, то возвращается значение по умолчанию для словаря. * Если есть перекрывающиеся диапазоны, то можно использовать любой подходящий. * Если граница диапазона ``NULL`` или некорректная дата (1900-01-01, 2039-01-01), то диапазон считается открытым. Диапазон может быть открытым с обеих сторон. Пример конфигурации: .. code-block:: xml ... Abcdef StartDate EndDate XXXType String .. _dicts-external_dicts_dict_layout-cache: cache ----- Словарь хранится в кэше, состоящем из фиксированного количества ячеек. Ячейки содержат часто используемые элементы. При поиске в словаре сначала просматривается кэш. На каждый блок данных, все не найденные в кэше или устаревшие ключи запрашиваются у источника с помощью ``SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)``. Затем, полученные данные записываются в кэш. Для cache-словарей может быть задано время устаревания (:ref:`lifetime `) данных в кэше. Если от загрузки данных в ячейке прошло больше времени, чем ``lifetime``, то значение не используется, и будет запрошено заново при следующей необходимости его использовать. Это наименее эффективный из всех способов размещения словарей. Скорость работы кэша очень сильно зависит от правильности настройки и сценария использования. Словарь типа cache показывает высокую производительность лишь при достаточно больших hit rate-ах (рекомендуется 99% и выше). Посмотреть средний hit rate можно в таблице ``system.dictionaries``. Чтобы увеличить производительность кэша, используйте подзапрос с ``LIMIT``, а снаружи вызывайте функцию со словарём. Поддерживаются :ref:`источники `: MySQL, ClickHouse, executable, HTTP. Пример настройки: .. code-block:: xml 1000000000 Укажите достаточно большой размер кэша. Количество ячеек следует подобрать экспериментальным путём: 1. Выставить некоторое значение. 2. Запросами добиться полной заполненности кэша. 3. Оценить потребление оперативной памяти с помощью таблицы ``system.dictionaries``. 4. Увеличивать/уменьшать количество ячеек до получения требуемого расхода оперативной памяти. .. warning:: Не используйте в качестве источника ClickHouse, поскольку он медленно обрабатывает запросы со случайным чтением. .. _dicts-external_dicts_dict_layout-complex_key_cache: complex_key_cache ----------------- Тип размещения предназначен для использования с составными :ref:`ключами `. Аналогичен ``cache``.