12 KiB
machine_translated | machine_translated_rev | toc_priority | toc_title |
---|---|---|---|
true | 72537a2d52 |
41 | Almacenamiento de diccionarios en la memoria |
Almacenamiento de diccionarios en la memoria
Hay una variedad de formas de almacenar diccionarios en la memoria.
Recomendamos plano, Hashed y Método de codificación de datos:. que proporcionan una velocidad de procesamiento óptima.
No se recomienda el almacenamiento en caché debido al rendimiento potencialmente bajo y las dificultades para seleccionar los parámetros óptimos. Lea más en la sección “cache”.
Hay varias formas de mejorar el rendimiento del diccionario:
- Llame a la función para trabajar con el diccionario después
GROUP BY
. - Marque los atributos para extraer como inyectivos. Un atributo se llama injective si diferentes valores de atributo corresponden a claves diferentes. Entonces, cuando
GROUP BY
utiliza una función que obtiene un valor de atributo mediante la clave, esta función se elimina automáticamente deGROUP BY
.
ClickHouse genera una excepción para errores con diccionarios. Ejemplos de errores:
- No se pudo cargar el diccionario al que se accede.
- Error al consultar un
cached
diccionario.
Puede ver la lista de diccionarios externos y sus estados en el system.dictionaries
tabla.
La configuración se ve así:
<yandex>
<dictionary>
...
<layout>
<layout_type>
<!-- layout settings -->
</layout_type>
</layout>
...
</dictionary>
</yandex>
Correspondiente Consulta DDL:
CREATE DICTIONARY (...)
...
LAYOUT(LAYOUT_TYPE(param value)) -- layout settings
...
Maneras de almacenar diccionarios en la memoria
- plano
- Hashed
- Sistema abierto.
- cache
- directo
- range_hashed
- Método de codificación de datos:
- complejo_key_cache
- Método de codificación de datos:
plano
El diccionario está completamente almacenado en la memoria en forma de matrices planas. ¿Cuánta memoria usa el diccionario? La cantidad es proporcional al tamaño de la clave más grande (en el espacio utilizado).
La clave del diccionario tiene el UInt64
tipo y el valor está limitado a 500.000. Si se descubre una clave más grande al crear el diccionario, ClickHouse produce una excepción y no crea el diccionario.
Se admiten todos los tipos de fuentes. Al actualizar, los datos (de un archivo o de una tabla) se leen en su totalidad.
Este método proporciona el mejor rendimiento entre todos los métodos disponibles para almacenar el diccionario.
Ejemplo de configuración:
<layout>
<flat />
</layout>
o
LAYOUT(FLAT())
Hashed
El diccionario está completamente almacenado en la memoria en forma de una tabla hash. El diccionario puede contener cualquier número de elementos con cualquier identificador En la práctica, el número de claves puede alcanzar decenas de millones de elementos.
Se admiten todos los tipos de fuentes. Al actualizar, los datos (de un archivo o de una tabla) se leen en su totalidad.
Ejemplo de configuración:
<layout>
<hashed />
</layout>
o
LAYOUT(HASHED())
Sistema abierto
Similar a hashed
, pero usa menos memoria a favor más uso de CPU.
Ejemplo de configuración:
<layout>
<sparse_hashed />
</layout>
LAYOUT(SPARSE_HASHED())
Método de codificación de datos:
Este tipo de almacenamiento es para su uso con material compuesto claves. Similar a hashed
.
Ejemplo de configuración:
<layout>
<complex_key_hashed />
</layout>
LAYOUT(COMPLEX_KEY_HASHED())
range_hashed
El diccionario se almacena en la memoria en forma de una tabla hash con una matriz ordenada de rangos y sus valores correspondientes.
Este método de almacenamiento funciona de la misma manera que hash y permite el uso de intervalos de fecha / hora (tipo numérico arbitrario) además de la clave.
Ejemplo: La tabla contiene descuentos para cada anunciante en el formato:
+---------|-------------|-------------|------+
| advertiser id | discount start date | discount end date | amount |
+===============+=====================+===================+========+
| 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 |
+---------|-------------|-------------|------+
Para utilizar un ejemplo para intervalos de fechas, defina el range_min
y range_max
elementos en el estructura. Estos elementos deben contener elementos name
ytype
(si type
no se especifica, se utilizará el tipo predeterminado - Fecha). type
puede ser de cualquier tipo numérico (Fecha / DateTime / UInt64 / Int32 / otros).
Ejemplo:
<structure>
<id>
<name>Id</name>
</id>
<range_min>
<name>first</name>
<type>Date</type>
</range_min>
<range_max>
<name>last</name>
<type>Date</type>
</range_max>
...
o
CREATE DICTIONARY somedict (
id UInt64,
first Date,
last Date
)
PRIMARY KEY id
LAYOUT(RANGE_HASHED())
RANGE(MIN first MAX last)
Para trabajar con estos diccionarios, debe pasar un argumento adicional al dictGetT
función, para la que se selecciona un rango:
dictGetT('dict_name', 'attr_name', id, date)
Esta función devuelve el valor para el id
s y el intervalo de fechas que incluye la fecha pasada.
Detalles del algoritmo:
- Si el
id
no se encuentra o no se encuentra un rango para elid
devuelve el valor predeterminado para el diccionario. - Si hay rangos superpuestos, puede usar cualquiera.
- Si el delimitador de rango es
NULL
o una fecha no válida (como 1900-01-01 o 2039-01-01), el rango se deja abierto. La gama puede estar abierta en ambos lados.
Ejemplo de configuración:
<yandex>
<dictionary>
...
<layout>
<range_hashed />
</layout>
<structure>
<id>
<name>Abcdef</name>
</id>
<range_min>
<name>StartTimeStamp</name>
<type>UInt64</type>
</range_min>
<range_max>
<name>EndTimeStamp</name>
<type>UInt64</type>
</range_max>
<attribute>
<name>XXXType</name>
<type>String</type>
<null_value />
</attribute>
</structure>
</dictionary>
</yandex>
o
CREATE DICTIONARY somedict(
Abcdef UInt64,
StartTimeStamp UInt64,
EndTimeStamp UInt64,
XXXType String DEFAULT ''
)
PRIMARY KEY Abcdef
RANGE(MIN StartTimeStamp MAX EndTimeStamp)
cache
El diccionario se almacena en una memoria caché que tiene un número fijo de celdas. Estas celdas contienen elementos de uso frecuente.
Al buscar un diccionario, primero se busca en la memoria caché. Para cada bloque de datos, todas las claves que no se encuentran en la memoria caché o están desactualizadas se solicitan desde el origen utilizando SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)
. Los datos recibidos se escriben en la memoria caché.
Para los diccionarios de caché, la caducidad vida de datos en la memoria caché se puede establecer. Si más tiempo que lifetime
ha pasado desde que se cargaron los datos en una celda, el valor de la celda no se usa y se vuelve a solicitar la próxima vez que se deba usar.
Esta es la menos efectiva de todas las formas de almacenar diccionarios. La velocidad de la memoria caché depende en gran medida de la configuración correcta y del escenario de uso. Un diccionario de tipo de caché funciona bien solo cuando las tasas de aciertos son lo suficientemente altas (recomendado 99% y superior). Puede ver la tasa de aciertos promedio en el system.dictionaries
tabla.
Para mejorar el rendimiento de la caché, utilice una subconsulta con LIMIT
, y llame a la función con el diccionario externamente.
Apoyar fuente: MySQL, ClickHouse, ejecutable, HTTP.
Ejemplo de configuración:
<layout>
<cache>
<!-- The size of the cache, in number of cells. Rounded up to a power of two. -->
<size_in_cells>1000000000</size_in_cells>
</cache>
</layout>
o
LAYOUT(CACHE(SIZE_IN_CELLS 1000000000))
Establezca un tamaño de caché lo suficientemente grande. Necesitas experimentar para seleccionar el número de celdas:
- Establecer algún valor.
- Ejecute consultas hasta que la memoria caché esté completamente llena.
- Evalúe el consumo de memoria utilizando el
system.dictionaries
tabla. - Aumente o disminuya el número de celdas hasta que se alcance el consumo de memoria requerido.
!!! warning "Advertencia" No use ClickHouse como fuente, ya que es lento procesar consultas con lecturas aleatorias.
complejo_key_cache
Este tipo de almacenamiento es para su uso con material compuesto claves. Similar a cache
.
directo
El diccionario no se almacena en la memoria y va directamente a la fuente durante el procesamiento de una solicitud.
La clave del diccionario tiene el UInt64
tipo.
Todos los tipos de fuente, excepto los archivos locales, son compatibles.
Ejemplo de configuración:
<layout>
<direct />
</layout>
o
LAYOUT(DIRECT())
Método de codificación de datos:
Este tipo de almacenamiento sirve para asignar prefijos de red (direcciones IP) a metadatos como ASN.
Ejemplo: La tabla contiene prefijos de red y su correspondiente número AS y código de país:
+-----------|-----|------+
| prefix | asn | cca2 |
+=================+=======+========+
| 202.79.32.0/20 | 17501 | NP |
+-----------|-----|------+
| 2620:0:870::/48 | 3856 | US |
+-----------|-----|------+
| 2a02:6b8:1::/48 | 13238 | RU |
+-----------|-----|------+
| 2001:db8::/32 | 65536 | ZZ |
+-----------|-----|------+
Cuando se utiliza este tipo de diseño, la estructura debe tener una clave compuesta.
Ejemplo:
<structure>
<key>
<attribute>
<name>prefix</name>
<type>String</type>
</attribute>
</key>
<attribute>
<name>asn</name>
<type>UInt32</type>
<null_value />
</attribute>
<attribute>
<name>cca2</name>
<type>String</type>
<null_value>??</null_value>
</attribute>
...
o
CREATE DICTIONARY somedict (
prefix String,
asn UInt32,
cca2 String DEFAULT '??'
)
PRIMARY KEY prefix
La clave debe tener solo un atributo de tipo String que contenga un prefijo IP permitido. Todavía no se admiten otros tipos.
Para consultas, debe utilizar las mismas funciones (dictGetT
con una tupla) como para diccionarios con claves compuestas:
dictGetT('dict_name', 'attr_name', tuple(ip))
La función toma cualquiera UInt32
para IPv4, o FixedString(16)
para IPv6:
dictGetString('prefix', 'asn', tuple(IPv6StringToNum('2001:db8::1')))
Todavía no se admiten otros tipos. La función devuelve el atributo para el prefijo que corresponde a esta dirección IP. Si hay prefijos superpuestos, se devuelve el más específico.
Los datos se almacenan en un trie
. Debe encajar completamente en la RAM.