{"id":74737,"date":"2020-03-20T08:43:14","date_gmt":"2020-03-20T05:43:14","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa"},"modified":"2020-03-20T08:43:14","modified_gmt":"2020-03-20T05:43:14","slug":"optimizacziya-strok-v-clickhouse-doklad-yandeksa","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa","title":{"rendered":"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>O banco de dados anal\u00edtico ClickHouse processa muitas strings diferentes, consumindo recursos. Para acelerar o funcionamento do sistema, novas otimiza\u00e7\u00f5es est\u00e3o constantemente sendo adicionadas. O desenvolvedor do ClickHouse, Nikolai Kochetov, fala sobre o tipo de dado string, incluindo um novo tipo, LowCardinality, e explica como \u00e9 poss\u00edvel acelerar o trabalho com strings. <\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"rqf-ILRgBdY\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/rqf-ILRgBdY\/hqdefault.jpg\" alt=\"Por que no hosting comum a administra\u00e7\u00e3o do PrestaShop \u00e9 lenta, e no seu n\u00e3o \u00e9?\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\n\u2014 Primeiro, vamos entender como podemos armazenar strings. <br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\n<img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/5e38e903aaaf54a533bd3026e76a14be.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTemos tipos de dados string. String \u00e9 uma boa op\u00e7\u00e3o por padr\u00e3o, e deve ser usado quase sempre. Ele tem uma sobrecarga pequena \u2014 9 bytes por string. Se quisermos que o tamanho das strings seja fixo e conhecido previamente, \u00e9 melhor usar FixedString. Com ele, podemos estabelecer o n\u00famero exato de bytes que precisamos, sendo conveniente para dados como endere\u00e7os IP ou fun\u00e7\u00f5es de hash. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/eaae898fb5163cb1c070c34a13f6f160.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nClaro, \u00e0s vezes algo pode ficar lento. Suponha que voc\u00ea esteja fazendo uma consulta a uma tabela. O ClickHouse l\u00ea uma quantidade consider\u00e1vel de dados, digamos, a uma velocidade de 100 GB\/s, mas processa poucas strings. Temos duas tabelas que armazenam dados quase id\u00eanticos. A partir da segunda tabela, o ClickHouse l\u00ea os dados com mais rapidez, mas as strings por segundo lidas s\u00e3o tr\u00eas vezes menores. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/be7cc47e628112bb212ed0e8ff9091ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSe olharmos para o tamanho dos dados comprimidos, ele ser\u00e1 quase igual. Na verdade, as mesmas informa\u00e7\u00f5es est\u00e3o gravadas nas tabelas \u2014 o primeiro bilh\u00e3o de n\u00fameros \u2014 apenas que na primeira coluna est\u00e3o armazenados como UInt64, enquanto na segunda como String. Por causa disso, a segunda consulta leva mais tempo para ler os dados do disco e descompri-los. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/c699103cecd972fcee73841cc35716d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAqui est\u00e1 outro exemplo. Suponha que exista um conjunto de strings previamente conhecido, que \u00e9 limitado a uma constante de 1000 ou 10.000 e praticamente nunca muda. Para esse caso, o tipo de dado Enum \u00e9 apropriado, e no ClickHouse existem dois \u2014 Enum8 e Enum16. Gra\u00e7as ao armazenamento em Enum, conseguimos processar consultas rapidamente. <\/p>\n<p>No ClickHouse, existem melhorias para GROUP BY, IN, DISTINCT e otimiza\u00e7\u00f5es para algumas fun\u00e7\u00f5es, como a compara\u00e7\u00e3o com uma string constante. \u00c9 claro que n\u00fameros em strings n\u00e3o s\u00e3o convertidos, mas, ao contr\u00e1rio, a string constante \u00e9 convertida em um valor Enum. Ap\u00f3s isso, todas as compara\u00e7\u00f5es s\u00e3o feitas rapidamente. <\/p>\n<p>Mas h\u00e1 desvantagens. Mesmo que conhe\u00e7amos o conjunto exato de strings, \u00e0s vezes ele precisa ser expandido. Se uma nova string aparecer, precisamos realizar um ALTER. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/064c35faaf3d9de2f12d29f83197e983.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO ALTER para Enum no ClickHouse \u00e9 implementado de forma otimizada. N\u00e3o reescrevemos os dados no disco, mas o ALTER pode atrasar devido ao fato de que as estruturas Enum s\u00e3o armazenadas no esquema da pr\u00f3pria tabela. Portanto, precisamos esperar as consultas de leitura da tabela, por exemplo. <\/p>\n<p>Surge a quest\u00e3o, \u00e9 poss\u00edvel fazer melhor? Provavelmente, sim. \u00c9 poss\u00edvel armazenar a estrutura Enum n\u00e3o no esquema da tabela, mas no ZooKeeper. No entanto, podem surgir problemas relacionados \u00e0 sincroniza\u00e7\u00e3o. Por exemplo, uma r\u00e9plica recebeu os dados, a outra n\u00e3o, e se ela tiver um Enum antigo, algo pode quebrar. (No ClickHouse, quase terminamos as consultas ALTER n\u00e3o bloqueantes. Quando terminarmos completamente, n\u00e3o ser\u00e1 necess\u00e1rio esperar pelas consultas de leitura.)<\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/f5d2fdf14778f6afdd4acc8c204e163c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPara evitar complica\u00e7\u00f5es com o ALTER Enum, podemos usar dicion\u00e1rios externos do ClickHouse. Lembro que isso \u00e9 uma estrutura de dados key-value dentro do ClickHouse, atrav\u00e9s da qual \u00e9 poss\u00edvel obter dados de fontes externas, como tabelas MySQL. <\/p>\n<p>No dicion\u00e1rio ClickHouse, armazenamos v\u00e1rias strings diferentes, enquanto que na tabela guardamos seus identificadores como n\u00fameros. Se for necess\u00e1rio obter uma string, chamamos a fun\u00e7\u00e3o dictGet e trabalhamos com ela. Depois disso, n\u00e3o precisamos fazer ALTER. Para adicionar algo ao Enum, inserimos isso na mesma tabela MySQL. <\/p>\n<p>Mas surgem outros problemas. Primeiro, a sintaxe pouco conveniente. Se queremos obter uma string, precisamos chamar dictGet. Em segundo lugar, falta de algumas otimiza\u00e7\u00f5es. Comparar com uma string constante para dicion\u00e1rios n\u00e3o \u00e9 t\u00e3o r\u00e1pido. <\/p>\n<p>Ainda podem haver problemas com atualiza\u00e7\u00f5es. Suponha que requisitamos uma string no dicion\u00e1rio cache e ela n\u00e3o foi para o cache. Ent\u00e3o, precisamos esperar que os dados sejam carregados de uma fonte externa. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/534818ee523a243623a5cb2babe08040.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUma desvantagem comum de ambos os m\u00e9todos \u00e9 que armazenamos todas as chaves em um s\u00f3 lugar e as sincronizamos. Ent\u00e3o, por que n\u00e3o armazenar dicion\u00e1rios localmente? Sem sincroniza\u00e7\u00e3o, sem problemas. Podemos armazenar o dicion\u00e1rio localmente em um peda\u00e7o no disco. Ou seja, fizemos um Insert, gravamos o dicion\u00e1rio. Se trabalhamos com dados na mem\u00f3ria, podemos gravar o dicion\u00e1rio em um bloco de dados, ou em um peda\u00e7o da coluna, ou em algum cache, para acelerar os c\u00e1lculos.<\/p>\n<h3>Codifica\u00e7\u00e3o de strings em dicion\u00e1rio <\/h3>\n<p>\nAssim, chegamos \u00e0 cria\u00e7\u00e3o de um novo tipo de dado no ClickHouse \u2014 LowCardinality. Este \u00e9 um formato de armazenamento de dados: como eles s\u00e3o gravados no disco e lidos, como s\u00e3o representados na mem\u00f3ria e o esquema de seu processamento. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/e25b2eb12ff158b89b7d2dbdfb8e2e5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNo slide, existem duas colunas. \u00c0 direita, as linhas s\u00e3o armazenadas de forma padr\u00e3o, no tipo String. \u00c9 vis\u00edvel que se tratam de modelos de telefones m\u00f3veis. \u00c0 esquerda, h\u00e1 exatamente a mesma coluna, apenas no tipo LowCardinality. Ela consiste em um dicion\u00e1rio com v\u00e1rias strings diferentes (as strings da coluna \u00e0 direita) e uma lista de posi\u00e7\u00f5es (n\u00fameros das linhas). <\/p>\n<p>Com essas duas estruturas, podemos recuperar a coluna original. Tamb\u00e9m existe um \u00edndice inverso - uma tabela hash, que ajuda a encontrar a posi\u00e7\u00e3o no dicion\u00e1rio a partir da string. Isso \u00e9 necess\u00e1rio para acelerar algumas consultas. Por exemplo, se quisermos comparar, buscar uma string em nossa coluna ou mescl\u00e1-las. <\/p>\n<p>LowCardinality \u00e9 um tipo de dado param\u00e9trico. Ele pode ser um n\u00famero, ou algo que \u00e9 armazenado como n\u00famero, ou uma string, ou Nullable desses. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/d52ef0c99617238442d4f71e43af48af.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA caracter\u00edstica do LowCardinality \u00e9 que ele pode ser salvo para algumas fun\u00e7\u00f5es. No slide, podemos ver um exemplo de consulta. Na primeira linha, criei uma coluna do tipo LowCardinality de String, chamada S. Em seguida, perguntei seu nome - o ClickHouse disse que \u00e9 LowCardinality de String. Tudo certo.<\/p>\n<p>A terceira linha \u00e9 quase igual, exceto que chamamos a fun\u00e7\u00e3o length. No ClickHouse, a fun\u00e7\u00e3o length retorna o tipo de dado UInt64. Mas agora temos LowCardinality de UInt64. Qual \u00e9 o sentido?<\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/a4a51a0f1ecd68f7fffd521ab786c8a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNo dicion\u00e1rio estavam os nomes dos telefones m\u00f3veis, aplicamos a fun\u00e7\u00e3o length. Agora temos um dicion\u00e1rio semelhante, consistindo apenas de n\u00fameros - s\u00e3o os comprimentos das strings. A coluna com posi\u00e7\u00f5es n\u00e3o se alterou. No final, processamos menos dados, economizamos tempo de consulta. <\/p>\n<p>Podem haver outras otimiza\u00e7\u00f5es, por exemplo, a adi\u00e7\u00e3o de um cache simples. Ao calcular o valor de uma fun\u00e7\u00e3o, podemos memorizar e criar o mesmo, sem recalcul\u00e1-lo. <\/p>\n<p>Tamb\u00e9m pode ser feita uma otimiza\u00e7\u00e3o de GROUP BY, pois nossa coluna com o dicion\u00e1rio j\u00e1 est\u00e1 parcialmente agregada - podemos calcular mais rapidamente os valores das fun\u00e7\u00f5es hash e encontrar aproximadamente o bucket onde colocar a pr\u00f3xima linha. Al\u00e9m disso, algumas fun\u00e7\u00f5es agregadas podem ser especializadas, como uniq, pois para ela s\u00f3 pode ser enviado o dicion\u00e1rio, enquanto as posi\u00e7\u00f5es permanecem intactas - assim, tudo funcionar\u00e1 mais r\u00e1pido. As duas primeiras otimiza\u00e7\u00f5es j\u00e1 foram adicionadas ao ClickHouse.<\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/943e0a8ae5a37cd47164246db3a67893.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nE se criarmos uma coluna com nosso tipo de dados e inserirmos muitas strings ruins diferentes? Nossa mem\u00f3ria vai ficar cheia? N\u00e3o, para isso o ClickHouse tem duas configura\u00e7\u00f5es especiais. A primeira \u00e9 low_cardinality_max_dictionary_size. Este \u00e9 o tamanho m\u00e1ximo do dicion\u00e1rio que pode ser gravado no disco. A inser\u00e7\u00e3o acontece da seguinte forma: quando inserimos dados, recebemos um fluxo de strings das quais formamos um grande dicion\u00e1rio comum. Se o dicion\u00e1rio se torna maior que o valor da configura\u00e7\u00e3o, gravamos o dicion\u00e1rio atual no disco, e as outras strings ficam \u2018de lado\u2019, pr\u00f3ximas aos \u00edndices. No final, nunca recalcularemos um grande dicion\u00e1rio e n\u00e3o teremos problemas de mem\u00f3ria. <\/p>\n<p>A segunda configura\u00e7\u00e3o \u00e9 chamada low_cardinality_use_single_dictionary_for_part. Imagine que, na esquema anterior, quando inserimos dados, nosso dicion\u00e1rio ficou cheio e o gravamos no disco. Surge a quest\u00e3o, por que n\u00e3o formar outro dicion\u00e1rio exatamente igual agora? <\/p>\n<p>Quando ele ficar cheio, gravaremos novamente no disco e come\u00e7aremos a formar um terceiro. Essa configura\u00e7\u00e3o basicamente desativa essa possibilidade por padr\u00e3o. <\/p>\n<p>Na verdade, muitos dicion\u00e1rios podem ser \u00fateis se quisermos inserir um conjunto de strings, mas acidentalmente inserimos \u2018lixo\u2019. Digamos que primeiro inserimos strings ruins e depois inserimos boas. Assim, o dicion\u00e1rio se dividir\u00e1 em muitos pequenos dicion\u00e1rios. Alguns deles conter\u00e3o \u2018lixo\u2019, mas os \u00faltimos ter\u00e3o boas strings. E se lermos, por exemplo, apenas o \u00faltimo gr\u00e2nulo, tudo vai funcionar rapidamente. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/834ba3295ace98870334aa10a78e4781.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAntes de falar sobre as vantagens do LowCardinality, j\u00e1 aviso que provavelmente n\u00e3o conseguiremos uma redu\u00e7\u00e3o nos dados no disco (embora isso possa acontecer), porque o ClickHouse comprime dados. Existe uma op\u00e7\u00e3o padr\u00e3o \u2014 LZ4. Tamb\u00e9m \u00e9 poss\u00edvel fazer compress\u00e3o com ZSTD. Mas ambos os algoritmos j\u00e1 implementam compress\u00e3o de dicion\u00e1rio, portanto, nosso dicion\u00e1rio externo do ClickHouse n\u00e3o ajudar\u00e1 muito. <\/p>\n<p>Para n\u00e3o ficar na superficialidade, eu peguei alguns dados da m\u00e9trica \u2014 String, LowCardinality(String) e Enum \u2014 e os salvei em diferentes tipos de dados. Surgiram tr\u00eas colunas, onde foi registrado um bilh\u00e3o de linhas. Na primeira coluna, CodePage, h\u00e1 apenas 62 valores. E \u00e9 vis\u00edvel que no LowCardinality(String) conseguimos uma compress\u00e3o melhor. String \u00e9 um pouco pior, mas isso provavelmente se deve ao fato de que as strings s\u00e3o curtas; armazenamos seus comprimentos, o que ocupa muito espa\u00e7o e se comprime mal. <\/p>\n<p>Se pegarmos PhoneModel, s\u00e3o 48 mil \u2014 j\u00e1 mais, e as diferen\u00e7as entre String e LowCardinality(String) quase n\u00e3o existem. Para URLs, tamb\u00e9m economizamos apenas 2 GB \u2014 acho que n\u00e3o vale a pena contar com isso. <\/p>\n<h3>Avalia\u00e7\u00e3o da velocidade de opera\u00e7\u00e3o<\/h3>\n<p>\n<img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/0b646570639f8f2e29b599473b84e25c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<b><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/toddwschneider\/nyc-taxi-data\">Link do slide<\/a><\/noindex><\/b><\/p>\n<p>Agora vamos avaliar a velocidade de opera\u00e7\u00e3o. Para isso, usei um conjunto de dados com a descri\u00e7\u00e3o das corridas de t\u00e1xi em Nova York. Ele <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/toddwschneider\/nyc-taxi-data\">dispon\u00edvel<\/a><\/noindex> est\u00e1 no GitHub. H\u00e1 pouco mais de um bilh\u00e3o de corridas. Ele reflete a localiza\u00e7\u00e3o, o hor\u00e1rio de in\u00edcio e t\u00e9rmino da corrida, o m\u00e9todo de pagamento, o n\u00famero de passageiros e at\u00e9 o tipo de t\u00e1xi \u2014 verde, amarelo e Uber. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/0901669dec01b0f956d6976e3aa8b741.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO primeiro pedido que fiz foi bastante simples \u2014 perguntei onde as pessoas mais costumam chamar t\u00e1xi. Para isso, \u00e9 necess\u00e1rio pegar a localiza\u00e7\u00e3o de onde foram feitas as chamadas, agrupar por essa localiza\u00e7\u00e3o e contar a fun\u00e7\u00e3o count. Aqui o ClickHouse apresenta algo. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/50983341e20bcbc1b5adbaed35f8624d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPara medir a velocidade de processamento da consulta, criei tr\u00eas tabelas com os mesmos dados, mas utilizei tr\u00eas tipos de dados diferentes para a nossa localiza\u00e7\u00e3o inicial \u2014 String, LowCardinality e Enum. LowCardinality e Enum se mostraram cinco vezes mais r\u00e1pidos que String. Enum \u00e9 mais r\u00e1pido porque trabalha com n\u00fameros. LowCardinality \u00e9 mais r\u00e1pido devido \u00e0 sua otimiza\u00e7\u00e3o para GROUP BY. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/e2ce4f2127d8728287488c85c92085fc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVamos complicar ainda mais a consulta \u2014 vamos perguntar onde fica o parque mais popular em Nova York. Novamente, mediremos isso com base nos locais onde as pessoas mais costumam chamar t\u00e1xi, mas filtraremos apenas aquelas localiza\u00e7\u00f5es que cont\u00eam a palavra \"parque\". Tamb\u00e9m adicionaremos a fun\u00e7\u00e3o like. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/7cf6fd64751f3ae578581caddde17aaf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOlhamos para o tempo \u2014 vemos que o Enum de repente come\u00e7ou a desacelerar. Al\u00e9m disso, ele est\u00e1 funcionando ainda mais lentamente que o tipo de dado padr\u00e3o String. Isso acontece porque a fun\u00e7\u00e3o like n\u00e3o \u00e9 otimizada para Enum. Precisamos converter nossas strings de Enum em strings normais \u2014 fazemos mais trabalho. LowCardinality(String) tamb\u00e9m n\u00e3o \u00e9 otimizado por padr\u00e3o, mas a fun\u00e7\u00e3o like funciona sobre o dicion\u00e1rio, portanto a consulta \u00e9 mais r\u00e1pida em compara\u00e7\u00e3o com String. <\/p>\n<p>Ao trabalhar com Enum, h\u00e1 um problema mais global. Se quisermos otimiz\u00e1-lo, precisamos fazer isso em cada parte do c\u00f3digo. Suponhamos que escrevemos uma nova fun\u00e7\u00e3o \u2014 \u00e9 necess\u00e1rio pensar em uma otimiza\u00e7\u00e3o para o Enum. J\u00e1 no LowCardinality, tudo \u00e9 otimizado por padr\u00e3o.<\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/459243eb5b3dd993393d0184b224ea09.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVamos olhar para a \u00faltima consulta, um pouco artificial. Vamos simplesmente calcular a fun\u00e7\u00e3o hash da nossa localiza\u00e7\u00e3o. A fun\u00e7\u00e3o hash \u00e9 uma consulta bastante lenta, leva tempo para ser calculada, portanto, tudo fica mais lento em at\u00e9 tr\u00eas vezes.<\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/a5f49c22748971646ec358eb52d3feda.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO LowCardinality ainda funciona mais r\u00e1pido, embora n\u00e3o haja filtragem aqui. Isso ocorre porque nossas fun\u00e7\u00f5es operam apenas sobre o dicion\u00e1rio. A fun\u00e7\u00e3o de c\u00e1lculo do hash tem um argumento \u2014 ela pode processar menos dados e tamb\u00e9m pode retornar LowCardinality. <\/p>\n<p><img decoding=\"async\" alt=\"Otimiza\u00e7\u00e3o de strings no ClickHouse. Palestra do Yandex\" src=\"\/wp-content\/uploads\/2020\/03\/7842b7eb2debb4a4b1d4cbc3488deb32.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNosso plano global \u00e9 alcan\u00e7ar uma velocidade de opera\u00e7\u00e3o n\u00e3o inferior \u00e0 do String em qualquer caso e manter as acelera\u00e7\u00f5es. E, quem sabe, talvez algum dia substituamos o String pelo LowCardinality, voc\u00ea atualiza o ClickHouse e tudo funcionar\u00e1 um pouco mais r\u00e1pido.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/492868\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0421\u0423\u0411\u0414 ClickHouse \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438. \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a ClickHouse \u041d\u0438\u043a\u043e\u043b\u0430\u0439 \u041a\u043e\u0447\u0435\u0442\u043e\u0432 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c \u0442\u0438\u043f\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043e \u043d\u043e\u0432\u043e\u043c \u0442\u0438\u043f\u0435, LowCardinality, \u0438 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438. \u2014 \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438. \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":74738,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-74737","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=\"description\" content=\"\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0421\u0423\u0411\u0414 ClickHouse \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.\" \/>\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\/optimizacziya-strok-v-clickhouse-doklad-yandeksa\" \/>\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\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u0432 ClickHouse. \u0414\u043e\u043a\u043b\u0430\u0434 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0421\u0423\u0411\u0414 ClickHouse \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa\" \/>\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-03-20T05:43:14+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-20T05:43:14+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\udd47Otimiza\u00e7\u00e3o de linhas no ClickHouse. Apresenta\u00e7\u00e3o do Yandex | ProHoster","description":"O banco de dados anal\u00edtico ClickHouse processa muitas linhas diferentes, consumindo recursos. Para acelerar o funcionamento do sistema, novas otimiza\u00e7\u00f5es est\u00e3o constantemente sendo adicionadas.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa","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\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u0432 ClickHouse. \u0414\u043e\u043a\u043b\u0430\u0434 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 | ProHoster","og:description":"\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0421\u0423\u0411\u0414 ClickHouse \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa","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-03-20T05:43:14+00:00","article:modified_time":"2020-03-20T05:43:14+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"74737","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 17:23:10","updated":"2022-09-27 14:48:44","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\/74737","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=74737"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/74737\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/74738"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=74737"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=74737"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=74737"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}