{"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\/pt\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks","title":{"rendered":"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/8e42c1fffffcc964eacef240ea90bbc5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como o ClickHouse \u00e9 um sistema especializado, \u00e9 importante considerar as caracter\u00edsticas de sua arquitetura ao utiliz\u00e1-lo. Neste relat\u00f3rio, Alexey discutir\u00e1 exemplos t\u00edpicos de erros ao usar o ClickHouse, que podem levar a um desempenho ineficaz. Ser\u00e3o mostrados exemplos pr\u00e1ticos de como a escolha de um ou outro esquema de processamento de dados pode alterar a performance drasticamente.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Ol\u00e1 a todos! Meu nome \u00e9 Alexey, eu trabalho com ClickHouse.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/7f5fc01663be58d3d25e518a4169b8cf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Em primeiro lugar, vou logo alegr\u00e1-los, n\u00e3o vou falar hoje sobre o que \u00e9 ClickHouse. Para ser sincero, estou cansado disso. Eu explico isso toda vez. E, provavelmente, todos j\u00e1 sabem. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/fae6bd07d098200643d591b8e5bf51e8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Em vez disso, vou falar sobre os poss\u00edveis erros, ou seja, como usar o ClickHouse de forma errada. Na verdade, n\u00e3o \u00e9 para ter medo, porque desenvolvemos o ClickHouse como um sistema que \u00e9 simples, conveniente e funciona bem desde o in\u00edcio. Instalou e est\u00e1 tudo pronto, sem problemas. <\/p>\n<p><\/p>\n<p>Mas ainda \u00e9 preciso considerar que este sistema \u00e9 especializado e \u00e9 f\u00e1cil se deparar com um cen\u00e1rio de uso incomum que pode tirar o sistema de sua zona de conforto.<\/p>\n<p><\/p>\n<p>Ent\u00e3o, quais s\u00e3o esses erros? Principalmente, vou falar sobre coisas \u00f3bvias. Para todos \u00e9 \u00f3bvio, todos entendem e podem se alegrar por serem t\u00e3o inteligentes, e quem n\u00e3o entende, aprender\u00e1 algo novo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/bffacf353ff31b361460178e911f0e16.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O primeiro e mais simples exemplo, que, infelizmente, \u00e9 bastante comum, \u00e9 o grande n\u00famero de inserts com pequenos batches, ou seja, uma grande quantidade de pequenos inserts.<\/p>\n<p><\/p>\n<p>Se considerarmos como o ClickHouse executa um insert, voc\u00ea pode enviar em uma \u00fanica solicita\u00e7\u00e3o um fluxo de dados de at\u00e9 um terabyte. Isso n\u00e3o \u00e9 problema. <\/p>\n<p><\/p>\n<p>E vamos verificar qual seria a performance t\u00edpica. Por exemplo, temos uma tabela com dados do Yandex.Metrica. Hits. 105 colunas de algum tipo. 700 bytes em formato n\u00e3o comprimido. E vamos inserir corretamente em batches de um milh\u00e3o de linhas. <\/p>\n<p><\/p>\n<p>Inserindo na tabela MergeTree, obtemos meio milh\u00e3o de linhas por segundo. Excelente. Na tabela replicada, ser\u00e1 um pouco menos, cerca de 400.000 linhas por segundo. <\/p>\n<p><\/p>\n<p>E se ativarmos a inser\u00e7\u00e3o com qu\u00f3rum, obtemos um pouco menos, mas ainda uma performance razo\u00e1vel, 250.000 linhas por segundo. A inser\u00e7\u00e3o com qu\u00f3rum \u00e9 um recurso n\u00e3o documentado no ClickHouse*.<\/p>\n<p><\/p>\n<p>* at\u00e9 o ano de 2020, <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/operations\/settings\/settings\/#settings-insert_quorum\">j\u00e1 documentado<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/668498fc82a0f6e851d05e6e1ea67033.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O que acontece se fizer mal? Inserimos uma linha por vez na tabela MergeTree e obtemos 59 linhas por segundo. Isso \u00e9 10.000 vezes mais devagar. No ReplicatedMergeTree, s\u00e3o 6 linhas por segundo. E se o quorum entrar em a\u00e7\u00e3o, acabam sendo 2 linhas por segundo. Na minha opini\u00e3o, isso \u00e9 um verdadeiro desastre. Como pode haver tanta lentid\u00e3o? At\u00e9 mesmo na minha camiseta est\u00e1 escrito que ClickHouse n\u00e3o deve travar. Mas, no entanto, isso acontece \u00e0s vezes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/4c771eddc4e8453f60ef91123ae5d109.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na verdade, essa \u00e9 uma falha nossa. Poder\u00edamos facilmente fazer com que tudo funcionasse corretamente, mas n\u00e3o o fizemos. E n\u00e3o o fizemos porque, para o nosso cen\u00e1rio, isso n\u00e3o era necess\u00e1rio. J\u00e1 t\u00ednhamos lotes. Os dados chegavam em lotes, e n\u00e3o havia problemas. Inserimos e tudo funcionava normalmente. Mas, \u00e9 claro, v\u00e1rios cen\u00e1rios s\u00e3o poss\u00edveis. Por exemplo, quando voc\u00ea tem muitos servidores que geram dados. E eles inserem dados n\u00e3o com tanta frequ\u00eancia, mas ainda assim ocorrem inser\u00e7\u00f5es frequentes. E \u00e9 necess\u00e1rio evitar isso de alguma forma. <\/p>\n<p><\/p>\n<p>Do ponto de vista t\u00e9cnico, a quest\u00e3o \u00e9 que, quando voc\u00ea faz um insert no ClickHouse, os dados n\u00e3o v\u00e3o para nenhuma memtable. Na verdade, nem temos um log structure MergeTree, mas apenas um MergeTree, porque n\u00e3o h\u00e1 log nem memTable. N\u00f3s simplesmente escrevemos os dados diretamente no sistema de arquivos, j\u00e1 organizados em colunas. E se voc\u00ea tem 100 colunas, ser\u00e1 necess\u00e1rio gravar mais de 200 arquivos em um diret\u00f3rio separado. Tudo isso \u00e9 bastante volumoso. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/24688fe3d39d81b92f12ac1b8b21425b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E surge a pergunta: \u2018Como fazer corretamente?\u2019, se essa situa\u00e7\u00e3o implica que os dados precisam, de alguma forma, ser gravados no ClickHouse.<\/p>\n<p><\/p>\n<p>M\u00e9todo 1. Este \u00e9 o m\u00e9todo mais simples. Usar alguma fila distribu\u00edda. Por exemplo, Kafka. Basta extrair os dados do Kafka, processar em lotes uma vez por segundo. E tudo funcionar\u00e1 normalmente, voc\u00ea registra e tudo funciona bem. <\/p>\n<p><\/p>\n<p>As desvantagens s\u00e3o que Kafka \u00e9 mais um sistema distribu\u00eddo volumoso. Eu entendo melhor se voc\u00ea j\u00e1 tem o Kafka na sua empresa. Isso \u00e9 bom, \u00e9 conveniente. Mas se n\u00e3o tem, vale a pena pensar duas vezes antes de adicionar mais um sistema distribu\u00eddo ao seu projeto. Portanto, \u00e9 recomend\u00e1vel considerar alternativas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey 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. Aqui est\u00e1 uma alternativa old school que \u00e9 muito simples. Voc\u00ea tem algum servidor que gera seus logs. Ele simplesmente grava seus logs em um arquivo. E a cada segundo, por exemplo, renomeamos esse arquivo e abrimos um novo. E um script separado, seja por cron ou algum daemon, pega o arquivo mais antigo e grava no ClickHouse. Se voc\u00ea gravar os logs a cada segundo, tudo funcionar\u00e1 perfeitamente. <\/p>\n<p><\/p>\n<p>Mas a desvantagem desse m\u00e9todo \u00e9 que, se o seu servidor, onde os logs s\u00e3o gerados, desaparecer, os dados tamb\u00e9m desaparecer\u00e3o.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey 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. Existe outro m\u00e9todo interessante que n\u00e3o usa arquivos tempor\u00e1rios. Por exemplo, voc\u00ea tem um sistema de an\u00fancios ou outro daemon interessante que gera dados. E voc\u00ea pode acumular um lote de dados diretamente na mem\u00f3ria, no buffer. E quando passar um tempo suficiente, voc\u00ea guarda esse buffer de lado, cria um novo, e em uma thread separada, o que j\u00e1 foi acumulado, \u00e9 inserido no ClickHouse.<\/p>\n<p><\/p>\n<p>Por outro lado, os dados tamb\u00e9m desaparecem com um kill -9. Se o seu servidor cair, voc\u00ea perder\u00e1 esses dados. E outro problema \u00e9 que se voc\u00ea n\u00e3o conseguir gravar no banco, os dados come\u00e7ar\u00e3o a se acumular na mem\u00f3ria. E ou a mem\u00f3ria acabar\u00e1, ou voc\u00ea simplesmente perder\u00e1 os dados. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey 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. Outro m\u00e9todo interessante. Voc\u00ea tem algum processo no servidor. E ele pode enviar dados para o ClickHouse imediatamente, mas fazendo isso em uma \u00fanica conex\u00e3o. Por exemplo, enviando uma solicita\u00e7\u00e3o HTTP com transfer-encoding: chunked com um insert. E gera chunks n\u00e3o t\u00e3o raramente, pode enviar cada linha, embora haja um overhead na estrutura\u00e7\u00e3o desses dados. <\/p>\n<p><\/p>\n<p>Mas, no entanto, nesse caso, os dados ser\u00e3o enviados para o ClickHouse imediatamente. E o ClickHouse ir\u00e1 bufferiz\u00e1-los. <\/p>\n<p><\/p>\n<p>Mas tamb\u00e9m surgem problemas. Agora voc\u00ea perder\u00e1 dados, incluindo quando seu processo for encerrado e, se o processo ClickHouse for encerrado, porque ser\u00e1 um insert n\u00e3o conclu\u00eddo. Os inserts no ClickHouse s\u00e3o at\u00f4micos at\u00e9 um determinado limite de n\u00famero de linhas. Em princ\u00edpio, esse \u00e9 um m\u00e9todo interessante. Tamb\u00e9m pode ser utilizado.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey 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. Aqui est\u00e1 mais uma maneira interessante. \u00c9 um servidor desenvolvido pela comunidade para processamento em lote de dados. Eu mesmo n\u00e3o olhei para ele, portanto n\u00e3o posso garantir nada. No entanto, para o pr\u00f3prio ClickHouse tamb\u00e9m n\u00e3o s\u00e3o fornecidas garantias. Este tamb\u00e9m \u00e9 open source, mas por outro lado, voc\u00ea pode estar acostumado a um certo padr\u00e3o de qualidade, que nos esfor\u00e7amos para garantir. Mas para essa ferramenta \u2013 eu n\u00e3o sei, v\u00e1 ao GitHub, veja o c\u00f3digo. Pode ser que tenham escrito algo bom. <\/p>\n<p><\/p>\n<p>* em 2020, deve-se tamb\u00e9m considerar <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 eficaz do ClickHouse. Alexey 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. Outra forma \u00e9 usar tabelas Buffer. A vantagem desse m\u00e9todo \u00e9 que \u00e9 muito f\u00e1cil de come\u00e7ar a utilizar. Voc\u00ea cria uma tabela Buffer e insere nela. <\/p>\n<p><\/p>\n<p>Mas a desvantagem \u00e9 que o problema n\u00e3o \u00e9 completamente resolvido. Se ao inserir com tipo MergeTree voc\u00ea deve agrupar os dados em um lote por segundo, ao inserir na tabela buffer, voc\u00ea precisa agrupar pelo menos algumas milhares por segundo. Se houver mais de 10.000 por segundo, ainda ser\u00e1 problem\u00e1tico. E se voc\u00ea estiver inserindo em lotes, voc\u00ea viu que consegue centenas de milhares de linhas por segundo. E isso j\u00e1 com dados bastante pesados. <\/p>\n<p><\/p>\n<p>E tamb\u00e9m as tabelas buffer n\u00e3o t\u00eam log. E se algo estiver errado com seu servidor, os dados ser\u00e3o perdidos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/9bb16bf5e8145cc8368b11e54c86c837.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E como um b\u00f4nus, recentemente no ClickHouse surgiu a possibilidade de extrair dados do Kafka. Existe um mecanismo de tabelas \u2013 Kafka. Voc\u00ea simplesmente cria. E pode anexar visualiza\u00e7\u00f5es materializadas a ele. Nesse caso, ele extrair\u00e1 os dados do Kafka e os inserir\u00e1 nas tabelas que voc\u00ea precisa. <\/p>\n<p><\/p>\n<p>E o que \u00e9 especialmente gratificante nessa possibilidade \u00e9 que n\u00e3o fomos n\u00f3s que fizemos. \u00c9 um recurso da comunidade. E quando digo \"recurso da comunidade\", n\u00e3o o digo com desprezo. Lemos o c\u00f3digo, fizemos a revis\u00e3o, deve funcionar normalmente. <\/p>\n<p><\/p>\n<p>* em 2020, foi adicionada suporte 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 eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/15dc61dfd435f5f8640395b7de480fe2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O que mais pode ser inc\u00f4modo ou inesperado ao inserir dados? Se voc\u00ea faz uma consulta insert values e em values escreve algumas express\u00f5es calculadas. Por exemplo, now() \u2013 isso tamb\u00e9m \u00e9 uma express\u00e3o calculada. E nesse caso, o ClickHouse \u00e9 for\u00e7ado a executar o interpretador dessas express\u00f5es para cada linha, e o desempenho cair\u00e1 drasticamente. \u00c9 melhor evitar isso.<\/p>\n<p><\/p>\n<p>* No momento, o problema est\u00e1 completamente resolvido, n\u00e3o h\u00e1 mais degrada\u00e7\u00e3o de desempenho ao usar express\u00f5es em VALUES.<\/p>\n<p><\/p>\n<p>Outro exemplo de quando podem ocorrer alguns problemas \u00e9 quando, em um \u00fanico lote, os dados pertencem a v\u00e1rias parti\u00e7\u00f5es. Por padr\u00e3o, o ClickHouse organiza as parti\u00e7\u00f5es por meses. Se voc\u00ea insere um lote de um milh\u00e3o de linhas e os dados abrangem v\u00e1rios anos, ter\u00e1 v\u00e1rias dezenas de parti\u00e7\u00f5es. Isso equivale a ter lotes com tamanhos v\u00e1rias dezenas de vezes menores, porque internamente eles s\u00e3o divididos primeiro por parti\u00e7\u00f5es.<\/p>\n<p><\/p>\n<p>* Recentemente, o ClickHouse adicionou suporte experimental para o formato compacto de peda\u00e7os e peda\u00e7os na mem\u00f3ria com log grav\u00e1vel, o que resolve quase completamente o problema.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/b8c6cecdba53559dad31ed11713a980d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Agora vamos considerar o segundo tipo de problema \u2013 a tipifica\u00e7\u00e3o de dados. <\/p>\n<p><\/p>\n<p>A tipifica\u00e7\u00e3o de dados pode ser estrita ou ser uma string. String \u00e9 quando voc\u00ea simplesmente declara que todos os seus campos s\u00e3o do tipo string. Isso \u00e9 p\u00e9ssimo. N\u00e3o devemos fazer assim. <\/p>\n<p><\/p>\n<p>Vamos entender como fazer corretamente nos casos em que queremos dizer que um campo \u00e9 uma string e que o ClickHouse pode resolver isso sozinho, sem eu me preocupar. Mas ainda assim vale a pena fazer alguns esfor\u00e7os. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/a0fdcf6423933293318411242fe2ede7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por exemplo, temos um endere\u00e7o IP. Em um caso, n\u00f3s o salvamos como uma string. Por exemplo, 192.168.1.1. E em outro caso \u2013 ser\u00e1 um n\u00famero do tipo UInt32*. 32 bits s\u00e3o suficientes para um endere\u00e7o IPv4.<\/p>\n<p><\/p>\n<p>Primeiro, n\u00e3o estranhe, os dados ser\u00e3o compactados de maneira aproximadamente igual. Havendo diferen\u00e7as, claro, mas n\u00e3o t\u00e3o grandes. Portanto, n\u00e3o h\u00e1 problemas significativos com entrada e sa\u00edda de disco. <\/p>\n<p><\/p>\n<p>Mas h\u00e1 uma diferen\u00e7a s\u00e9ria em termos de tempo de CPU e no tempo de execu\u00e7\u00e3o da consulta. <\/p>\n<p><\/p>\n<p>Vamos contar o n\u00famero de endere\u00e7os IP \u00fanicos, se eles forem armazenados como n\u00fameros. Obtemos 137 milh\u00f5es de linhas por segundo. Se for o mesmo como strings, d\u00e1 37 milh\u00f5es de linhas por segundo. N\u00e3o sei por que essa coincid\u00eancia aconteceu. Eu mesmo executei essas consultas. Mas, ainda assim, \u00e9 cerca de 4 vezes mais lento. <\/p>\n<p><\/p>\n<p>E se contarmos a diferen\u00e7a no espa\u00e7o em disco, tamb\u00e9m h\u00e1 uma diferen\u00e7a. E a diferen\u00e7a \u00e9 de cerca de um quarto, porque h\u00e1 muitos endere\u00e7os IP \u00fanicos. Se houvesse linhas com poucos valores diferentes, elas se comprimiriam de maneira semelhante a um dicion\u00e1rio, ocupando aproximadamente o mesmo espa\u00e7o. <\/p>\n<p><\/p>\n<p>E a diferen\u00e7a de quatro vezes no tempo de estrada n\u00e3o \u00e9 desprez\u00edvel. Pode ser que voc\u00ea n\u00e3o se importe, mas quando vejo uma diferen\u00e7a assim, fico triste.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/f74dbfdab5a9e26fa044a5870a8cc00d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vamos considerar diferentes casos. <\/p>\n<p><\/p>\n<p>1. Um caso onde voc\u00ea tem poucos valores \u00fanicos. Nesse caso, usamos uma pr\u00e1tica simples que voc\u00ea provavelmente conhece e pode aplicar a qualquer SGBD. Isso faz sentido n\u00e3o apenas para o ClickHouse. Voc\u00ea simplesmente grava identificadores num\u00e9ricos no banco. E a convers\u00e3o para strings e vice-versa pode ser feita j\u00e1 no lado da sua aplica\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p>Por exemplo, voc\u00ea tem uma regi\u00e3o. E est\u00e1 tentando salv\u00e1-la como string. E l\u00e1 estar\u00e1 escrito: Moscovo e MO. E quando vejo que est\u00e1 escrito \"Moscovo\", tudo bem, mas quando tamb\u00e9m aparece MO, fico ainda mais triste. Isso \u00e9 uma quantidade enorme de bytes. <\/p>\n<p><\/p>\n<p>Em vez disso, gravamos simplesmente o n\u00famero Ulnt32 e 250. Temos 250 no Yandex, e voc\u00ea pode ter um n\u00famero diferente. Para constar, no ClickHouse existe a capacidade incorporada de trabalhar com geobases. Voc\u00ea simplesmente grava um dicion\u00e1rio com as regi\u00f5es, incluindo hier\u00e1rquico, ou seja, haver\u00e1 Moscovo, MO e tudo o que precisar. E voc\u00ea pode converter isso no n\u00edvel da consulta. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/cc6e871136dab8f8a35246a5af512cda.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A segunda op\u00e7\u00e3o \u00e9 semelhante, mas j\u00e1 com suporte dentro do ClickHouse. Este \u00e9 o tipo de dados Enum. Voc\u00ea simplesmente define dentro do Enum todos os valores necess\u00e1rios. Por exemplo, o tipo de dispositivo e escreve: desktop, m\u00f3vel, tablet, televis\u00e3o. No total, 4 op\u00e7\u00f5es. <\/p>\n<p><\/p>\n<p>A desvantagem \u00e9 que \u00e9 necess\u00e1rio alterar periodicamente. Adicionou apenas uma op\u00e7\u00e3o. Fazemos alter table. Na verdade, alterar uma tabela no ClickHouse \u00e9 gratuito. Especialmente gratuito para Enum, porque os dados no disco n\u00e3o mudam. Mas, mesmo assim, o alter bloqueia a tabela e precisa esperar que todas as sele\u00e7\u00f5es sejam conclu\u00eddas. E s\u00f3 depois disso o alter ser\u00e1 realizado, ou seja, algumas inconveni\u00eancias ainda existem.<\/p>\n<p><\/p>\n<p>* nas vers\u00f5es mais recentes do ClickHouse, o ALTER \u00e9 totalmente n\u00e3o bloqueante.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/d7284fa5be583ab063bb6de0b60f54d4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outra op\u00e7\u00e3o bastante \u00fanica para o ClickHouse \u00e9 a conex\u00e3o de dicion\u00e1rios externos. Voc\u00ea pode escrever n\u00fameros no ClickHouse e manter seus dicion\u00e1rios em qualquer sistema que lhe convier. Por exemplo, voc\u00ea pode usar: MySQL, Mongo, Postgres. Voc\u00ea pode at\u00e9 criar seu pr\u00f3prio microservi\u00e7o que entregar\u00e1 esses dados via http. E no n\u00edvel do ClickHouse, voc\u00ea escreve uma fun\u00e7\u00e3o que transformar\u00e1 esses dados de n\u00fameros em strings. <\/p>\n<p><\/p>\n<p>Este \u00e9 um m\u00e9todo especializado, mas muito eficaz para realizar um join com uma tabela externa. Existem duas op\u00e7\u00f5es. Em uma op\u00e7\u00e3o, esses dados ser\u00e3o totalmente armazenados em cache, completamente na mem\u00f3ria e atualizados com certa periodicidade. Na outra op\u00e7\u00e3o, se esses dados n\u00e3o cabem na mem\u00f3ria, \u00e9 poss\u00edvel armazen\u00e1-los em cache parcialmente. <\/p>\n<p><\/p>\n<p>Aqui est\u00e1 um exemplo. Existe o Yandex.Direct. E l\u00e1 h\u00e1 campanhas publicit\u00e1rias e banners. Existem cerca de dez milh\u00f5es de campanhas publicit\u00e1rias. E elas cabem na mem\u00f3ria. J\u00e1 os banners \u2013 s\u00e3o bilh\u00f5es, eles n\u00e3o cabem. E usamos um dicion\u00e1rio em cache do MySQL.<\/p>\n<p><\/p>\n<p>O \u00fanico problema \u00e9 que o dicion\u00e1rio em cache funcionar\u00e1 corretamente se a taxa de acerto estiver pr\u00f3xima de 100%. Se for menor, ao processar solicita\u00e7\u00f5es para cada lote de dados, ser\u00e1 necess\u00e1rio realmente buscar as chaves faltantes e obter os dados do MySQL. Posso garantir que o ClickHouse \u2013 sim, n\u00e3o apresenta lentid\u00e3o, mas n\u00e3o comentarei sobre outros sistemas.<\/p>\n<p><\/p>\n<p>Como um b\u00f4nus, o que os dicion\u00e1rios oferecem \u00e9 uma maneira muito simples de atualizar dados no ClickHouse retroativamente. Ou seja, voc\u00ea tinha um relat\u00f3rio sobre campanhas publicit\u00e1rias, o usu\u00e1rio simplesmente mudou a campanha publicit\u00e1ria e em todos os dados antigos, em todos os relat\u00f3rios, esses dados tamb\u00e9m mudaram. Se voc\u00ea escrever linhas diretamente na tabela, ser\u00e1 imposs\u00edvel atualiz\u00e1-las. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/a5a2919d6be7d00c0ad5875b9a8f0f31.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outra maneira \u00e9 quando voc\u00ea n\u00e3o sabe de onde obter os identificadores para suas linhas. Voc\u00ea pode simplesmente fazer um hash. E a op\u00e7\u00e3o mais simples \u00e9 usar um hash de 64 bits. <\/p>\n<p><\/p>\n<p>O \u00fanico problema \u00e9 que se o hash tiver 64 bits, as colis\u00f5es ocorrer\u00e3o quase certamente. Porque se houver um bilh\u00e3o de linhas, a probabilidade j\u00e1 se torna significativa. <\/p>\n<p><\/p>\n<p>E n\u00e3o seria muito bom fazer o hash dos nomes das campanhas publicit\u00e1rias dessa forma. Se as campanhas publicit\u00e1rias de diferentes empresas se confundirem, n\u00e3o ficar\u00e1 claro. <\/p>\n<p><\/p>\n<p>E h\u00e1 um truque simples. Embora n\u00e3o seja muito adequado para dados s\u00e9rios, se voc\u00ea tiver algo menos cr\u00edtico, basta adicionar o identificador do cliente \u00e0 chave do dicion\u00e1rio. Assim, voc\u00ea ter\u00e1 colis\u00f5es, mas apenas dentro dos limites de um \u00fanico cliente. Este m\u00e9todo \u00e9 usado por n\u00f3s para o mapa de links no Yandex.Metrica. Temos URLs l\u00e1, armazenamos hashes. E sabemos que, claro, h\u00e1 colis\u00f5es. Mas quando a p\u00e1gina \u00e9 exibida, a probabilidade de que, em uma \u00fanica p\u00e1gina, um usu\u00e1rio tenha algumas URLs combinadas e que isso seja notado \u00e9 desprez\u00edvel. <\/p>\n<p><\/p>\n<p>Como b\u00f4nus, para muitas opera\u00e7\u00f5es, apenas os hashes s\u00e3o suficientes e voc\u00ea n\u00e3o precisa armazenar as strings em lugar algum. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/abbb73aaba29d10e3b7e7650bf68e6a6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outro exemplo, se as strings forem curtas, como dom\u00ednios de sites. Voc\u00ea pode armazen\u00e1-las como est\u00e3o. Ou, por exemplo, o idioma do navegador ru \u2013 2 bytes. Claro, eu lamento pelos bytes, mas n\u00e3o se preocupe, 2 bytes n\u00e3o s\u00e3o um problema. Por favor, armazene como est\u00e1, n\u00e3o se preocupe. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/901eaed0029da6ea59630b57ccf80c25.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outro caso, quando, ao contr\u00e1rio, h\u00e1 muitas strings e muitas delas s\u00e3o \u00fanicas, com um potencial ilimitado. Um exemplo t\u00edpico s\u00e3o as frases de busca ou URLs. Frases de busca, inclusive por causa de erros de digita\u00e7\u00e3o. Vamos ver quantas frases de busca \u00fanicas existem em um dia. Acontece que quase metade de todos os eventos \u00e9 composta por elas. E nesse caso, voc\u00ea poderia pensar que \u00e9 necess\u00e1rio normalizar os dados, calcular identificadores e armazen\u00e1-los em uma tabela separada. Mas n\u00e3o \u00e9 necess\u00e1rio fazer isso. Basta armazenar essas strings como est\u00e3o. <\/p>\n<p><\/p>\n<p>Melhor n\u00e3o inventar nada, porque se armazenar separadamente, ser\u00e1 necess\u00e1rio fazer um join. E esse join, na melhor das hip\u00f3teses, \u00e9 um acesso aleat\u00f3rio \u00e0 mem\u00f3ria, se ainda couber na mem\u00f3ria. Se n\u00e3o couber, haver\u00e1 problemas. <\/p>\n<p><\/p>\n<p>E se os dados s\u00e3o armazenados in place, eles simplesmente s\u00e3o lidos na ordem necess\u00e1ria do sistema de arquivos e tudo funciona normalmente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/15f1d632083def16ccbc939579c1cf6b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se voc\u00ea tem URLs ou algum outro tipo de string longa e complexa, vale a pena considerar que voc\u00ea pode calcular um resumo antecipadamente e grav\u00e1-lo em uma coluna separada. <\/p>\n<p><\/p>\n<p>Para URLs, por exemplo, voc\u00ea pode armazenar o dom\u00ednio separadamente. E se realmente precisar do dom\u00ednio, basta usar essa coluna, enquanto as URLs estar\u00e3o armazenadas e voc\u00ea n\u00e3o precisar\u00e1 sequer toc\u00e1-las. <\/p>\n<p><\/p>\n<p>Vamos ver qual \u00e9 a diferen\u00e7a. No ClickHouse existe uma fun\u00e7\u00e3o especializada que calcula o dom\u00ednio. Ela \u00e9 muito r\u00e1pida, n\u00f3s a otimizamos. E, sinceramente, ela nem atende ao RFC, mas, mesmo assim, calcula tudo o que precisamos. <\/p>\n<p><\/p>\n<p>Em um caso, estaremos apenas extraindo URLs e computando o dom\u00ednio. O resultado \u00e9 de 166 milissegundos. Mas se pegarmos um dom\u00ednio j\u00e1 preparado, o tempo cai para apenas 67 milissegundos, ou seja, quase tr\u00eas vezes mais r\u00e1pido. Isso n\u00e3o \u00e9 porque precisamos fazer c\u00e1lculos, mas porque lemos menos dados. <\/p>\n<p><\/p>\n<p>Por que, ent\u00e3o, uma consulta mais lenta gera uma maior velocidade em gigabytes por segundo? Porque ela l\u00ea mais gigabytes. Esses dados s\u00e3o completamente desnecess\u00e1rios. A consulta parece funcionar mais r\u00e1pido, mas leva mais tempo para ser executada.<\/p>\n<p><\/p>\n<p>Se olharmos o volume de dados no disco, veremos que a URL ocupa 126 megabytes, enquanto o dom\u00ednio ocupa apenas 5 megabytes. Isso \u00e9 25 vezes menos. No entanto, a consulta \u00e9 realizada apenas 4 vezes mais r\u00e1pido. Isso acontece porque os dados s\u00e3o quentes. Se fossem frios, provavelmente seria 25 vezes mais r\u00e1pido devido \u00e0 entrada e sa\u00edda de disco. <\/p>\n<p><\/p>\n<p>A prop\u00f3sito, se avaliarmos o quanto o dom\u00ednio \u00e9 menor que a URL, vemos que \u00e9 cerca de 4 vezes. Mas, por algum motivo, os dados no disco ocupam 25 vezes menos. Por que isso? Devido \u00e0 compress\u00e3o. Tanto a URL quanto o dom\u00ednio s\u00e3o comprimidos. Mas frequentemente, a URL cont\u00e9m muita informa\u00e7\u00e3o desnecess\u00e1ria. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/c93d2128a41561ed7abb25d77414bc2d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E, claro, \u00e9 importante usar os tipos de dados corretos, que s\u00e3o especialmente projetados para os valores necess\u00e1rios ou que se adequam. Se voc\u00ea estiver usando IPv4, guarde como UInt32*. Se for IPv6, use FixedString(16), pois o endere\u00e7o IPv6 tem 128 bits, ou seja, armazene no formato bin\u00e1rio. <\/p>\n<p><\/p>\n<p>E o que fazer se voc\u00ea \u00e0s vezes tem endere\u00e7os IPv4 e outras vezes IPv6? Sim, \u00e9 poss\u00edvel armazenar ambos. Uma coluna para IPv4 e outra para IPv6. Claro, existe a op\u00e7\u00e3o de representar IPv4 em IPv6. Isso tamb\u00e9m funcionar\u00e1, mas se voc\u00ea frequentemente precisar de um endere\u00e7o IPv4 nas suas consultas, \u00e9 uma boa ideia armazen\u00e1-lo em uma coluna separada. <\/p>\n<p><\/p>\n<p>* Agora no ClickHouse existem tipos de dados separados para IPv4 e IPv6 que armazenam os dados de forma t\u00e3o eficiente quanto n\u00fameros, mas os apresentam de maneira t\u00e3o conveniente quanto strings.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/d7d6342ebd6b8b4f3526b3cd8a06cf26.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00c9 importante observar que os dados devem ser pr\u00e9-processados com anteced\u00eancia. Por exemplo, voc\u00ea recebe alguns logs brutos. E talvez n\u00e3o seja uma boa ideia envi\u00e1-los imediatamente para o ClickHouse, embora seja tentador n\u00e3o fazer nada e tudo funcione. Mas \u00e9 melhor realizar os c\u00e1lculos que puder.<\/p>\n<p><\/p>\n<p>Por exemplo, a vers\u00e3o do navegador. Em um departamento vizinho, que n\u00e3o quero mencionar, a vers\u00e3o do navegador \u00e9 armazenada assim, ou seja, como uma string: 12.3. E depois, para gerar um relat\u00f3rio, eles pegam essa string, dividem em um array e depois pegam o primeiro elemento do array. Naturalmente, tudo fica lento. Perguntei por que eles fazem isso. Eles me responderam que n\u00e3o gostam de otimiza\u00e7\u00e3o prematura. E eu n\u00e3o gosto de pessimismo prematuro.<\/p>\n<p><\/p>\n<p>Ent\u00e3o, neste caso, \u00e9 mais adequado dividir em 4 colunas. N\u00e3o tenha medo, porque isso \u00e9 ClickHouse. ClickHouse \u00e9 um banco de dados por coluna. E quanto mais pequenas colunas organizadas, melhor. Se tiver 5 BrowserVersion, fa\u00e7a 5 colunas. Isso \u00e9 normal. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/f9a67221bf8508933d7bd336b16f9e04.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Agora, vamos considerar o que fazer se voc\u00ea tiver muitas strings muito longas, muitos arrays muito longos. Eles n\u00e3o precisam ser armazenados no ClickHouse de maneira alguma. Em vez disso, voc\u00ea pode salvar no ClickHouse apenas um identificador. E coloque essas strings longas em algum outro sistema. <\/p>\n<p><\/p>\n<p>Por exemplo, em um dos nossos servi\u00e7os anal\u00edticos, existem certos par\u00e2metros de eventos. E se muitos par\u00e2metros chegarem para os eventos, n\u00f3s simplesmente armazenamos os primeiros 512 que encontramos. Porque 512 n\u00e3o \u00e9 um desperd\u00edcio. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/755271e8788ba4bd638f493bf320c820.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E se voc\u00ea n\u00e3o conseguir decidir sobre os seus tipos de dados, voc\u00ea tamb\u00e9m pode gravar os dados no ClickHouse, mas em uma tabela tempor\u00e1ria do tipo Log, especialmente para dados tempor\u00e1rios. Depois disso, voc\u00ea pode analisar qual \u00e9 a distribui\u00e7\u00e3o de valores l\u00e1, o que realmente existe e criar os tipos corretos.<\/p>\n<p><\/p>\n<p>* atualmente, o ClickHouse tem um tipo de dado <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/sql-reference\/data-types\/lowcardinality\/\">LowCardinality<\/a><\/noindex> que permite armazenar strings de forma eficiente com menor custo de processamento.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/7e9e53d86a4189783c28ce56a669198c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Agora, vamos considerar outro caso interessante. \u00c0s vezes, as coisas funcionam de um jeito estranho para as pessoas. Eu entro e vejo isso. E logo imagino que foi feito por um administrador muito experiente e inteligente, que tem grande experi\u00eancia em configurar o MySQL vers\u00e3o 3.23. <\/p>\n<p><\/p>\n<p>Aqui vemos mil tabelas, cada uma com o resto da divis\u00e3o de algo incompreens\u00edvel por mil. <\/p>\n<p><\/p>\n<p>Eu respeito a experi\u00eancia alheia e entendo as dificuldades que podem ter sido enfrentadas para adquiri-la. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/3a5e21ef2076966fcc627670485c5b3a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E as raz\u00f5es s\u00e3o mais ou menos compreens\u00edveis. Esses s\u00e3o estere\u00f3tipos antigos que podem ter se acumulado ao trabalhar com outros sistemas. Por exemplo, em tabelas MyISAM, n\u00e3o h\u00e1 uma chave prim\u00e1ria clusterizada. E esse tipo de divis\u00e3o de dados pode ser uma tentativa desesperada de obter a mesma funcionalidade. <\/p>\n<p><\/p>\n<p>Outra raz\u00e3o \u00e9 que realizar opera\u00e7\u00f5es como alter em tabelas grandes \u00e9 dif\u00edcil. Tudo fica bloqueado. Embora em vers\u00f5es modernas do MySQL esse problema n\u00e3o seja t\u00e3o s\u00e9rio. <\/p>\n<p><\/p>\n<p>Ou, por exemplo, micro-sharding, mas falaremos disso mais adiante.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/321b1d9caa8db7aca5b96e08c61d05b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No ClickHouse n\u00e3o \u00e9 necess\u00e1rio fazer isso, porque, primeiro, a chave prim\u00e1ria \u00e9 clusterizada e os dados s\u00e3o organizados de acordo com a chave prim\u00e1ria. <\/p>\n<p><\/p>\n<p>\u00c0s vezes me perguntam: \"Como o desempenho de consultas em intervalo no ClickHouse muda com o tamanho da tabela?\" Eu digo que n\u00e3o muda. Por exemplo, se voc\u00ea tem uma tabela com um bilh\u00e3o de linhas e l\u00ea um intervalo de um milh\u00e3o de linhas, tudo funciona normalmente. Se a tabela tem um trilh\u00e3o de linhas e voc\u00ea l\u00ea um milh\u00e3o de linhas, o desempenho ser\u00e1 quase o mesmo. <\/p>\n<p><\/p>\n<p>E, em segundo lugar, n\u00e3o h\u00e1 necessidade de coisas como parti\u00e7\u00f5es manuais. Se voc\u00ea entrar e olhar o que est\u00e1 no sistema de arquivos, ver\u00e1 que a tabela \u00e9 um objeto bastante robusto. Dentro dela, existe algo como parti\u00e7\u00f5es. Ou seja, o ClickHouse faz tudo por voc\u00ea e voc\u00ea n\u00e3o precisa se preocupar.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/652f3742ad3a44f172d0d7302abd09f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Alterar no ClickHouse \u00e9 gratuito, se for apenas para adicionar\/remover colunas. <\/p>\n<p><\/p>\n<p>E n\u00e3o vale a pena criar tabelas pequenas, porque se voc\u00ea tem 10 linhas ou 10.000 linhas na tabela, isso \u00e9 irrelevante. O ClickHouse \u00e9 um sistema que otimiza o throughput, n\u00e3o a lat\u00eancia, ent\u00e3o processar 10 linhas n\u00e3o faz sentido. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/144144b4740e9c5daec80c8dadc445f9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00c9 correto utilizar uma tabela grande. Livre-se dos estere\u00f3tipos antigos; tudo ficar\u00e1 bem. <\/p>\n<p><\/p>\n<p>Como b\u00f4nus, na \u00faltima vers\u00e3o, temos a capacidade de criar uma chave de parti\u00e7\u00e3o arbitr\u00e1ria para realizar v\u00e1rias opera\u00e7\u00f5es de manuten\u00e7\u00e3o em parti\u00e7\u00f5es espec\u00edficas. <\/p>\n<p><\/p>\n<p>Por exemplo, voc\u00ea precisa de muitas tabelas pequenas, como quando h\u00e1 uma necessidade de processar alguns dados intermedi\u00e1rios, voc\u00ea recebe chunks e precisa realizar transforma\u00e7\u00f5es sobre eles antes de grav\u00e1-los na tabela final. Para esse caso, existe um motor de tabela excelente \u2013 o StripeLog. \u00c9 como o TinyLog, mas melhor. <\/p>\n<p><\/p>\n<p>* agora no ClickHouse h\u00e1 tamb\u00e9m <noindex><a rel=\"nofollow\" href=\"https:\/\/clickhouse.tech\/docs\/en\/sql-reference\/table-functions\/input\/\">a fun\u00e7\u00e3o da tabela input<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/d62f0b3d29876c29c6c0ba236b200186.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outro antipadr\u00e3o \u00e9 o microsharding. Por exemplo, voc\u00ea precisa shardizar seus dados e tem 5 servidores, mas amanh\u00e3 haver\u00e1 6 servidores. E voc\u00ea est\u00e1 pensando em como reequilibrar esses dados. Em vez disso, voc\u00ea divide n\u00e3o em 5 shards, mas em 1.000 shards. E depois mapeia cada um desses microshards para um servidor separado. Assim, em um servidor, voc\u00ea pode ter, por exemplo, 200 ClickHouse. Inst\u00e2ncias separadas em portas diferentes ou bancos de dados distintos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/3e550ef7e338b84e4394eb9fa4538769.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mas no ClickHouse isso n\u00e3o \u00e9 muito bom. Porque at\u00e9 mesmo uma inst\u00e2ncia do ClickHouse tenta usar todos os recursos dispon\u00edveis do servidor para processar uma \u00fanica consulta. Ou seja, voc\u00ea tem um servidor e, por exemplo, 56 n\u00facleos de processador. Voc\u00ea executa uma consulta que leva um segundo e ela usar\u00e1 56 n\u00facleos. E se voc\u00ea tem 200 ClickHouse no mesmo servidor, surgir\u00e3o 10.000 threads. No geral, ser\u00e1 muito ruim.<\/p>\n<p><\/p>\n<p>Outra raz\u00e3o \u00e9 que a distribui\u00e7\u00e3o do trabalho entre essas inst\u00e2ncias ser\u00e1 desigual. Alguma terminar\u00e1 antes, alguma terminar\u00e1 depois. Se tudo isso ocorresse em uma \u00fanica inst\u00e2ncia, o ClickHouse resolveria automaticamente como distribuir corretamente os dados entre os threads. <\/p>\n<p><\/p>\n<p>E mais uma raz\u00e3o \u00e9 que voc\u00ea ter\u00e1 comunica\u00e7\u00e3o interprocessos via TCP. Os dados precisar\u00e3o ser serializados, desserializados e isso cria uma quantidade enorme de microshards. Ser\u00e1 simplesmente ineficiente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/18cacc17d22ae1cb2977c6be74769896.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outro antipadr\u00e3o, embora seja dif\u00edcil cham\u00e1-lo assim. \u00c9 a grande quantidade de pr\u00e9-agrega\u00e7\u00e3o.<\/p>\n<p><\/p>\n<p>Na verdade, a pr\u00e9-agrega\u00e7\u00e3o \u00e9 boa. Tinha um bilh\u00e3o de linhas, voc\u00ea agregou e ficou com 1.000 linhas, e agora a consulta \u00e9 executada instantaneamente. Tudo \u00f3timo. Isso \u00e9 poss\u00edvel. E para isso, at\u00e9 mesmo no ClickHouse h\u00e1 um tipo especial de tabela, o AggregatingMergeTree, que faz a agrega\u00e7\u00e3o incremental \u00e0 medida que os dados s\u00e3o inseridos. <\/p>\n<p><\/p>\n<p>Mas h\u00e1 casos em que voc\u00ea pensa que vamos agregar os dados dessa forma e ainda agregar os dados assim. E em algum departamento vizinho, que n\u00e3o quero mencionar, eles usam tabelas SummingMergeTree para somar por chave prim\u00e1ria, usando cerca de 20 colunas como chave prim\u00e1ria. Eu mudei os nomes de algumas colunas por precau\u00e7\u00e3o, mas \u00e9 mais ou menos assim que funciona.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/54e3a02ab4bbce7c63ded595780ae1f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E surgem esses problemas. Primeiro, o volume de dados n\u00e3o diminui muito. Por exemplo, diminui em tr\u00eas vezes. Tr\u00eas vezes seria um bom pre\u00e7o para permitir-se oportunidades ilimitadas de an\u00e1lise, que surgem quando os dados n\u00e3o est\u00e3o agregados. Se os dados est\u00e3o agregados, voc\u00ea acaba recebendo apenas estat\u00edsticas med\u00edocres em vez de an\u00e1lises. <\/p>\n<p><\/p>\n<p>E o que \u00e9 especialmente irritante? \u00c9 que essas pessoas do departamento vizinho v\u00eam e pedem para adicionar mais uma coluna \u00e0 chave prim\u00e1ria. Ou seja, agregamos os dados assim, mas agora queremos um pouco mais. Mas no ClickHouse n\u00e3o h\u00e1 como alterar a chave prim\u00e1ria. Portanto, \u00e9 preciso escrever alguns scripts em C++. E eu n\u00e3o gosto de scripts, mesmo que sejam em C++.<\/p>\n<p><\/p>\n<p>E se voc\u00ea olhar para o motivo pelo qual o ClickHouse foi criado, dados n\u00e3o agregados s\u00e3o exatamente o cen\u00e1rio para o qual ele foi concebido. Se voc\u00ea est\u00e1 usando o ClickHouse para dados n\u00e3o agregados, voc\u00ea est\u00e1 fazendo tudo certo. Se voc\u00ea est\u00e1 agregando, isso \u00e0s vezes pode ser perdo\u00e1vel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/09fafd4c8a3ea8c22e586cb7a5cf6564.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Outro caso interessante s\u00e3o as consultas em um loop infinito. \u00c0s vezes, eu vou a algum servidor de produ\u00e7\u00e3o e olho l\u00e1 o show processlist. E a cada vez descubro que algo terr\u00edvel est\u00e1 acontecendo. <\/p>\n<p><\/p>\n<p>Por exemplo, isso. Aqui j\u00e1 fica claro que poderia ser tudo executado em uma \u00fanica consulta. Basta escrever url in e a lista.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/ae03b659f178962f50e0640614517296.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por que muitas dessas consultas em um loop infinito s\u00e3o ruins? Se o \u00edndice n\u00e3o for utilizado, voc\u00ea ter\u00e1 muitas passagens pelos mesmos dados. Mas se o \u00edndice for utilizado, por exemplo, se voc\u00ea tem uma chave prim\u00e1ria em ru e escreve url = algo assim. E voc\u00ea pensa que vai ler um \u00fanico url da tabela, tudo ficar\u00e1 normal. Mas, na verdade, n\u00e3o. Porque o ClickHouse faz tudo em pacotes. <\/p>\n<p><\/p>\n<p>Quando \u00e9 necess\u00e1rio ler um intervalo de dados, l\u00ea-se um pouco mais, porque o \u00edndice no ClickHouse \u00e9 esparso. Esse \u00edndice n\u00e3o permite encontrar uma \u00fanica linha na tabela, apenas um intervalo. E os dados s\u00e3o comprimidos em blocos. Para ler uma linha, \u00e9 necess\u00e1rio pegar um bloco inteiro e descompact\u00e1-lo. E se voc\u00ea executar um monte de consultas, ter\u00e1 muitas interse\u00e7\u00f5es, e muitos trabalhos ser\u00e3o executados repetidamente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/95eef43c5b869f8b145c61ce3c616cfd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Como um b\u00f4nus, vale destacar que no ClickHouse n\u00e3o se deve ter medo de passar at\u00e9 megabytes e at\u00e9 centenas de megabytes na se\u00e7\u00e3o IN. Lembro da nossa pr\u00e1tica, que se no MySQL passarmos um monte de valores na se\u00e7\u00e3o IN, por exemplo, 100 megabytes de alguns n\u00fameros, o MySQL consome 10 gigabytes de mem\u00f3ria e mais nada acontece, tudo funciona mal. <\/p>\n<p><\/p>\n<p>E a segunda coisa \u00e9 que no ClickHouse, se suas consultas usam \u00edndices, isso nunca \u00e9 mais lento do que um full scan, ou seja, se quase toda a tabela precisa ser lida, ele ir\u00e1 percorrer sequencialmente e ler toda a tabela. Em geral, ele mesmo se encarrega disso.<\/p>\n<p><\/p>\n<p>No entanto, existem algumas dificuldades. Por exemplo, o IN com subconsulta n\u00e3o utiliza o \u00edndice. Mas esse \u00e9 o nosso problema e precisamos corrigi-lo. N\u00e3o h\u00e1 nada fundamental aqui. Vamos consertar isso. <\/p>\n<p><\/p>\n<p>E mais uma coisa interessante \u00e9 que se voc\u00ea tiver uma consulta muito longa e a execu\u00e7\u00e3o distribu\u00edda de consultas, essa consulta muito longa ser\u00e1 enviada para cada servidor sem compress\u00e3o. Por exemplo, 100 megabytes e 500 servidores. E, assim, voc\u00ea transmitir\u00e1 50 gigabytes pela rede. Ser\u00e1 transmitido e depois tudo ser\u00e1 executado com sucesso.<\/p>\n<p><\/p>\n<p>* j\u00e1 \u00e9 utilizado; tudo consertado, como prometido.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/5fcde9bf04fff0645be2530daa12743f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>E \u00e9 bastante comum que as consultas venham de uma API. Por exemplo, voc\u00ea criou um servi\u00e7o. E se seu servi\u00e7o for necess\u00e1rio para algu\u00e9m, voc\u00ea abriu uma API e, literalmente dois dias depois, v\u00ea que algo estranho est\u00e1 acontecendo. Tudo est\u00e1 sobrecarregado e algumas consultas horr\u00edveis est\u00e3o chegando, que nunca deveriam ter ocorrido. <\/p>\n<p><\/p>\n<p>E a solu\u00e7\u00e3o \u00e9 uma s\u00f3. Se voc\u00ea abriu uma API, ter\u00e1 que limit\u00e1-la. Por exemplo, introduzir algumas quotas. N\u00e3o h\u00e1 op\u00e7\u00f5es normais. Caso contr\u00e1rio, logo escrever\u00e3o um script e voc\u00ea ter\u00e1 problemas. <\/p>\n<p><\/p>\n<p>E no ClickHouse existe uma funcionalidade especial \u2013 o monitoramento de cotas. Voc\u00ea pode, por exemplo, passar sua chave de cota. Isso pode ser, por exemplo, um identificador interno do usu\u00e1rio. E as cotas ser\u00e3o contabilizadas independentemente para cada um deles. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/532438d0f116919e62f04e32ebbd3c45.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Agora, outra coisa interessante. \u00c9 a replica\u00e7\u00e3o manual. <\/p>\n<p><\/p>\n<p>Eu conhe\u00e7o muitos casos em que, apesar de o ClickHouse ter suporte interno \u00e0 replica\u00e7\u00e3o, as pessoas replicam o ClickHouse manualmente.<\/p>\n<p><\/p>\n<p>Qual \u00e9 o princ\u00edpio? Voc\u00ea tem um pipeline de processamento de dados. E ele opera independentemente, por exemplo, em diferentes data centers. Voc\u00ea grava os mesmos dados da mesma forma no ClickHouse. No entanto, a pr\u00e1tica mostra que os dados acabar\u00e3o divergindo devido a algumas peculiaridades no seu c\u00f3digo. Espero que isso n\u00e3o aconte\u00e7a com o seu. <\/p>\n<p><\/p>\n<p>E periodicamente voc\u00ea ainda precisar\u00e1 fazer a sincroniza\u00e7\u00e3o manualmente. Por exemplo, uma vez por m\u00eas, os administradores fazem rsync.<\/p>\n<p><\/p>\n<p>Na verdade, \u00e9 muito mais simples usar a replica\u00e7\u00e3o embutida no ClickHouse. Mas aqui podem haver algumas contraindica\u00e7\u00f5es, pois para isso \u00e9 necess\u00e1rio usar o ZooKeeper. N\u00e3o direi nada de ruim sobre o ZooKeeper, no geral, o sistema funciona, mas \u00e0s vezes as pessoas n\u00e3o o utilizam devido \u00e0 fobia de Java, porque o ClickHouse \u00e9 um sistema muito bom, escrito em C++, que pode ser utilizado e funcionar\u00e1 tudo bem. E o ZooKeeper \u00e9 em Java. E de alguma forma, n\u00e3o d\u00e1 vontade de olhar para isso, mas ent\u00e3o voc\u00ea pode usar a replica\u00e7\u00e3o manual. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/3b5b68996daef6b8920f067b189f25e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O ClickHouse \u00e9 um sistema pr\u00e1tico. Ele leva em considera\u00e7\u00e3o suas necessidades. Se voc\u00ea tiver replica\u00e7\u00e3o manual, poder\u00e1 criar uma tabela Distribu\u00edda que observa suas r\u00e9plicas manuais e realiza failover entre elas. E h\u00e1 at\u00e9 uma op\u00e7\u00e3o especial que permite evitar flaps, mesmo que suas r\u00e9plicas divergiam sistematicamente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/70f6630f8b14756163923a7db8dd7391.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al\u00e9m disso, podem haver problemas se voc\u00ea estiver usando motores de tabela primitivos. O ClickHouse \u00e9 como um construtor, onde existem muitos tipos diferentes de motores de tabela. Para todos os casos s\u00e9rios, como est\u00e1 escrito na documenta\u00e7\u00e3o, use tabelas da fam\u00edlia MergeTree. Os outros s\u00e3o apenas para casos espec\u00edficos ou para testes.<\/p>\n<p><\/p>\n<p>Na tabela MergeTree, n\u00e3o \u00e9 necess\u00e1rio que voc\u00ea tenha uma data e hora. Voc\u00ea ainda pode utiliz\u00e1-la. Se n\u00e3o houver data e hora, coloque um valor padr\u00e3o de 2000. Isso vai funcionar e n\u00e3o exigir\u00e1 recursos. <\/p>\n<p><\/p>\n<p>E na nova vers\u00e3o do servidor, voc\u00ea pode at\u00e9 especificar para ter particionamento customizado sem uma chave de parti\u00e7\u00e3o. Isso ser\u00e1 o mesmo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/6d4046d11afdd1e5962d49a1612b666a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por outro lado, voc\u00ea pode usar mecanismos de tabela primitivos. Por exemplo, encher os dados uma vez e ver, manipular e excluir. Voc\u00ea pode usar o Log.<\/p>\n<p><\/p>\n<p>Ou o armazenamento de pequenos volumes para processamento intermedi\u00e1rio \u2013 isso \u00e9 StripeLog ou TinyLog.<\/p>\n<p><\/p>\n<p>Memory pode ser usado se o volume de dados for pequeno e voc\u00ea precisar apenas manipular algo na RAM. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/8a3d4e0e3a8c26dd3a2b2f64123e2bf9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>ClickHouse n\u00e3o gosta muito de dados hiper-normalizados. <\/p>\n<p><\/p>\n<p>Aqui est\u00e1 um exemplo t\u00edpico. \u00c9 uma enorme quantidade de URLs. Voc\u00ea os colocou em uma tabela vizinha. E ent\u00e3o decidiu fazer um JOIN com eles, mas isso normalmente n\u00e3o funcionar\u00e1, porque ClickHouse suporta apenas Hash JOIN. Se n\u00e3o houver RAM suficiente para o grande volume de dados que precisam ser unidos, ent\u00e3o o JOIN n\u00e3o poder\u00e1 ser realizado*. <\/p>\n<p><\/p>\n<p>Se os dados tiverem alta cardinalidade, n\u00e3o se preocupe, armazene-os de forma denormalizada, URLs diretamente inplace na tabela principal. <\/p>\n<p><\/p>\n<p>* agora o ClickHouse tamb\u00e9m tem merge join, e ele funciona quando os dados intermedi\u00e1rios n\u00e3o cabem na RAM. Mas isso n\u00e3o \u00e9 eficiente e a recomenda\u00e7\u00e3o permanece v\u00e1lida.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/e8160a8db17c18d48f810092c55b094c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mais alguns exemplos, mas j\u00e1 estou na d\u00favida se eles s\u00e3o antipadr\u00f5es ou n\u00e3o. <\/p>\n<p><\/p>\n<p>O ClickHouse tem uma desvantagem conhecida. Ele n\u00e3o suporta updates*. Em certo sentido, isso \u00e9 at\u00e9 bom. Se voc\u00ea tiver dados importantes, como contabilidade, ningu\u00e9m poder\u00e1 alter\u00e1-los, porque n\u00e3o h\u00e1 suporte para updates.<\/p>\n<p><\/p>\n<p>* j\u00e1 foi adicionada h\u00e1 tempos a compatibilidade com update e delete em modo batch.<\/p>\n<p><\/p>\n<p>Mas existem algumas maneiras especiais que permitem updates, de certa forma em segundo plano. Por exemplo, tabelas do tipo ReplaceMergeTree. Elas fazem updates durante as mesclagens em segundo plano. Voc\u00ea pode for\u00e7ar isso usando optimize table. Mas n\u00e3o fa\u00e7a isso com muita frequ\u00eancia, pois resultar\u00e1 em reescrita completa da parti\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p>JOINs distribu\u00eddos no ClickHouse tamb\u00e9m s\u00e3o mal tratados pelo planejador de consultas. <\/p>\n<p><\/p>\n<p>Ruim, mas \u00e0s vezes \u00e9 aceit\u00e1vel.<\/p>\n<p><\/p>\n<p>Usar ClickHouse apenas para ler dados de volta com select*.<\/p>\n<p><\/p>\n<p>Eu n\u00e3o recomendaria usar ClickHouse para c\u00e1lculos pesados. Mas n\u00e3o \u00e9 bem assim, porque j\u00e1 estamos nos afastando dessa recomenda\u00e7\u00e3o. E recentemente adicionamos a possibilidade de aplicar modelos de aprendizado de m\u00e1quina no ClickHouse \u2013 Catboost. E isso me preocupa, porque eu penso: \"Que horror. Quantos ciclos por byte isso resulta!\". Fico muito triste em gastar ciclos em bytes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Uso eficaz do ClickHouse. Alexey Milovidov (Yandex)\" src=\"\/wp-content\/uploads\/2020\/08\/f686d5d352ccb444cd06e2ae68897137.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mas n\u00e3o se preocupe, instale o ClickHouse, tudo vai ficar bem. Se precisar, temos uma comunidade. Ali\u00e1s, a comunidade \u00e9 voc\u00ea. E se voc\u00ea tiver algum problema, pode ao menos entrar no nosso chat e, espero, que algu\u00e9m te ajude. <\/p>\n<p><\/p>\n<p>Perguntas<\/p>\n<p><\/p>\n<p><em>Obrigado pela apresenta\u00e7\u00e3o! Onde posso reclamar sobre a queda do ClickHouse?<\/em><\/p>\n<p><\/p>\n<p>Voc\u00ea pode reclamar comigo pessoalmente agora mesmo. <\/p>\n<p><\/p>\n<p><em>Recentemente comecei a usar o ClickHouse. Logo derrubei a interface cli.<\/em><\/p>\n<p><\/p>\n<p>Voc\u00ea teve sorte. <\/p>\n<p><\/p>\n<p><em>Mais tarde derrubei o servidor com um pequeno select.<\/em><\/p>\n<p><\/p>\n<p>Voc\u00ea tem talento. <\/p>\n<p><\/p>\n<p><em>Eu abri um bug no GitHub, mas ignoraram.<\/em> <\/p>\n<p><\/p>\n<p>Vamos ver. <\/p>\n<p><\/p>\n<p><em>O Alexey me enganou para me levar \u00e0 apresenta\u00e7\u00e3o, prometendo falar sobre como voc\u00ea compacta os dados por dentro.<\/em><\/p>\n<p><\/p>\n<p>\u00c9 muito simples. <\/p>\n<p><\/p>\n<p><em>Eu percebi isso ontem. Mais detalhes.<\/em> <\/p>\n<p><\/p>\n<p>N\u00e3o h\u00e1 nada de terrivelmente complicado. \u00c9 apenas compress\u00e3o por blocos. Por padr\u00e3o, usa-se LZ4, mas pode-se ativar ZSTD*. Blocos variam de 64 kilobytes a 1 megabyte.<\/p>\n<p><\/p>\n<p>* tamb\u00e9m h\u00e1 suporte para codecs de compress\u00e3o especializados que podem ser usados em combina\u00e7\u00e3o com outros algoritmos.<\/p>\n<p><\/p>\n<p><em>Os blocos cont\u00eam apenas dados crus?<\/em><\/p>\n<p><\/p>\n<p>N\u00e3o exatamente crus. S\u00e3o arrays. Se voc\u00ea tem uma coluna num\u00e9rica, os n\u00fameros est\u00e3o organizados em um array sequencial. <\/p>\n<p><\/p>\n<p><em>Entendi.<\/em> <\/p>\n<p><\/p>\n<p><em>Alexey, o exemplo que foi com uniqExact sobre endere\u00e7os IP, ou seja, o que o uniqExact leva mais tempo para calcular em strings do que em n\u00fameros e assim por diante. E se aplicarmos um truque e fizermos o casting no momento da leitura? Ou seja, voc\u00ea, aparentemente, disse que no disco isso n\u00e3o varia muito. Se lermos strings do disco e fizermos o casting, ent\u00e3o nossos agregados ser\u00e3o mais r\u00e1pidos ou n\u00e3o? Ou acabamos ganhando algo insignificante aqui? Eu acho que voc\u00ea testou isso, mas n\u00e3o mencionou no benchmark.<\/em> <\/p>\n<p><\/p>\n<p>Acho que ser\u00e1 mais lento do que sem o cast. Nesse caso, o endere\u00e7o IP precisa ser extra\u00eddo da string. Claro que em ClickHouse a extra\u00e7\u00e3o de endere\u00e7os IP tamb\u00e9m \u00e9 otimizada. N\u00f3s nos esfor\u00e7amos bastante, mas os n\u00fameros est\u00e3o registrados em forma de dez mil. Muito inconveniente. Por outro lado, a fun\u00e7\u00e3o uniqExact funcionar\u00e1 com strings mais lentamente, n\u00e3o apenas porque s\u00e3o strings, mas tamb\u00e9m porque \u00e9 escolhida uma especializa\u00e7\u00e3o diferente do algoritmo. Strings s\u00e3o processadas de forma diferente.<\/p>\n<p><\/p>\n<p><em>E se pegarmos um tipo de dado mais primitivo? Por exemplo, registramos o user id, que temos in, registramos como uma string e depois fazemos o cast, ser\u00e1 mais divertido ou n\u00e3o?<\/em><\/p>\n<p><\/p>\n<p>Eu duvido. Acho que ser\u00e1 at\u00e9 mais triste, porque, afinal, analisar n\u00fameros \u00e9 um problema s\u00e9rio. Tenho a impress\u00e3o de que esse colega fez at\u00e9 uma apresenta\u00e7\u00e3o sobre como \u00e9 dif\u00edcil analisar n\u00fameros na forma de dez mil, ou talvez n\u00e3o. <\/p>\n<p><\/p>\n<p><em>Alexey, muito obrigado pela apresenta\u00e7\u00e3o! E tamb\u00e9m muito obrigado pelo ClickHouse! Eu tenho uma pergunta sobre os planos. Existe a possibilidade de uma funcionalidade para atualizar dicion\u00e1rios parcialmente?<\/em><\/p>\n<p><\/p>\n<p>Ou seja, uma recarga parcial?<\/p>\n<p><\/p>\n<p><em>Sim, sim. Algo como a possibilidade de especificar um campo MySQL, ou seja, atualizar ap\u00f3s para carregar apenas esses dados, se o dicion\u00e1rio for muito grande.<\/em><\/p>\n<p><\/p>\n<p>Uma funcionalidade muito interessante. E acho que algu\u00e9m a sugeriu no nosso chat. Pode ser que tenha sido voc\u00ea. <\/p>\n<p><\/p>\n<p><em>N\u00e3o acho que fui eu.<\/em><\/p>\n<p><\/p>\n<p>\u00d3timo, ent\u00e3o agora temos dois pedidos. E podemos come\u00e7ar devagar. Mas quero avis\u00e1-lo imediatamente que essa funcionalidade \u00e9 bastante simples de implementar. Ou seja, teoricamente, precisamos apenas escrever o n\u00famero da vers\u00e3o na tabela e, em seguida, escrever: a vers\u00e3o \u00e9 menor que tal. E isso significa que, provavelmente, iremos sugerir que entusiastas fa\u00e7am isso. Voc\u00ea \u00e9 um entusiasta? <\/p>\n<p><\/p>\n<p><em>Sim, mas, infelizmente, n\u00e3o em C++.<\/em><\/p>\n<p><\/p>\n<p>Seus colegas conseguem programar em C++? <\/p>\n<p><\/p>\n<p><em>Vou encontrar algu\u00e9m.<\/em><\/p>\n<p><\/p>\n<p>Perfeito.<\/p>\n<p><\/p>\n<p>* a funcionalidade foi adicionada dois meses ap\u00f3s a apresenta\u00e7\u00e3o \u2013 foi desenvolvida pelo autor da pergunta e enviada. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/ClickHouse\/ClickHouse\/pull\/1771\">pull request<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><em>Obrigado!<\/em><\/p>\n<p><\/p>\n<p><em>Ol\u00e1! Obrigado pela apresenta\u00e7\u00e3o! Voc\u00ea mencionou que o ClickHouse utiliza muito bem todos os recursos dispon\u00edveis. E o palestrante ao lado da Luxoft falou sobre sua solu\u00e7\u00e3o para os Correios da R\u00fassia. Ele disse que gostaram muito do ClickHouse, mas n\u00e3o o usaram em vez de seu principal concorrente devido ao fato de que ele consumia toda a CPU. E n\u00e3o conseguiram integr\u00e1-lo \u00e0 sua arquitetura, ao seu ZooKeeper com Docker. Existe uma maneira de limitar o ClickHouse para que ele n\u00e3o consuma tudo o que est\u00e1 dispon\u00edvel?<\/em><\/p>\n<p><\/p>\n<p>Sim, \u00e9 poss\u00edvel e muito f\u00e1cil. Se voc\u00ea quiser que consuma menos n\u00facleos, basta escrever <code>set max_threads = 1<\/code>. E assim, ele executar\u00e1 a consulta em um \u00fanico n\u00facleo. Al\u00e9m disso, \u00e9 poss\u00edvel definir configura\u00e7\u00f5es diferentes para diferentes usu\u00e1rios. Portanto, n\u00e3o h\u00e1 problemas. E informe aos colegas da Luxoft que n\u00e3o \u00e9 bom que n\u00e3o tenham encontrado essa configura\u00e7\u00e3o na documenta\u00e7\u00e3o. <\/p>\n<p><\/p>\n<p><em>Alexei, ol\u00e1! Gostaria de perguntar sobre uma quest\u00e3o. N\u00e3o \u00e9 a primeira vez que ou\u00e7o que muitos come\u00e7am a usar o ClickHouse como armazenamento de logs. Na apresenta\u00e7\u00e3o voc\u00ea disse para n\u00e3o fazer isso, ou seja, n\u00e3o \u00e9 necess\u00e1rio armazenar strings longas. O que voc\u00ea pensa sobre isso?<\/em><\/p>\n<p><\/p>\n<p>Em primeiro lugar, logs geralmente n\u00e3o s\u00e3o strings longas. Pode haver, \u00e9 claro, exce\u00e7\u00f5es. Por exemplo, algum servi\u00e7o escrito em Java gera uma exce\u00e7\u00e3o, que \u00e9 registrada. E assim em um ciclo infinito, e o espa\u00e7o no disco r\u00edgido acaba. A solu\u00e7\u00e3o \u00e9 muito simples. Se as strings forem muito longas, corte-as. E o que significa longo? Dezenas de quilobytes \u00e9 ruim*.<\/p>\n<p><\/p>\n<p>* nas vers\u00f5es mais recentes do ClickHouse, foi inclu\u00edda a \"granularidade adaptativa do \u00edndice\", o que resolve em grande parte o problema de armazenamento de strings longas.<\/p>\n<p><\/p>\n<p><em>E um quilobyte \u00e9 normal?<\/em><\/p>\n<p><\/p>\n<p>Normal. <\/p>\n<p><\/p>\n<p><em>Ol\u00e1! Obrigado pela apresenta\u00e7\u00e3o! J\u00e1 perguntei isso no chat, mas n\u00e3o lembro se recebi resposta. Est\u00e1 previsto expandir a se\u00e7\u00e3o WITH de maneira semelhante ao CTE?<\/em><\/p>\n<p><\/p>\n<p>Por enquanto n\u00e3o. A se\u00e7\u00e3o WITH \u00e9 um pouco s\u00e9ria. \u00c9 uma pequena funcionalidade que temos.<\/p>\n<p><\/p>\n<p><em>Entendi. Obrigado!<\/em><\/p>\n<p><\/p>\n<p><em>Obrigado pela apresenta\u00e7\u00e3o! Muito interessante! Uma pergunta global. Est\u00e1 previsto fazer, talvez, alguma modifica\u00e7\u00e3o na exclus\u00e3o de dados?<\/em><\/p>\n<p><\/p>\n<p>Com certeza. Essa \u00e9 nossa primeira tarefa na fila. Estamos pensando ativamente em como fazer tudo corretamente. E \u00e9 hora de come\u00e7ar a digitar*.<\/p>\n<p><\/p>\n<p>* pressionamos bot\u00f5es no teclado e tudo foi feito.<\/p>\n<p><\/p>\n<p><em>Isso afetar\u00e1 de alguma forma o desempenho do sistema ou n\u00e3o? A inser\u00e7\u00e3o ser\u00e1 t\u00e3o r\u00e1pida quanto agora?<\/em><\/p>\n<p><\/p>\n<p>Talvez os pr\u00f3prios deletes, os pr\u00f3prios updates sejam muito pesados, mas isso n\u00e3o afetar\u00e1 o desempenho dos selects e o desempenho dos inserts.<\/p>\n<p><\/p>\n<p><em>E mais uma pequena pergunta. Na apresenta\u00e7\u00e3o, voc\u00ea falou sobre a chave prim\u00e1ria. Portanto, temos o particionamento, que por padr\u00e3o \u00e9 mensal, correto? E quando definimos um intervalo de datas que se encaixa em um m\u00eas, lemos apenas essa parti\u00e7\u00e3o, certo?<\/em><\/p>\n<p><\/p>\n<p>Sim.<\/p>\n<p><\/p>\n<p><em>Tenho uma pergunta. Se n\u00e3o conseguimos destacar alguma chave prim\u00e1ria, \u00e9 correto faz\u00ea-la pelo campo \"Data\" para que, em segundo plano, haja uma menor reorganiza\u00e7\u00e3o desses dados, permitindo que eles fiquem mais organizados? Se voc\u00ea n\u00e3o tem consultas em intervalos e n\u00e3o consegue escolher nenhuma chave prim\u00e1ria, vale a pena incluir a data na chave prim\u00e1ria?<\/em><\/p>\n<p><\/p>\n<p>Sim.<\/p>\n<p><\/p>\n<p>Talvez fa\u00e7a sentido incluir no chave prim\u00e1ria um campo pelo qual os dados possam ser melhor compactados, se eles forem ordenados por esse campo. Por exemplo, o identificador do usu\u00e1rio. O usu\u00e1rio, por exemplo, acessa o mesmo site. Nesse caso, voc\u00ea coloca o id do usu\u00e1rio e o tempo. Assim, seus dados ser\u00e3o melhor compactados. Quanto \u00e0 data, se voc\u00ea realmente n\u00e3o tem e nunca ter\u00e1 consultas em intervalos de datas, ent\u00e3o pode n\u00e3o incluir a data na chave prim\u00e1ria. <\/p>\n<p><\/p>\n<p><em>Certo, muito obrigado!<\/em><\/p>\n<p>Fonte: <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.3 - 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\/pt\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\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\/pt\/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 eficaz do ClickHouse. Alexey Milovidov (Yandex) | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/effektivnoe-ispolzovanie-clickhouse-aleksej-milovidov-yandeks","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/91438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=91438"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/91438\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/91439"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=91438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=91438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=91438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}