{"id":91438,"date":"2020-08-13T19:42:36","date_gmt":"2020-08-13T17:42:36","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks"},"modified":"2020-08-13T19:42:36","modified_gmt":"2020-08-13T17:42:36","slug":"effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks","title":{"rendered":"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/8e42c1fffffcc964eacef240ea90bbc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dado que ClickHouse es un sistema especializado, es importante tener en cuenta las caracter\u00edsticas de su arquitectura al utilizarlo. En esta presentaci\u00f3n, Alexey abordar\u00e1 ejemplos de errores comunes al usar ClickHouse que pueden llevar a un funcionamiento ineficiente. A trav\u00e9s de ejemplos pr\u00e1cticos, se mostrar\u00e1 c\u00f3mo la elecci\u00f3n de un esquema de procesamiento de datos u otro puede alterar la rendimiento por \u00f3rdenes de magnitud.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>\u00a1Hola a todos! Mi nombre es Alexey, y trabajo con ClickHouse.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/7f5fc01663be58d3d25e518a4169b8cf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Primero, me apresuro a alegrarlos, no les contar\u00e9 hoy qu\u00e9 es ClickHouse. Para ser honesto, estoy cansado de hacerlo. Cada vez que hablo de ello, y probablemente todos ya lo saben. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/fae6bd07d098200643d591b8e5bf51e8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En lugar de eso, hablar\u00e9 sobre los posibles escollos, es decir, c\u00f3mo se puede utilizar incorrectamente ClickHouse. En realidad, no hay raz\u00f3n para tener miedo, porque desarrollamos ClickHouse como un sistema que es simple, conveniente y funciona desde el primer momento. Lo instalas y listo, sin problemas. <\/p>\n<p><\/p>\n<p>Pero a\u00fan as\u00ed, es importante tener en cuenta que este sistema es especializado y se puede f\u00e1cilmente topar con un escenario de uso inusual que sacar\u00e1 al sistema de su zona de confort.<\/p>\n<p><\/p>\n<p>Entonces, \u00bfcu\u00e1les son esos escollos? En su mayor\u00eda, hablar\u00e9 de cosas obvias. Todos ven lo obvio, todos entienden y pueden alegrarse de ser tan inteligentes, y quienes no entienden aprender\u00e1n algo nuevo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/bffacf353ff31b361460178e911f0e16.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>El primer ejemplo m\u00e1s simple, que desafortunadamente ocurre con frecuencia, es un gran n\u00famero de inserciones con lotes peque\u00f1os, es decir, un gran n\u00famero de peque\u00f1as inserciones.<\/p>\n<p><\/p>\n<p>Si consideramos c\u00f3mo ClickHouse realiza una inserci\u00f3n, puedes enviar una cantidad de datos en un solo pedido, incluso hasta un terabyte. No hay problema. <\/p>\n<p><\/p>\n<p>Y veamos cu\u00e1l ser\u00eda el rendimiento t\u00edpico. Por ejemplo, tenemos una tabla con datos de Yandex.Metrica. Hits. 105 columnas. 700 bytes en formato sin comprimir. Y vamos a insertar correctamente en lotes de un mill\u00f3n de filas. <\/p>\n<p><\/p>\n<p>Insertando en una tabla MergeTree, obtenemos medio mill\u00f3n de filas por segundo. Excelente. En la tabla replicada, ser\u00e1 un poco menos, alrededor de 400,000 filas por segundo. <\/p>\n<p><\/p>\n<p>Y si activamos la inserci\u00f3n con qu\u00f3rum, obtenemos un poco menos, pero sigue siendo un rendimiento razonable, 250,000 filas por segundo. La inserci\u00f3n con qu\u00f3rum es una caracter\u00edstica no documentada en ClickHouse*.<\/p>\n<p><\/p>\n<p>* hasta el a\u00f1o 2020, <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/operations\/settings\/settings\/#settings-insert_quorum\">ya est\u00e1 documentada<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/668498fc82a0f6e851d05e6e1ea67033.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfQu\u00e9 pasar\u00e1 si lo hacemos mal? Insertamos una fila a la vez en la tabla MergeTree y obtenemos 59 filas por segundo. Esto es 10,000 veces m\u00e1s lento. En ReplicatedMergeTree, es 6 filas por segundo. Y si adem\u00e1s se activa el qu\u00f3rum, entonces obtenemos 2 filas por segundo. En mi opini\u00f3n, esto es una total decepci\u00f3n. \u00bfC\u00f3mo se puede tener tanto retraso? Incluso en mi camiseta dice que ClickHouse no debe ralentizarse. Pero, a veces, sucede. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/4c771eddc4e8453f60ef91123ae5d109.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De hecho, esta es nuestra falla. Podr\u00edamos haber hecho que todo funcionara correctamente, pero no lo hicimos. Y no lo hicimos porque para nuestro escenario no era necesario. Ya ten\u00edamos lotes. Simplemente, recib\u00edamos lotes y no hab\u00eda problemas. Insertamos y todo funcionaba correctamente. Pero, por supuesto, podr\u00edan surgir varios escenarios. Por ejemplo, cuando tienes un mont\u00f3n de servidores donde se generan datos. Y estos insertan datos no tan frecuentemente, pero aun as\u00ed se obtienen inserciones frecuentes. Y hay que evitar eso de alguna manera. <\/p>\n<p><\/p>\n<p>Desde un punto de vista t\u00e9cnico, la cuesti\u00f3n es que cuando haces un insert en ClickHouse, los datos no van a ninguna tabla de memoria. Ni siquiera tenemos un log structure MergeTree verdadero, solo un MergeTree, porque no hay log ni memTable. Simplemente, escribimos los datos directamente en el sistema de archivos, ya organizados por columnas. Y si tienes 100 columnas, tendr\u00e1s que escribir m\u00e1s de 200 archivos en un directorio separado. Todo esto es bastante voluminoso. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/24688fe3d39d81b92f12ac1b8b21425b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y surge la pregunta: \u00ab\u00bfC\u00f3mo hacerlo bien?\u00bb si la situaci\u00f3n es que de alguna manera necesitas registrar datos en ClickHouse.<\/p>\n<p><\/p>\n<p>M\u00e9todo 1. Este es el m\u00e9todo m\u00e1s sencillo. Utilizar alguna cola distribuida. Por ejemplo, Kafka. Simplemente sacas datos de Kafka, haciendo lotes una vez por segundo. Y todo funcionar\u00e1 bien, registras y todo funciona como se espera. <\/p>\n<p><\/p>\n<p>Las desventajas son que Kafka es otro sistema distribuido voluminoso. Entiendo si ya tienes Kafka en tu empresa. Esto es bueno, es conveniente. Pero si no lo tienes, vale la pena pensarlo dos veces antes de incorporar otro sistema distribuido en tu proyecto. Por lo tanto, se deben considerar alternativas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/4f687221e8c7443abf02fb002c4eba5b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>M\u00e9todo 2. Esta es una alternativa de la vieja escuela y, adem\u00e1s, muy simple. Tienes un servidor que genera tus registros. Simplemente guarda tus registros en un archivo. Y una vez por segundo, por ejemplo, renombramos ese archivo, abrimos uno nuevo. Y un script separado, ya sea mediante cron o alg\u00fan demonio, toma el archivo m\u00e1s antiguo y lo escribe en ClickHouse. Si los registros se escriben cada segundo, todo funcionar\u00e1 perfectamente. <\/p>\n<p><\/p>\n<p>Pero la desventaja de este m\u00e9todo es que si tu servidor, donde se generan los registros, desaparece, tambi\u00e9n se perder\u00e1n los datos.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/b4c28b6df87386c42b6908bdfccb6b90.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>M\u00e9todo 3. Hay otro m\u00e9todo interesante que no utiliza archivos temporales. Por ejemplo, puedes tener alg\u00fan tipo de servicio de publicidad o alg\u00fan otro demonio que genera datos. Y puedes acumular un conjunto de datos directamente en la memoria, en el b\u00fafer. Y cuando pasa suficiente tiempo, dejas ese b\u00fafer a un lado, creas uno nuevo y, en un hilo separado, introduces lo que ya se ha acumulado en ClickHouse.<\/p>\n<p><\/p>\n<p>Por otro lado, los datos tambi\u00e9n desaparecer\u00e1n con un kill -9. Si tu servidor falla, perder\u00e1s esos datos. Y hay otro problema: si no se puede escribir en la base de datos, los datos se seguir\u00e1n acumulando en la memoria. O se quedar\u00e1 sin memoria, o simplemente perder\u00e1s datos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/dc375b22fcb26cfa111d0bdb4563aa88.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>M\u00e9todo 4. Otro m\u00e9todo interesante. Tienes un proceso en el servidor. Y puede enviar datos a ClickHouse de inmediato, pero hacerlo en una sola conexi\u00f3n. Por ejemplo, env\u00edas una solicitud http con transfer-encoding: chunked con insert. Y genera fragmentos no muy raramente, se puede enviar cada l\u00ednea, aunque habr\u00e1 un overhead en el framing de esos datos. <\/p>\n<p><\/p>\n<p>Sin embargo, en este caso, los datos se enviar\u00e1n a ClickHouse de inmediato. Y ClickHouse los almacenar\u00e1 en b\u00fafer. <\/p>\n<p><\/p>\n<p>Pero tambi\u00e9n surgen problemas. Ahora perder\u00e1s datos, incluyendo cuando tu proceso se detenga y, si el proceso de ClickHouse se detiene, porque eso ser\u00e1 un insert incompleto. Y en ClickHouse los inserts son at\u00f3micos hasta un cierto umbral en t\u00e9rminos de n\u00famero de filas. En principio, es un m\u00e9todo interesante. Tambi\u00e9n se puede utilizar.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/6a18a974b9600ade377a870390e95d3d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>M\u00e9todo 5. Aqu\u00ed hay otro m\u00e9todo interesante. Es un servidor dise\u00f1ado por la comunidad para el procesamiento de datos por lotes. No lo he revisado yo mismo, as\u00ed que no puedo garantizar nada. Sin embargo, tampoco se ofrecen garant\u00edas para ClickHouse. Tambi\u00e9n es open source, pero por otro lado, podr\u00eda ser que est\u00e9s acostumbrado a un cierto est\u00e1ndar de calidad que tratamos de mantener. En cuanto a esta herramienta, no lo s\u00e9, visita GitHub y revisa el c\u00f3digo. Tal vez hayan escrito algo decente. <\/p>\n<p><\/p>\n<p>* a partir de 2020, tambi\u00e9n se debe a\u00f1adir para consideraci\u00f3n <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/vk\/blog\/430168\/\">KittenHouse<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/ae6a04af63ae4e7fa160c002fdb6d506.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>M\u00e9todo 6. Otro m\u00e9todo es el uso de tablas Buffer. La ventaja de este m\u00e9todo es que es muy f\u00e1cil de comenzar a usar. Creas una tabla Buffer y la llenas. <\/p>\n<p><\/p>\n<p>La desventaja es que el problema no se resuelve por completo. Si al insertar tipo MergeTree debes agrupar los datos por un lote por segundo, al insertar en una tabla buffer, necesitas agrupar al menos varios miles por segundo. Si hay m\u00e1s de 10,000 por segundo, a\u00fan as\u00ed habr\u00e1 problemas. Y si insertas en lotes, habr\u00e1s visto que ah\u00ed se obtienen cientos de miles de filas por segundo. Y esto ya con datos bastante pesados. <\/p>\n<p><\/p>\n<p>Adem\u00e1s, las tablas buffer no tienen registro. Y si algo va mal con tu servidor, los datos se perder\u00e1n. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/9bb16bf5e8145cc8368b11e54c86c837.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y como bonificaci\u00f3n, recientemente en ClickHouse se ha a\u00f1adido la posibilidad de extraer datos de Kafka. Existe un motor de tabla \u2013 Kafka. Simplemente lo creas. Y se le pueden a\u00f1adir vistas materializadas. En este caso, extraer\u00e1 autom\u00e1ticamente los datos de Kafka e insertar\u00e1 en las tablas que necesites. <\/p>\n<p><\/p>\n<p>Y lo que alegra especialmente de esta funcionalidad es que no lo hicimos nosotros. Es una funci\u00f3n de la comunidad. Y cuando digo 'funci\u00f3n de la comunidad', lo digo sin desd\u00e9n. Le\u00edmos el c\u00f3digo, hicimos revisiones, deber\u00eda funcionar bien. <\/p>\n<p><\/p>\n<p>* a partir de 2020, se a\u00f1adi\u00f3 soporte similar para <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/engines\/table-engines\/integrations\/rabbitmq\/\">RabbitMQ<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/15dc61dfd435f5f8640395b7de480fe2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfQu\u00e9 m\u00e1s puede ser inc\u00f3modo o inesperado al insertar datos? Si realizas una consulta insert values y en values escribes algunas expresiones calculadas. Por ejemplo, now() es tambi\u00e9n una expresi\u00f3n calculada. Y en este caso, ClickHouse se ve obligado a ejecutar el int\u00e9rprete de estas expresiones para cada fila, lo que hace que el rendimiento se desplome dr\u00e1sticamente. Es mejor evitarlo.<\/p>\n<p><\/p>\n<p>* En este momento, el problema est\u00e1 completamente solucionado, ya no hay regresiones en el rendimiento al usar expresiones en VALUES.<\/p>\n<p><\/p>\n<p>Otro ejemplo de posibles problemas es cuando en un solo lote los datos corresponden a m\u00faltiples particiones. Por defecto, en ClickHouse, las particiones son por meses. Y si insertas un lote de un mill\u00f3n de filas, y esos datos abarcan varios a\u00f1os, tendr\u00e1s varias decenas de particiones. Esto es equivalente a tener lotes de un tama\u00f1o varias decenas de veces menor, ya que dentro de ellos siempre se dividen primero por particiones.<\/p>\n<p><\/p>\n<p>* Recientemente, se ha a\u00f1adido en ClickHouse, en modo experimental, soporte para el formato compacto de partes y partes en memoria con registro de escritura anticipada, lo que casi resuelve por completo el problema.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/b8c6cecdba53559dad31ed11713a980d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ahora consideremos el segundo tipo de problema: la tipificaci\u00f3n de datos. <\/p>\n<p><\/p>\n<p>La tipificaci\u00f3n de datos puede ser estricta o de tipo cadena. La de tipo cadena es cuando simplemente declaras que todos tus campos son del tipo string. Eso es un desastre. No se debe hacer as\u00ed. <\/p>\n<p><\/p>\n<p>Vamos a descubrir c\u00f3mo hacerlo correctamente en aquellos casos en los que quieras indicar que un campo es una cadena, y que ClickHouse se encargue de ello, mientras t\u00fa no te preocupes demasiado. Pero de todos modos, vale la pena hacer algunos esfuerzos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/a0fdcf6423933293318411242fe2ede7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por ejemplo, tenemos una direcci\u00f3n IP. En un caso, la hemos guardado como una cadena. Por ejemplo, 192.168.1.1. Y en otro caso, ser\u00e1 un n\u00famero de tipo UInt32*. 32 bits son suficientes para una direcci\u00f3n IPv4.<\/p>\n<p><\/p>\n<p>Primero, y aunque parezca extra\u00f1o, los datos se comprimir\u00e1n de manera similar. Habr\u00e1 diferencias, por supuesto, pero no ser\u00e1n tan significativas. As\u00ed que no hay problemas especiales con la entrada\/salida del disco. <\/p>\n<p><\/p>\n<p>Pero hay una diferencia significativa en el tiempo de CPU y en el tiempo de ejecuci\u00f3n de la consulta. <\/p>\n<p><\/p>\n<p>Calculemos la cantidad de direcciones IP \u00fanicas, si se almacenan como n\u00fameros. Resulta que hay 137 millones de filas por segundo. Si lo mismo se hace como cadenas, son 37 millones de filas por segundo. No s\u00e9 por qu\u00e9 hay tal coincidencia. Yo mismo ejecut\u00e9 estas consultas. Sin embargo, de todos modos, es aproximadamente 4 veces m\u00e1s lento. <\/p>\n<p><\/p>\n<p>Y si calculamos la diferencia en espacio en disco, tambi\u00e9n hay una diferencia. Y esa diferencia es de aproximadamente una cuarta parte, porque hay un n\u00famero considerable de direcciones IP \u00fanicas. Si aqu\u00ed hubiera cadenas con una peque\u00f1a cantidad de valores diferentes, se habr\u00edan comprimido mediante diccionario a un volumen aproximadamente igual. <\/p>\n<p><\/p>\n<p>Y la diferencia de tiempo en la carretera no se desprecia. Puede que te d\u00e9 igual, pero cuando veo tal diferencia, me entristece.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/f74dbfdab5a9e26fa044a5870a8cc00d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Consideremos diferentes casos. <\/p>\n<p><\/p>\n<p>1. Un caso en el que tienes pocos valores \u00fanicos. En este caso, utilizamos una pr\u00e1ctica simple que probablemente ya conoces y que puedes aplicar a cualquier SGBD. Esto tiene sentido no solo para ClickHouse. Simplemente registras identificadores num\u00e9ricos en la base de datos. Y convertir a cadenas y viceversa se puede hacer ya en el lado de tu aplicaci\u00f3n. <\/p>\n<p><\/p>\n<p>Por ejemplo, tienes una regi\u00f3n. Y tratas de guardarla como una cadena. Y ah\u00ed podr\u00eda decir: Mosc\u00fa y la regi\u00f3n de Mosc\u00fa. Cuando veo que dice 'Mosc\u00fa', est\u00e1 bien, pero cuando tambi\u00e9n dice la regi\u00f3n de Mosc\u00fa, me entristece un poco. \u00bfCu\u00e1ntos bytes son? <\/p>\n<p><\/p>\n<p>En su lugar, simplemente registramos un n\u00famero Ulnt32 y 250. En Yandex tenemos 250, y quiz\u00e1s t\u00fa tengas un n\u00famero diferente. Solo para aclarar, ClickHouse tiene una capacidad integrada para trabajar con bases geogr\u00e1ficas. Simplemente registras un directorio con las regiones, incluidas las jer\u00e1rquicas, es decir, ah\u00ed estar\u00e1n Mosc\u00fa, la regi\u00f3n de Mosc\u00fa y todo lo que necesites. Y se puede convertir a nivel de consulta. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/cc6e871136dab8f8a35246a5af512cda.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La segunda opci\u00f3n es similar, pero ya con soporte interno en ClickHouse. Este es el tipo de datos Enum. Simplemente dentro de Enum escribes todos los valores que necesitas. Por ejemplo, el tipo de dispositivo, y ah\u00ed escribes: escritorio, m\u00f3vil, tableta, televisor. Solo 4 variantes. <\/p>\n<p><\/p>\n<p>El inconveniente es que hay que alterar peri\u00f3dicamente. Solo se a\u00f1ade una variante. Hacemos alter table. En realidad, hacer alter table en ClickHouse es gratuito. Especialmente es gratuito para Enum, porque los datos en disco no cambian. Sin embargo, alter bloquea la tabla y debe esperar a que se realicen todas las selecciones. Y solo despu\u00e9s de eso se ejecutar\u00e1 alter, es decir, todav\u00eda hay algunas incomodidades.<\/p>\n<p><\/p>\n<p>* en las versiones recientes de ClickHouse, ALTER se ha hecho completamente no bloqueante.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/d7284fa5be583ab063bb6de0b60f54d4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otra opci\u00f3n bastante \u00fanica para ClickHouse es la conexi\u00f3n de diccionarios externos. Puedes escribir n\u00fameros en ClickHouse, mientras que tus directorios pueden estar en cualquier sistema que prefieras. Por ejemplo, se puede utilizar: MySQL, Mongo, Postgres. Incluso puedes crear tu propio microservicio que entregue estos datos por http. Y a nivel de ClickHouse, escribes una funci\u00f3n que transformar\u00e1 estos datos de n\u00fameros a cadenas. <\/p>\n<p><\/p>\n<p>Este es un m\u00e9todo especializado, pero muy eficaz para realizar un join con una tabla externa. Existen dos variantes. En una de ellas, los datos estar\u00e1n completamente en cach\u00e9, completamente presentes en memoria y se actualizar\u00e1n peri\u00f3dicamente. En la otra variante, si los datos no caben en la memoria, se pueden almacenar en cach\u00e9 parcialmente. <\/p>\n<p><\/p>\n<p>Aqu\u00ed hay un ejemplo. Hay Yandex.Direct. Y all\u00ed hay campa\u00f1as publicitarias y banners. Probablemente haya alrededor de diez millones de campa\u00f1as publicitarias. Y aproximadamente caben en la memoria. En cuanto a los banners, son miles de millones y no caben. Utilizamos un diccionario almacenable en cach\u00e9 de MySQL.<\/p>\n<p><\/p>\n<p>El \u00fanico problema es que el diccionario almacenable en cach\u00e9 funcionar\u00e1 correctamente si la tasa de aciertos est\u00e1 cerca del 100%. Si es menor, entonces al procesar las solicitudes para cada lote de datos, realmente tendremos que obtener las claves faltantes y recuperar los datos de MySQL. En cuanto a ClickHouse, puedo asegurar que no se ralentiza; no hablar\u00e9 de otros sistemas.<\/p>\n<p><\/p>\n<p>Como bonus, los diccionarios son una forma muy sencilla de actualizar datos en ClickHouse retroactivamente. Es decir, si ten\u00eda un informe sobre campa\u00f1as publicitarias y el usuario simplemente cambi\u00f3 la campa\u00f1a, esos datos tambi\u00e9n cambian en todos los datos antiguos y en todos los informes. Si se escriben filas directamente en la tabla, su actualizaci\u00f3n ser\u00e1 imposible. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/a5a2919d6be7d00c0ad5875b9a8f0f31.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otro m\u00e9todo es cuando no sabe de d\u00f3nde obtener los identificadores para sus filas. Simplemente puede hacer un hash. Y la manera m\u00e1s sencilla es utilizar un hash de 64 bits. <\/p>\n<p><\/p>\n<p>El \u00fanico problema es que, si el hash es de 64 bits, habr\u00e1 colisiones casi seguramente. Porque si hay mil millones de filas, la probabilidad se vuelve significativa. <\/p>\n<p><\/p>\n<p>No ser\u00eda muy adecuado hacer as\u00ed el hash de los nombres de las campa\u00f1as publicitarias. Si las campa\u00f1as publicitarias de diferentes empresas se confunden, habr\u00e1 algo confuso. <\/p>\n<p><\/p>\n<p>Y hay un truco simple. Sin embargo, no es muy adecuado para datos serios, pero si se trata de algo no tan grave, simplemente a\u00f1ade el identificador del cliente a la clave del diccionario. Entonces habr\u00e1 colisiones, pero solo dentro de un mismo cliente. Este m\u00e9todo se utiliza en nuestro mapa de enlaces en Yandex.Metrica. Ah\u00ed tenemos URLs, almacenamos hashes. Y sabemos que, por supuesto, hay colisiones. Pero cuando se muestra la p\u00e1gina, la probabilidad de que en una sola p\u00e1gina a un mismo usuario se le agrupen algunas URLs y que se note, se puede ignorar. <\/p>\n<p><\/p>\n<p>Como bonificaci\u00f3n, para muchas operaciones solo se necesitan hashes y no es necesario almacenar las cadenas en ning\u00fan lugar. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/abbb73aaba29d10e3b7e7650bf68e6a6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otro ejemplo, si las cadenas son cortas, por ejemplo, los dominios de los sitios. Se pueden almacenar tal cual. O, por ejemplo, el idioma del navegador ru - 2 bytes. Claro, me da pena los bytes, pero no te preocupes, 2 bytes no son un gran problema. Por favor, almacena tal cual, no te complique. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/901eaed0029da6ea59630b57ccf80c25.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otro caso, cuando hay muchas cadenas y adem\u00e1s son muy \u00fanicas, y hay potencialmente muchas m\u00e1s. Un ejemplo t\u00edpico son las frases de b\u00fasqueda o URLs. Las frases de b\u00fasqueda, incluido por errores tipogr\u00e1ficos. Veamos cu\u00e1ntas frases de b\u00fasqueda \u00fanicas hay en un d\u00eda. Y resulta que son casi la mitad de todos los eventos. En este caso, podr\u00edas pensar que se necesita normalizar los datos, contar identificadores, y almacenarlos en una tabla separada. Pero no es necesario hacerlo. Simplemente almacena esas cadenas tal cual. <\/p>\n<p><\/p>\n<p>Mejor no te complicues, porque si se almacenan por separado, se necesitar\u00e1 hacer un join. Y este join, en el mejor de los casos, es acceso aleatorio a la memoria, si es que cabe en la memoria. Si no cabe, entonces habr\u00e1 problemas. <\/p>\n<p><\/p>\n<p>Y si los datos se almacenan in place, simplemente se leen en el orden necesario desde el sistema de archivos y todo est\u00e1 bien.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/15f1d632083def16ccbc939579c1cf6b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Si tienes URLs o alguna otra cadena larga y complicada, deber\u00edas pensar en contar alguna reducci\u00f3n de antemano y registrarla en una columna separada. <\/p>\n<p><\/p>\n<p>Para las URLs, por ejemplo, se puede almacenar el dominio por separado. Y si realmente necesitas el dominio, simplemente usa esa columna, y las URLs quedar\u00e1n all\u00ed, y ni siquiera tendr\u00e1s que tocarlas. <\/p>\n<p><\/p>\n<p>Veamos cu\u00e1l es la diferencia. En ClickHouse hay una funci\u00f3n especializada que calcula el dominio. Es muy r\u00e1pida, la hemos optimizado. Y, honestamente, no se ajusta al RFC, pero aun as\u00ed calcula todo lo que necesitamos. <\/p>\n<p><\/p>\n<p>En un caso, simplemente extraeremos las URLs y calcularemos el dominio. Esto toma 166 milisegundos. Y si tomamos un dominio ya preparado, solo tarda 67 milisegundos, es decir, casi tres veces m\u00e1s r\u00e1pido. Y esto no se debe a que tenemos que hacer c\u00e1lculos, sino porque leemos menos datos. <\/p>\n<p><\/p>\n<p>Por alguna raz\u00f3n, una consulta que es m\u00e1s lenta tiene una mayor velocidad de gigabytes por segundo. Porque lee m\u00e1s gigabytes. Estos son datos completamente innecesarios. La consulta parece funcionar m\u00e1s r\u00e1pido, pero toma m\u00e1s tiempo en completarse.<\/p>\n<p><\/p>\n<p>Si miramos el tama\u00f1o de los datos en el disco, vemos que la URL ocupa 126 megabytes, mientras que el dominio solo 5 megabytes. Esto resulta en 25 veces menos. Sin embargo, la consulta se completa solo 4 veces m\u00e1s r\u00e1pido. Esto se debe a que los datos son 'calientes'. Si fueran 'fr\u00edos', seguramente ser\u00eda 25 veces m\u00e1s r\u00e1pido debido a la entrada y salida de disco. <\/p>\n<p><\/p>\n<p>A prop\u00f3sito, si evaluamos cu\u00e1nto m\u00e1s peque\u00f1o es el dominio comparado con la URL, resulta que es aproximadamente cuatro veces menor. Pero extra\u00f1amente, en el disco, los datos ocupan 25 veces menos. \u00bfPor qu\u00e9? Debido a la compresi\u00f3n. Tanto la URL como el dominio se comprimen. Pero a menudo, la URL contiene un mont\u00f3n de basura. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/c93d2128a41561ed7abb25d77414bc2d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y, por supuesto, es importante usar los tipos de datos correctos que est\u00e1n dise\u00f1ados espec\u00edficamente para los valores necesarios o que son apropiados. Si est\u00e1s en IPv4, almacena como UInt32*. Si es IPv6, usa FixedString(16), porque la direcci\u00f3n IPv6 son 128 bits, es decir, almac\u00e9nala directamente en formato binario. <\/p>\n<p><\/p>\n<p>\u00bfY qu\u00e9 hacer si a veces tienes direcciones IPv4 y a veces IPv6? S\u00ed, puedes almacenar ambos. Una columna para IPv4, otra para IPv6. Claro, hay una opci\u00f3n de mostrar IPv4 en IPv6. Esto tambi\u00e9n funcionar\u00e1, pero si a menudo necesitas la direcci\u00f3n IPv4 en las consultas, ser\u00eda mejor tenerla en una columna separada. <\/p>\n<p><\/p>\n<p>* ahora en ClickHouse hay tipos de datos separados para IPv4, IPv6, que almacenan los datos tan eficientemente como n\u00fameros, pero los representan de manera tan conveniente como cadenas.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/d7d6342ebd6b8b4f3526b3cd8a06cf26.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tambi\u00e9n es importante mencionar que es conveniente preprocesar los datos de antemano. Por ejemplo, si recibes algunos registros en bruto. Y, puede que no debas simplemente volcarlos en ClickHouse, aunque es muy tentador no hacer nada y que todo funcione. Pero a\u00fan as\u00ed, vale la pena realizar los c\u00e1lculos que se puedan.<\/p>\n<p><\/p>\n<p>Por ejemplo, la versi\u00f3n del navegador. En un departamento cercano, al que no quiero se\u00f1alar con el dedo, la versi\u00f3n del navegador se almacena de esta manera, es decir, como una cadena: 12.3. Y luego, para hacer un informe, toman esta cadena y la dividen en un array, y luego toman el primer elemento del array. Por supuesto, todo se ralentiza. Les pregunt\u00e9 por qu\u00e9 hac\u00edan eso. Me respondieron que no les gusta la optimizaci\u00f3n prematura. Y a m\u00ed no me gusta la pesimizaci\u00f3n prematura.<\/p>\n<p><\/p>\n<p>Por lo tanto, en este caso ser\u00e1 m\u00e1s correcto dividir en 4 columnas. No se asusten, porque esto es ClickHouse. ClickHouse es una base de datos en columnas. Y cuantas m\u00e1s peque\u00f1as y ordenadas columnas haya, mejor ser\u00e1. Si hay 5 versiones del navegador, hagan 5 columnas. Es normal. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/f9a67221bf8508933d7bd336b16f9e04.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ahora consideremos qu\u00e9 hacer si tienes muchas cadenas largas, arrays muy largos. No necesitas almacenarlos en ClickHouse en absoluto. En su lugar, puedes guardar en ClickHouse solo alg\u00fan identificador. Y esas cadenas largas, col\u00f3calas en otro sistema. <\/p>\n<p><\/p>\n<p>Por ejemplo, en uno de nuestros servicios anal\u00edticos hay ciertos par\u00e1metros de eventos. Y si llegan muchos par\u00e1metros a los eventos, simplemente guardamos los primeros 512 que encontramos. Porque 512 no es un gran sacrificio. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/755271e8788ba4bd638f493bf320c820.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y si no puedes decidir sobre tus tipos de datos, tambi\u00e9n puedes grabar los datos en ClickHouse, pero en una tabla temporal de tipo Log, especial para datos temporales. Despu\u00e9s de eso, puedes analizar la distribuci\u00f3n de valores, qu\u00e9 hay en general y definir los tipos correctos.<\/p>\n<p><\/p>\n<p>* ahora en ClickHouse hay un tipo de dato <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/sql-reference\/data-types\/lowcardinality\/\">LowCardinality<\/a><\/noindex> que permite almacenar cadenas de manera eficiente con menor esfuerzo.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/7e9e53d86a4189783c28ce56a669198c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ahora consideremos otro caso interesante. A veces, las cosas parecen funcionar de manera extra\u00f1a. Entro y veo esto. Y enseguida se presenta la idea de que esto fue hecho por un administrador muy experimentado e inteligente, con una gran experiencia en la configuraci\u00f3n de MySQL versi\u00f3n 3.23. <\/p>\n<p><\/p>\n<p>Aqu\u00ed vemos mil tablas, cada una de las cuales tiene un residuo de una divisi\u00f3n de algo indeterminado entre mil. <\/p>\n<p><\/p>\n<p>En principio, respeto la experiencia ajena, tambi\u00e9n entiendo qu\u00e9 sufrimientos pueden haber dado lugar a esa experiencia. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/3a5e21ef2076966fcc627670485c5b3a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y las razones son m\u00e1s o menos claras. Son viejos estereotipos que pudieron acumularse al trabajar con otros sistemas. Por ejemplo, en MyISAM las tablas no tienen una clave primaria clustered. Y este m\u00e9todo de dividir datos puede ser un intento desesperado de obtener la misma funcionalidad. <\/p>\n<p><\/p>\n<p>Otra raz\u00f3n es que realizar operaciones como alter sobre tablas grandes es dif\u00edcil. Todo se bloquear\u00e1. Aunque en las versiones modernas de MySQL este problema ya no es tan serio. <\/p>\n<p><\/p>\n<p>O, por ejemplo, micrShardering, pero de eso hablaremos un poco m\u00e1s tarde.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/321b1d9caa8db7aca5b96e08c61d05b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En ClickHouse no hace falta hacer eso, porque, en primer lugar, la clave primaria es clustered, los datos est\u00e1n ordenados por la clave primaria. <\/p>\n<p><\/p>\n<p>Y a veces me preguntan: \"\u00bfC\u00f3mo cambia el rendimiento de las consultas por rango en ClickHouse en funci\u00f3n del tama\u00f1o de la tabla?\". Yo digo que no cambia en absoluto. Por ejemplo, si tienes una tabla de mil millones de filas y lees un rango de un mill\u00f3n de filas. Todo est\u00e1 bien. Si en la tabla hay un bill\u00f3n de filas y lees un mill\u00f3n de filas, ser\u00e1 pr\u00e1cticamente lo mismo. <\/p>\n<p><\/p>\n<p>Y, en segundo lugar, no se requieren cosas como particiones manuales. Si entras y miras lo que hay en el sistema de archivos, ver\u00e1s que la tabla es algo bastante serio. Y dentro hay algo como particiones. Es decir, ClickHouse lo hace todo por ti y no necesitas sufrir.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/652f3742ad3a44f172d0d7302abd09f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>El alter en ClickHouse es gratuito si es alter add\/drop column. <\/p>\n<p><\/p>\n<p>Y no vale la pena crear tablas peque\u00f1as, porque si tienes 10 filas o 10,000 filas en la tabla, no importa en absoluto. ClickHouse es un sistema que optimiza el rendimiento, no la latencia, as\u00ed que procesar 10 filas no tiene sentido. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/144144b4740e9c5daec80c8dadc445f9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Es correcto usar una tabla grande. Deshazte de los viejos estereotipos, todo estar\u00e1 bien. <\/p>\n<p><\/p>\n<p>Y como bono, en nuestra \u00faltima versi\u00f3n ha surgido la posibilidad de hacer una clave de particionamiento arbitraria para realizar diversas operaciones de mantenimiento en particiones individuales. <\/p>\n<p><\/p>\n<p>Por ejemplo, necesitas muchas tablas peque\u00f1as, como cuando hay una necesidad de procesar algunos datos intermedios, recibes fragmentos y necesitas realizar transformaciones sobre ellos antes de escribir en la tabla final. Para este caso, hay un motor de tablas excelente: StripeLog. Es similar a TinyLog, pero mejor. <\/p>\n<p><\/p>\n<p>* ahora en ClickHouse tambi\u00e9n hay <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/sql-reference\/table-functions\/input\/\">la funci\u00f3n de tabla input<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/d62f0b3d29876c29c6c0ba236b200186.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otro antipatr\u00f3n es el microsharding. Por ejemplo, necesitas shardear los datos y tienes 5 servidores, pero ma\u00f1ana habr\u00e1 6 servidores. Y piensas en c\u00f3mo equilibrar esos datos. En lugar de eso, divides no en 5 shards, sino en 1,000 shards. Luego, asignas cada uno de estos microshards a un servidor diferente. As\u00ed, tendr\u00e1s en un servidor, por ejemplo, 200 ClickHouse, por ejemplo. Instancias separadas en puertos distintos o bases de datos separadas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/3e550ef7e338b84e4394eb9fa4538769.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pero en ClickHouse esto no es muy bueno. Porque incluso una instancia de ClickHouse intenta utilizar todos los recursos disponibles del servidor para procesar una sola consulta. Es decir, tienes un servidor con, por ejemplo, 56 n\u00facleos de procesamiento. Realizas una consulta que tarda un segundo en ejecutarse, y utilizar\u00e1 56 n\u00facleos. Si colocaste 200 ClickHouse en un solo servidor, resulta que se iniciar\u00e1n 10,000 hilos. En general, ser\u00e1 un desastre.<\/p>\n<p><\/p>\n<p>Otra raz\u00f3n es que la distribuci\u00f3n del trabajo entre estas instancias ser\u00e1 desigual. Algunas terminar\u00e1n antes, otras despu\u00e9s. Si todo ocurriera en una \u00fanica instancia, ClickHouse podr\u00eda manejar c\u00f3mo distribuir correctamente los datos entre los hilos. <\/p>\n<p><\/p>\n<p>Y otra raz\u00f3n es que habr\u00e1 interacci\u00f3n interprocesador a trav\u00e9s de TCP. Los datos tendr\u00e1n que ser serializados, deserializados y, con esta enorme cantidad de microshards, simplemente no funcionar\u00e1 de manera eficiente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/18cacc17d22ae1cb2977c6be74769896.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otro antipatr\u00f3n, aunque es dif\u00edcil de clasificar como tal, es una gran cantidad de preagregaci\u00f3n.<\/p>\n<p><\/p>\n<p>En general, la preagregaci\u00f3n es buena. Ten\u00edas mil millones de filas, las agregaste y ahora tienes 1,000 filas, y la consulta se ejecuta al instante. Todo es maravilloso. Se puede hacer as\u00ed. Y para ello, incluso en ClickHouse hay un tipo especial de tabla, AggregatingMergeTree, que realiza preagregaci\u00f3n incremental a medida que se insertan datos. <\/p>\n<p><\/p>\n<p>Pero hay ocasiones en las que piensas que vamos a agregar datos as\u00ed y tambi\u00e9n as\u00ed. Y en alg\u00fan departamento vecino, tampoco quiero decir cu\u00e1l, utilizan tablas SummingMergeTree para sumar por la clave primaria, y como clave primaria utilizan unas 20 columnas variadas. He cambiado por si acaso algunos nombres de columnas para la discreci\u00f3n, pero es m\u00e1s o menos as\u00ed.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/54e3a02ab4bbce7c63ded595780ae1f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y surgen problemas as\u00ed. En primer lugar, el volumen de datos no se reduce mucho. Por ejemplo, se reduce a tres veces. Tres veces ser\u00eda un buen precio para permitirse posibilidades ilimitadas en an\u00e1lisis, las cuales surgen si los datos no est\u00e1n agregados. Si los datos est\u00e1n agregados, en lugar de an\u00e1lisis obtienes solo estad\u00edsticas lamentables. <\/p>\n<p><\/p>\n<p>\u00bfY qu\u00e9 es lo que realmente molesta? Que estas personas del departamento vecino vienen y a veces piden a\u00f1adir otra columna a la clave primaria. Es decir, as\u00ed hemos agregado los datos, y ahora queremos un poco m\u00e1s. Pero en ClickHouse no hay un comando para modificar la clave primaria. As\u00ed que hay que escribir alg\u00fan tipo de scripts en C++. Y no me gustan los scripts, incluso si son en C++.<\/p>\n<p><\/p>\n<p>Y si miras para qu\u00e9 fue creado ClickHouse, los datos no agregados son justo el escenario para el cual naci\u00f3. Si utilizas ClickHouse para datos no agregados, est\u00e1s haciendo todo bien. Si agregas, a veces es comprensible. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/09fafd4c8a3ea8c22e586cb7a5cf6564.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Otro caso interesante son las consultas en un ciclo infinito. A veces accedo a alg\u00fan servidor de producci\u00f3n y miro el show processlist. Y cada vez descubro que est\u00e1 ocurriendo algo horrible. <\/p>\n<p><\/p>\n<p>Por ejemplo, esto. Aqu\u00ed est\u00e1 claro que todo podr\u00eda haberse ejecutado en una sola consulta. Simplemente escribe all\u00ed url in y la lista.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/ae03b659f178962f50e0640614517296.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfPor qu\u00e9 tener muchas consultas en un ciclo infinito es malo? Si no se utiliza un \u00edndice, tendr\u00e1s muchos recorridos por los mismos datos. Pero si se utiliza un \u00edndice, por ejemplo, tienes una clave primaria por ru y escribes url = algo. Y piensas que leer\u00e1 de la tabla un solo url, todo estar\u00e1 bien. Pero en realidad no es as\u00ed. Porque ClickHouse lo hace todo por lotes. <\/p>\n<p><\/p>\n<p>Cuando necesita leer un rango de datos, lee un poco m\u00e1s porque el \u00edndice en ClickHouse es disperso. Este \u00edndice no permite encontrar una fila individual en la tabla, solo un rango. Y los datos se comprimen en bloques. Para leer una fila, hay que tomar todo un bloque y descomprimirlo. Y si realiza muchas consultas, tendr\u00e1 muchas intersecciones de estas, y mucho trabajo se estar\u00e1 realizando una y otra vez.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/95eef43c5b869f8b145c61ce3c616cfd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y como bonus, se puede notar que en ClickHouse no hay que tener miedo de pasar incluso megabytes y hasta cientos de megabytes en la secci\u00f3n IN. Recuerdo de nuestra pr\u00e1ctica que si en MySQL pasamos un mont\u00f3n de valores en la secci\u00f3n IN, por ejemplo, pasamos 100 megabytes de algunos n\u00fameros, entonces MySQL consume 10 gigabytes de memoria y no sucede nada m\u00e1s, todo funciona mal. <\/p>\n<p><\/p>\n<p>Y lo segundo es que en ClickHouse, si sus consultas utilizan un \u00edndice, nunca ser\u00e1 m\u00e1s lento que un escaneo completo, es decir, si se necesita leer casi toda la tabla, lo har\u00e1 de manera secuencial y leer\u00e1 toda la tabla. En general, se las arreglar\u00e1 solo.<\/p>\n<p><\/p>\n<p>Sin embargo, hay algunas dificultades. Por ejemplo, el IN con una subconsulta no utiliza el \u00edndice. Pero ese es nuestro problema y debemos solucionarlo. No hay nada fundamental aqu\u00ed. Lo estaremos arreglando. <\/p>\n<p><\/p>\n<p>Y otra cosa interesante es que si tiene una consulta muy larga y el procesamiento de consultas es distribuido, entonces esta consulta muy larga se enviar\u00e1 a cada servidor sin compresi\u00f3n. Por ejemplo, 100 megabytes y 500 servidores. Y, por lo tanto, se transmitir\u00e1n 50 gigabytes por la red. Se transmitir\u00e1 y luego todo se ejecutar\u00e1 correctamente.<\/p>\n<p><\/p>\n<p>* ya se est\u00e1 utilizando; todo lo repararon, como se prometi\u00f3.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/5fcde9bf04fff0645be2530daa12743f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y es un caso bastante frecuente que las consultas provienen de API. Por ejemplo, cre\u00f3 alg\u00fan servicio. Y si su servicio es necesario para alguien, abre un API y literalmente en dos d\u00edas ve que sucede algo incomprensible. Todo est\u00e1 sobrecargado y llegan algunas consultas horrorosas que nunca debieron ser. <\/p>\n<p><\/p>\n<p>Y la soluci\u00f3n es una. Si ha abierto un API, tendr\u00e1 que limitarlo. Por ejemplo, introducir cuotas. No hay otras opciones normales. De lo contrario, inmediatamente escribir\u00e1n un script y habr\u00e1 problemas. <\/p>\n<p><\/p>\n<p>En ClickHouse hay una funci\u00f3n especial: el conteo de cuotas. Se puede pasar su propia clave de cuota, que puede ser, por ejemplo, un identificador interno de usuario. Las cuotas se calcular\u00e1n de forma independiente para cada uno de ellos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/532438d0f116919e62f04e32ebbd3c45.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ahora hay otra cosa interesante. Es la replicaci\u00f3n manual. <\/p>\n<p><\/p>\n<p>Conozco muchos casos en los que, a pesar de que ClickHouse tiene soporte incorporado para la replicaci\u00f3n, las personas replican ClickHouse manualmente.<\/p>\n<p><\/p>\n<p>\u00bfCu\u00e1l es el principio? Tienes un pipeline de procesamiento de datos. Y funciona de manera independiente, por ejemplo, en diferentes centros de datos. Est\u00e1s escribiendo los mismos datos de la misma manera en ClickHouse. Sin embargo, la pr\u00e1ctica muestra que los datos seguir\u00e1n divergentes debido a algunas peculiaridades en tu c\u00f3digo. Espero que en el tuyo no sea as\u00ed. <\/p>\n<p><\/p>\n<p>Y peri\u00f3dicamente todav\u00eda tendr\u00e1s que sincronizar manualmente. Por ejemplo, una vez al mes, los administradores hacen un rsync.<\/p>\n<p><\/p>\n<p>En realidad, es mucho m\u00e1s f\u00e1cil utilizar la replicaci\u00f3n integrada en ClickHouse. Pero aqu\u00ed puede haber algunas contraindicaciones, ya que para esto se necesita usar ZooKeeper. No dir\u00e9 nada malo sobre ZooKeeper, en principio, el sistema funciona, pero a veces las personas no lo utilizan por fobia a Java, porque ClickHouse es un excelente sistema escrito en C++ que se puede utilizar y funcionar\u00e1 a la perfecci\u00f3n. Y ZooKeeper est\u00e1 en Java. Y de alguna manera no se quiere mirar, pero entonces se puede usar la replicaci\u00f3n manual. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/3b5b68996daef6b8920f067b189f25e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>ClickHouse es un sistema pr\u00e1ctico. Tiene en cuenta tus necesidades. Si tienes replicaci\u00f3n manual, puedes crear una tabla Distributed que observe tus r\u00e9plicas manuales y realice un failover entre ellas. Y hay incluso una opci\u00f3n especial que permite evitar flaps, incluso si tus r\u00e9plicas divergen sistem\u00e1ticamente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/70f6630f8b14756163923a7db8dd7391.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A continuaci\u00f3n, pueden surgir problemas si usas motores de tabla primitivos. ClickHouse es como un constructor que tiene un mont\u00f3n de diferentes motores de tablas. Para todos los casos serios, como se indica en la documentaci\u00f3n, utiliza tablas de la familia MergeTree. Los dem\u00e1s son as\u00ed, para casos aislados o para pruebas.<\/p>\n<p><\/p>\n<p>En la tabla MergeTree no es necesario que tengas alguna fecha y hora. A\u00fan as\u00ed, puedes usarlas. Si no hay fecha y hora, escribe que el default es el a\u00f1o 2000. Esto funcionar\u00e1 y no requerir\u00e1 recursos. <\/p>\n<p><\/p>\n<p>En la nueva versi\u00f3n del servidor, incluso puede especificar que tenga un particionamiento personalizado sin clave de partici\u00f3n. Ser\u00e1 lo mismo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/6d4046d11afdd1e5962d49a1612b666a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por otro lado, se pueden utilizar motores de tablas primitivos. Por ejemplo, cargar datos una vez y observar, manipular y eliminar. Puede usar Log.<\/p>\n<p><\/p>\n<p>O almacenar peque\u00f1os vol\u00famenes para procesamiento intermedio: eso es StripeLog o TinyLog.<\/p>\n<p><\/p>\n<p>Memory se puede usar si hay un peque\u00f1o volumen de datos y simplemente desea manipular algo en la RAM. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/8a3d4e0e3a8c26dd3a2b2f64123e2bf9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>ClickHouse no es muy compatible con datos sobre-normalizados. <\/p>\n<p><\/p>\n<p>Aqu\u00ed hay un ejemplo t\u00edpico. Es una gran cantidad de URLs. Las metiste en una tabla secundaria. Y luego decidiste hacer un JOIN, pero eso no funcionar\u00e1, por lo general, porque ClickHouse solo admite Hash JOIN. Si la RAM no es suficiente para la gran cantidad de datos que se necesitan unir, no podr\u00e1s realizar el JOIN*. <\/p>\n<p><\/p>\n<p>Si los datos tienen alta cardinalidad, no te preocupes, gu\u00e1rdalos en forma denormalizada, las URLs directamente en la tabla principal. <\/p>\n<p><\/p>\n<p>* Ahora ClickHouse tambi\u00e9n tiene merge join, y funciona cuando los datos intermedios no caben en la RAM. Pero eso no es eficiente y la recomendaci\u00f3n sigue siendo v\u00e1lida.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/e8160a8db17c18d48f810092c55b094c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aqu\u00ed hay un par de ejemplos m\u00e1s, pero ya empiezo a dudar de si son antipatr\u00f3n o no. <\/p>\n<p><\/p>\n<p>ClickHouse tiene una desventaja conocida. No puede realizar actualizaciones*. En cierto modo, eso es incluso bueno. Si tienes alg\u00fan dato importante, por ejemplo, en contabilidad, nadie podr\u00e1 enviarlo, porque no hay actualizaciones.<\/p>\n<p><\/p>\n<p>* Ya se ha a\u00f1adido el soporte para actualizaciones y eliminaciones en modo batch.<\/p>\n<p><\/p>\n<p>Pero hay algunos m\u00e9todos especiales que permiten hacer actualizaciones como si fuera en segundo plano. Por ejemplo, tablas del tipo ReplaceMergeTree. Realizan actualizaciones durante las fusiones en segundo plano. Puedes forzarlo usando optimize table. Pero no lo hagas con demasiada frecuencia, porque eso implicar\u00eda una reescritura completa de la partici\u00f3n. <\/p>\n<p><\/p>\n<p>Los JOIN distribuidos en ClickHouse tambi\u00e9n son mal tratados por el planificador de consultas. <\/p>\n<p><\/p>\n<p>Mal, pero a veces est\u00e1 bien.<\/p>\n<p><\/p>\n<p>Usar ClickHouse solo para leer datos nuevamente mediante select*.<\/p>\n<p><\/p>\n<p>No recomendar\u00eda utilizar ClickHouse para c\u00e1lculos dif\u00edciles. Pero no es del todo cierto, porque ya estamos alej\u00e1ndonos de esa recomendaci\u00f3n. Y recientemente hemos a\u00f1adido la posibilidad de aplicar modelos de aprendizaje autom\u00e1tico en ClickHouse: Catboost. Y esto me preocupa, porque pienso: '\u00a1Qu\u00e9 horror! \u00bfCu\u00e1ntos ciclos por byte obtenemos?'. Me duele desperdiciar ciclos en bytes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso efectivo de ClickHouse. Alexei Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/f686d5d352ccb444cd06e2ae68897137.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pero no temas, instala ClickHouse, todo estar\u00e1 bien. Si algo, tenemos una comunidad. Por cierto, la comunidad son ustedes. Y si tienen alg\u00fan problema, al menos pueden entrar a nuestro chat, y espero que les ayuden. <\/p>\n<p><\/p>\n<p>Preguntas<\/p>\n<p><\/p>\n<p><em>\u00a1Gracias por la presentaci\u00f3n! \u00bfD\u00f3nde puedo quejarme de la ca\u00edda de ClickHouse?<\/em><\/p>\n<p><\/p>\n<p>Pueden quejarse conmigo personalmente ahora mismo. <\/p>\n<p><\/p>\n<p><em>Recientemente comenc\u00e9 a usar ClickHouse. Ca\u00ed el cli inmediatamente.<\/em><\/p>\n<p><\/p>\n<p>Tienes suerte. <\/p>\n<p><\/p>\n<p><em>Un poco m\u00e1s tarde ca\u00ed el servidor con un peque\u00f1o select.<\/em><\/p>\n<p><\/p>\n<p>Tienes talento. <\/p>\n<p><\/p>\n<p><em>Abr\u00ed un bug en GitHub, pero lo ignoraron.<\/em> <\/p>\n<p><\/p>\n<p>Veremos. <\/p>\n<p><\/p>\n<p><em>Aleksey me enga\u00f1\u00f3 para que asistiera a la presentaci\u00f3n, prometiendo contar c\u00f3mo presionan los datos internamente.<\/em><\/p>\n<p><\/p>\n<p>Es muy sencillo. <\/p>\n<p><\/p>\n<p><em>Eso ya lo entend\u00ed ayer. M\u00e1s concretamente.<\/em> <\/p>\n<p><\/p>\n<p>No hay trucos horribles all\u00ed. Simplemente compresi\u00f3n por bloques. Por defecto se usa LZ4, se puede activar ZSTD*. Bloques de 64 kilobytes a 1 megabyte.<\/p>\n<p><\/p>\n<p>* tambi\u00e9n hay soporte para c\u00f3decs de compresi\u00f3n especializados que se pueden usar en cadena con otros algoritmos.<\/p>\n<p><\/p>\n<p><em>\u00bfLos bloques simplemente contienen datos en crudo?<\/em><\/p>\n<p><\/p>\n<p>No son totalmente crudos. Hay matrices. Si tienes una columna num\u00e9rica, los n\u00fameros est\u00e1n dispuestos en una matriz. <\/p>\n<p><\/p>\n<p><em>Entiendo.<\/em> <\/p>\n<p><\/p>\n<p><em>Aleksey, el ejemplo que tuvimos con uniqExact sobre direcciones IP, es decir, lo que uniqExact se calcula m\u00e1s lento en cadenas que en n\u00fameros, etc. \u00bfY si aplicamos una maniobra y hacemos un casting en el momento de la lectura? Es decir, ustedes dijeron que en el disco no var\u00eda mucho. Si leemos las cadenas desde el disco y hacemos casting, \u00bfentonces nuestros agregados ser\u00e1n m\u00e1s r\u00e1pidos o no? \u00bfO de hecho no ganamos significativamente aqu\u00ed? Me parece que ustedes lo testearon, pero por alguna raz\u00f3n no lo indicaron en el benchmark.<\/em> <\/p>\n<p><\/p>\n<p>Creo que ser\u00e1 m\u00e1s lento que sin el casting. En este caso, hay que analizar la direcci\u00f3n IP de la cadena. Por supuesto, en ClickHouse tambi\u00e9n optimizamos el an\u00e1lisis de direcciones IP. Hicimos un gran esfuerzo, pero all\u00ed los n\u00fameros est\u00e1n registrados en forma de diez mil\u00e9simas. Es muy inc\u00f3modo. Por otro lado, la funci\u00f3n uniqExact funcionar\u00e1 m\u00e1s lentamente con cadenas, no solo porque son cadenas, sino tambi\u00e9n porque se elige otra especializaci\u00f3n del algoritmo. Las cadenas simplemente se procesan de manera diferente.<\/p>\n<p><\/p>\n<p><em>\u00bfY si tomamos un tipo de dato m\u00e1s primitivo? Por ejemplo, escribimos el user id que tenemos en, lo anotamos como cadena, y luego lo casteamos, \u00bfser\u00e1 m\u00e1s divertido o no?<\/em><\/p>\n<p><\/p>\n<p>Dudo. Creo que ser\u00e1 incluso m\u00e1s triste, porque analizar n\u00fameros sigue siendo un problema serio. Me parece que este colega incluso tuvo una charla sobre lo dif\u00edcil que es analizar n\u00fameros en forma de diez mil\u00e9simas, o tal vez no. <\/p>\n<p><\/p>\n<p><em>\u00a1Alexey, muchas gracias por la charla! Y tambi\u00e9n muchas gracias por ClickHouse. Tengo una pregunta sobre los planes. \u00bfHay planes para una caracter\u00edstica que permita actualizar diccionarios de manera parcial?<\/em><\/p>\n<p><\/p>\n<p>Es decir, \u00bfrecarga parcial?<\/p>\n<p><\/p>\n<p><em>S\u00ed, s\u00ed. Como la posibilidad de especificar un campo en MySQL, es decir, actualizar despu\u00e9s, para que solo se carguen esos datos si el diccionario es muy grande.<\/em><\/p>\n<p><\/p>\n<p>Es una caracter\u00edstica muy interesante. Y creo que alguien la propuso en nuestro chat. Podr\u00eda ser que fuiste t\u00fa. <\/p>\n<p><\/p>\n<p><em>No creo que lo haya hecho.<\/em><\/p>\n<p><\/p>\n<p>Excelente, as\u00ed que ahora hay dos solicitudes. Y se puede empezar a hacerlo sin prisa. Pero quiero advertirte que esta caracter\u00edstica es bastante simple de implementar. Es decir, en teor\u00eda solo hay que escribir el n\u00famero de versi\u00f3n en la tabla y luego escribir: versi\u00f3n menor que tal. Y esto significa que, probablemente, le sugeriremos hacerlo a los entusiastas. \u00bfEres un entusiasta? <\/p>\n<p><\/p>\n<p><em>S\u00ed, pero, desafortunadamente, no en C++.<\/em><\/p>\n<p><\/p>\n<p>\u00bfTus colegas saben escribir en C++? <\/p>\n<p><\/p>\n<p><em>Encontrar\u00e9 a alguien.<\/em><\/p>\n<p><\/p>\n<p>Excelente*.<\/p>\n<p><\/p>\n<p>* la posibilidad fue a\u00f1adida dos meses despu\u00e9s de la charla \u2013 la desarroll\u00f3 el autor de la pregunta y la envi\u00f3. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/ClickHouse\/ClickHouse\/pull\/1771\">pull request<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><em>\u00a1Gracias!<\/em><\/p>\n<p><\/p>\n<p><em>\u00a1Hola! \u00a1Gracias por la presentaci\u00f3n! Mencionaste que ClickHouse consume muy bien todos los recursos disponibles. Y el presentador de Luxoft hablaba sobre su soluci\u00f3n para Correos de Rusia. Dijo que estaban muy satisfechos con ClickHouse, pero no lo usaron en lugar de su principal competidor precisamente porque consum\u00eda todo el procesador. Y no pudieron integrarlo en su arquitectura, en su ZooKeeper con Docker. \u00bfHay alguna forma de limitar a ClickHouse para que no consuma todo lo que le est\u00e1 disponible?<\/em><\/p>\n<p><\/p>\n<p>S\u00ed, se puede y es muy f\u00e1cil. Si deseas que consuma menos n\u00facleos, simplemente escribe <code>set max_threads = 1<\/code>. Y listo, la consulta se ejecutar\u00e1 en un n\u00facleo. Adem\u00e1s, se puede configurar este ajuste de manera diferente para distintos usuarios. As\u00ed que no hay problemas. Y diles a mis colegas de Luxoft que no est\u00e1 bien que no encontraran esta configuraci\u00f3n en la documentaci\u00f3n. <\/p>\n<p><\/p>\n<p><em>\u00a1Hola, Alexey! Quer\u00eda preguntarte sobre algo. Ya no es la primera vez que escucho que muchos comienzan a usar ClickHouse como almacenamiento de logs. En la presentaci\u00f3n dijiste que no deber\u00edan hacerlo, es decir, no hay que almacenar cadenas largas. \u00bfCu\u00e1l es tu opini\u00f3n al respecto?<\/em><\/p>\n<p><\/p>\n<p>Primero que nada, los logs, por lo general, no son cadenas largas. Por supuesto, hay excepciones. Por ejemplo, alg\u00fan servicio escrito en Java que lanza una excepci\u00f3n y se registra. Y as\u00ed en un ciclo infinito, ocupando el espacio en el disco duro. La soluci\u00f3n es muy simple. Si las cadenas son muy largas, c\u00f3rtalas. \u00bfY qu\u00e9 significa largas? Decenas de kilobytes est\u00e1 mal.<\/p>\n<p><\/p>\n<p>* en las versiones recientes de ClickHouse, se ha incluido la \"granularidad adaptativa del \u00edndice\", lo que elimina en gran medida el problema de almacenamiento de cadenas largas.<\/p>\n<p><\/p>\n<p><em>\u00bfY un kilobyte est\u00e1 bien?<\/em><\/p>\n<p><\/p>\n<p>Est\u00e1 bien. <\/p>\n<p><\/p>\n<p><em>\u00a1Hola! \u00a1Gracias por la presentaci\u00f3n! Ya hice esta pregunta en el chat, pero no recuerdo si recib\u00ed respuesta. \u00bfSe planea expandir la secci\u00f3n WITH a la manera de CTE?<\/em><\/p>\n<p><\/p>\n<p>Por ahora no. La secci\u00f3n WITH es algo poco seria. Para nosotros es solo una peque\u00f1a caracter\u00edstica.<\/p>\n<p><\/p>\n<p><em>Entiendo. \u00a1Gracias!<\/em><\/p>\n<p><\/p>\n<p><em>\u00a1Gracias por la presentaci\u00f3n! \u00a1Muy interesante! Una pregunta global. \u00bfSe planea hacer, quiz\u00e1s, alguna modificaci\u00f3n para la eliminaci\u00f3n de datos en forma de marcadores?<\/em><\/p>\n<p><\/p>\n<p>Sin falta. Esa es nuestra primera tarea en la cola. Actualmente estamos pensando activamente en c\u00f3mo hacer todo correctamente. Y es el momento de empezar a teclear.<\/p>\n<p><\/p>\n<p>* pulsamos las teclas del teclado y lo hicimos todo.<\/p>\n<p><\/p>\n<p><em>\u00bfEsto afectar\u00e1 de alguna manera el rendimiento del sistema o no? \u00bfLa inserci\u00f3n seguir\u00e1 siendo tan r\u00e1pida como ahora?<\/em><\/p>\n<p><\/p>\n<p>Es posible que las eliminaciones y actualizaciones sean muy pesadas, pero esto no afectar\u00e1 el rendimiento de las selecciones ni de las inserciones.<\/p>\n<p><\/p>\n<p><em>Y otra peque\u00f1a pregunta. En la presentaci\u00f3n hablaste sobre la clave primaria. Por lo tanto, tenemos particionamiento, que por defecto es mensual, \u00bfcorrecto? Y cuando establecemos un rango de fechas que cabe dentro de un mes, solo se lee esa partici\u00f3n, \u00bfverdad?<\/em><\/p>\n<p><\/p>\n<p>S\u00ed.<\/p>\n<p><\/p>\n<p><em>Una pregunta. Si no podemos identificar ninguna clave primaria, \u00bfes correcto hacerla por el campo 'Fecha' para que en segundo plano haya menos reestructuraci\u00f3n de esos datos, para que est\u00e9n m\u00e1s ordenados? Si no tienes consultas de rango y no puedes elegir ninguna clave primaria, \u00bfvale la pena incluir la fecha en la clave primaria?<\/em><\/p>\n<p><\/p>\n<p>S\u00ed.<\/p>\n<p><\/p>\n<p>Quiz\u00e1s tenga sentido incluir en la clave primaria un campo que permita que los datos se compriman mejor si est\u00e1n ordenados por ese campo. Por ejemplo, el identificador del usuario. El usuario, por ejemplo, visita el mismo sitio web. En este caso, pones el id del usuario y el tiempo. As\u00ed los datos se comprimir\u00e1n mejor. En cuanto a la fecha, si realmente no tienes y nunca tienes consultas de rango por fechas, entonces no es necesario incluir la fecha en la clave primaria. <\/p>\n<p><\/p>\n<p><em>\u00a1Bien, muchas gracias!<\/em><\/p>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/514840\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0422\u0430\u043a \u043a\u0430\u043a ClickHouse \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439, \u043f\u0440\u0438 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0432\u0430\u0436\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0435\u0433\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b. \u0412 \u044d\u0442\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u0442 \u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 ClickHouse, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043d\u0435\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435. \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u0432\u044b\u0431\u043e\u0440 \u0442\u043e\u0439 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u0441\u0445\u0435\u043c\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u043f\u043e\u0440\u044f\u0434\u043a\u0438. \u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":91439,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-91438","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u042d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 ClickHouse. \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041c\u0438\u043b\u043e\u0432\u0438\u0434\u043e\u0432 (\u042f\u043d\u0434\u0435\u043a\u0441) | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-08-13T17:42:36+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-08-13T17:42:36+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Uso eficiente de ClickHouse. Alexey Milovidov (Yandex) | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u042d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 ClickHouse. \u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u041c\u0438\u043b\u043e\u0432\u0438\u0434\u043e\u0432 (\u042f\u043d\u0434\u0435\u043a\u0441) | ProHoster","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-08-13T17:42:36+00:00","article:modified_time":"2020-08-13T17:42:36+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"91438","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:27:23","updated":"2022-09-28 17:25:41","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/91438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=91438"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/91438\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/91439"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=91438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=91438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=91438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}