{"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\/pl\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa","title":{"rendered":"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Analityczna baza danych ClickHouse przetwarza wiele r\u00f3\u017cnych ci\u0105g\u00f3w, wykorzystuj\u0105c zasoby. Aby przyspieszy\u0107 dzia\u0142anie systemu, ci\u0105gle dodawane s\u0105 nowe optymalizacje. Programista ClickHouse, Nikolaj Koczetow, opowiada o typie danych ci\u0105gowych, w tym o nowym typie, LowCardinality, i wyja\u015bnia, jak mo\u017cna przyspieszy\u0107 prac\u0119 z ci\u0105gami. <\/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=\"Odtwarzaj wideo\" 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 Na pocz\u0105tku zrozummy, jak mo\u017cna przechowywa\u0107 ci\u0105gi. <br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\n<img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/5e38e903aaaf54a533bd3026e76a14be.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMamy typy danych ci\u0105gowych. String jest dobrze dostosowany jako domy\u015blny, warto go u\u017cywa\u0107 prawie zawsze. Ma niewielki Overhead \u2014 9 bajt\u00f3w na jeden ci\u0105g. Je\u015bli chcemy, aby rozmiar ci\u0105g\u00f3w by\u0142 sta\u0142y i znany z g\u00f3ry, lepiej u\u017cy\u0107 FixedString. W nim mo\u017cna okre\u015bli\u0107 potrzebn\u0105 liczb\u0119 bajt\u00f3w, jest wygodny dla danych typu adresy IP lub funkcje skr\u00f3tu. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/eaae898fb5163cb1c070c34a13f6f160.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOczywi\u015bcie, czasami co\u015b zwalnia. Powiedzmy, \u017ce wykonujesz zapytanie do tabeli. ClickHouse odczytuje do\u015b\u0107 du\u017c\u0105 ilo\u015b\u0107 danych, powiedzmy, z szybko\u015bci\u0105 100 GB\/s, przy jednoczesnym przetwarzaniu niewielkiej liczby ci\u0105g\u00f3w. Mamy dwie tabele, kt\u00f3re przechowuj\u0105 prawie identyczne dane. Z drugiej tabeli ClickHouse odczytuje dane z wi\u0119ksz\u0105 pr\u0119dko\u015bci\u0105, ale liczba ci\u0105g\u00f3w odczytywanych na sekund\u0119 jest trzy razy mniejsza. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/be7cc47e628112bb212ed0e8ff9091ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJe\u017celi spojrzymy na rozmiar skompresowanych danych, oka\u017ce si\u0119, \u017ce jest prawie r\u00f3wny. W rzeczywisto\u015bci w tabelach zapisane s\u0105 te same dane \u2014 miliard pierwszych liczb \u2014 tylko w pierwszej kolumnie zapisane s\u0105 jako UInt64, a w drugiej \u2014 jako String. Z tego powodu drugie zapytanie d\u0142u\u017cej odczytuje dane z dysku i je dekompresuje. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/c699103cecd972fcee73841cc35716d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOto inny przyk\u0142ad. Za\u0142\u00f3\u017cmy, \u017ce istnieje z g\u00f3ry znany zbi\u00f3r ci\u0105g\u00f3w, ograniczony sta\u0142\u0105 1000 lub 10 000 i praktycznie nigdy si\u0119 nie zmienia. Dla tego przypadku odpowiedni jest typ danych Enum, w ClickHouse s\u0105 dwa \u2014 Enum8 i Enum16. Dzi\u0119ki przechowywaniu w Enum szybko przetwarzamy zapytania. <\/p>\n<p>W ClickHouse istniej\u0105 optymalizacje dla GROUP BY, IN, DISTINCT i optymalizacje dla niekt\u00f3rych funkcji, na przyk\u0142ad dla por\u00f3wnania z sta\u0142ym ci\u0105giem. Oczywi\u015bcie liczby w ci\u0105gu nie s\u0105 konwertowane, a wr\u0119cz przeciwnie, sta\u0142y ci\u0105g jest przekszta\u0142cany do warto\u015bci Enum. Po tym wszystkim wszystko szybko si\u0119 por\u00f3wnuje. <\/p>\n<p>Ale s\u0105 te\u017c wady. Nawet je\u015bli znamy dok\u0142adny zbi\u00f3r ci\u0105g\u00f3w, czasami musi on by\u0107 uzupe\u0142niany. Pojawi\u0142 si\u0119 nowy ci\u0105g \u2014 musimy wykona\u0107 ALTER. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/064c35faaf3d9de2f12d29f83197e983.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nALTER dla Enum w ClickHouse jest zoptymalizowane. Nie przepisujemy danych na dysku, ale ALTER mog\u0105 zwalnia\u0107 z powodu tego, \u017ce struktury Enum s\u0105 przechowywane w schemacie samej tabeli. Dlatego musimy poczeka\u0107 na zapytania do odczytu z tabeli, na przyk\u0142ad. <\/p>\n<p>Pojawia si\u0119 pytanie, czy mo\u017cna to zrobi\u0107 lepiej? Pewnie, \u017ce tak. Mo\u017cna zachowa\u0107 struktur\u0119 Enum nie w schemacie tabeli, ale w ZooKeeper. Mog\u0105 jednak wyst\u0105pi\u0107 problemy zwi\u0105zane z synchronizacj\u0105. Na przyk\u0142ad jedna replika otrzyma\u0142a dane, druga \u2014 nie, i je\u015bli ma stary Enum, to co\u015b si\u0119 zepsuje. (W ClickHouse prawie zako\u0144czyli\u015bmy wsp\u00f3\u0142bie\u017cne zapytania ALTER. Gdy je zako\u0144czymy ca\u0142kowicie, nie b\u0119dziemy musieli czeka\u0107 na zapytania do odczytu.)<\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/f5d2fdf14778f6afdd4acc8c204e163c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAby nie bawi\u0107 si\u0119 w ALTER Enum, mo\u017cna u\u017cywa\u0107 zewn\u0119trznych s\u0142ownik\u00f3w ClickHouse. Przypomn\u0119, \u017ce to struktura danych w formacie klucz-warto\u015b\u0107 wewn\u0105trz ClickHouse, za pomoc\u0105 kt\u00f3rej mo\u017cna pozyskiwa\u0107 dane z zewn\u0119trznych \u017ar\u00f3de\u0142, na przyk\u0142ad z tabel MySQL. <\/p>\n<p>W s\u0142owniku ClickHouse przechowujemy wiele r\u00f3\u017cnych ci\u0105g\u00f3w, a w tabeli \u2014 ich identyfikatory w postaci liczb. Je\u015bli potrzebujemy uzyska\u0107 ci\u0105g, wywo\u0142ujemy funkcj\u0119 dictGet i pracujemy z ni\u0105. Po tym nie musimy wykonywa\u0107 ALTER. Aby co\u015b doda\u0107 do Enum, wstawiamy to do tej samej tabeli MySQL. <\/p>\n<p>Ale pojawiaj\u0105 si\u0119 inne problemy. Po pierwsze, niewygodna sk\u0142adnia. Je\u015bli chcemy uzyska\u0107 ci\u0105g, musimy wywo\u0142a\u0107 dictGet. Po drugie, brak niekt\u00f3rych optymalizacji. Por\u00f3wnanie z sta\u0142ym ci\u0105giem dla s\u0142ownik\u00f3w nie jest r\u00f3wnie szybkie. <\/p>\n<p>Mog\u0105 tak\u017ce wyst\u0105pi\u0107 problemy z aktualizacj\u0105. Za\u0142\u00f3\u017cmy, \u017ce zapytali\u015bmy o ci\u0105g w s\u0142owniku podr\u0119cznym, ale ten nie zosta\u0142 do niego dodany. W takim przypadku musimy poczeka\u0107, a\u017c dane za\u0142aduj\u0105 si\u0119 z zewn\u0119trznego \u017ar\u00f3d\u0142a. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/534818ee523a243623a5cb2babe08040.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOg\u00f3lnym brakiem obu metod jest to, \u017ce przechowujemy wszystkie klucze w jednym miejscu i je synchronizujemy. Dlaczego wi\u0119c nie trzyma\u0107 s\u0142ownik\u00f3w lokalnie? Brak synchronizacji \u2014 brak problem\u00f3w. Mo\u017cna przechowywa\u0107 s\u0142ownik lokalnie na kawa\u0142ku dysku. To znaczy, \u017ce zrobili\u015bmy Insert, zapisali\u015bmy s\u0142ownik. Je\u015bli pracujemy z danymi w pami\u0119ci, mo\u017cemy zapisa\u0107 s\u0142ownik albo w bloku danych, albo w kawa\u0142ku kolumny, albo w jakim\u015b pami\u0119ci podr\u0119cznej, aby przyspieszy\u0107 obliczenia.<\/p>\n<h3>Kodowanie s\u0142ownik\u00f3w ci\u0105g\u00f3w <\/h3>\n<p>\nW ten spos\u00f3b przeszli\u015bmy do stworzenia nowego typu danych w ClickHouse \u2014 LowCardinality. To format przechowywania danych: jak s\u0105 zapisywane na dysku i jak s\u0105 odczytywane, jak s\u0105 reprezentowane w pami\u0119ci oraz schema ich przetwarzania. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/e25b2eb12ff158b89b7d2dbdfb8e2e5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNa slajdzie s\u0105 dwie kolumny. Po prawej stronie standardowo przechowywane s\u0105 wiersze, w typie String. Wida\u0107, \u017ce s\u0105 to jakie\u015b modele telefon\u00f3w kom\u00f3rkowych. Po lewej stronie znajduje si\u0119 dok\u0142adnie taka sama kolumna, tylko w typie LowCardinality. Sk\u0142ada si\u0119 ona ze s\u0142ownika z wieloma r\u00f3\u017cnymi wierszami (wiersze z kolumny po prawej) i listy pozycji (numer\u00f3w wierszy). <\/p>\n<p>Dzi\u0119ki tym dw\u00f3m strukturom mo\u017cna odtworzy\u0107 pierwotn\u0105 kolumn\u0119. Istnieje r\u00f3wnie\u017c odwrotny indeks \u2014 tabela haszuj\u0105ca, kt\u00f3ra pomaga znale\u017a\u0107 pozycj\u0119 w s\u0142owniku na podstawie wiersza. Jest potrzebna do przyspieszenia niekt\u00f3rych zapyta\u0144. Na przyk\u0142ad, je\u015bli chcemy por\u00f3wna\u0107, wyszuka\u0107 wiersz w naszej kolumnie lub je ze sob\u0105 po\u0142\u0105czy\u0107. <\/p>\n<p>LowCardinality \u2014 parametryczny typ danych. Mo\u017ce by\u0107 albo liczb\u0105, albo czym\u015b, co jest przechowywane jako liczba, albo ci\u0105giem znak\u00f3w, albo Nullable od nich. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/d52ef0c99617238442d4f71e43af48af.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCech\u0105 LowCardinality jest to, \u017ce mo\u017ce by\u0107 przechowywany dla niekt\u00f3rych funkcji. Na slajdzie wida\u0107 przyk\u0142ad zapytania. W pierwszej linijce stworzy\u0142em kolumn\u0119 typu LowCardinality od String, nazwa\u0142em j\u0105 S. Nast\u0119pnie zapyta\u0142em o jej nazw\u0119 \u2014 ClickHouse powiedzia\u0142, \u017ce to LowCardinality od String. Wszystko si\u0119 zgadza.<\/p>\n<p>Trzecia linijka jest prawie taka sama, tylko wywo\u0142ali\u015bmy funkcj\u0119 length. W ClickHouse funkcja length zwraca typ danych UInt64. Ale my mamy teraz LowCardinality od UInt64. O co w tym chodzi?<\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/a4a51a0f1ecd68f7fffd521ab786c8a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nW s\u0142owniku przechowywane by\u0142y nazwy telefon\u00f3w kom\u00f3rkowych, zastosowali\u015bmy funkcj\u0119 length. Teraz mamy podobny s\u0142ownik, sk\u0142adaj\u0105cy si\u0119 tylko z liczb \u2014 to d\u0142ugo\u015bci ci\u0105g\u00f3w. Kolumna z pozycjami si\u0119 nie zmieni\u0142a. W efekcie przetworzyli\u015bmy mniej danych, oszcz\u0119dzaj\u0105c czas zapytania. <\/p>\n<p>Mog\u0105 by\u0107 te\u017c inne optymalizacje, na przyk\u0142ad dodanie prostego cache. Przy obliczaniu warto\u015bci funkcji mo\u017cna zapami\u0119ta\u0107 j\u0105 i zbudowa\u0107 podobn\u0105 bez ponownego obliczania. <\/p>\n<p>Mo\u017ce by\u0107 te\u017c dokonana optymalizacja GROUP BY, poniewa\u017c nasza kolumna ze s\u0142ownikiem ju\u017c cz\u0119\u015bciowo zgrupowana \u2014 mo\u017cna szybciej oblicza\u0107 warto\u015b\u0107 funkcji haszuj\u0105cych i mniej wi\u0119cej znale\u017a\u0107 bucket, do kt\u00f3rego umie\u015bci\u0107 kolejny wiersz. Mo\u017cna tak\u017ce specjalizowa\u0107 niekt\u00f3re funkcje agreguj\u0105ce, na przyk\u0142ad uniq, poniewa\u017c do niej mo\u017cna przes\u0142a\u0107 tylko s\u0142ownik, a pozycje pozostawi\u0107 nietkni\u0119te \u2014 dzi\u0119ki temu wszystko b\u0119dzie dzia\u0142a\u0107 szybciej. Pierwsze dwie optymalizacje ju\u017c dodali\u015bmy do ClickHouse.<\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/943e0a8ae5a37cd47164246db3a67893.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA co, je\u015bli stworzymy kolumn\u0119 z naszym typem danych i wstawimy do niej wiele r\u00f3\u017cnych z\u0142ych wierszy? Czy nasza pami\u0119\u0107 si\u0119 nie przepe\u0142ni? Nie, w tym celu ClickHouse ma dwie specjalne ustawienia. Pierwsza to low_cardinality_max_dictionary_size. To maksymalny rozmiar s\u0142ownika, kt\u00f3ry mo\u017ce by\u0107 zapisany na dysku. Wstawianie odbywa si\u0119 w nast\u0119puj\u0105cy spos\u00f3b: gdy wstawiamy dane, przychodzi do nas strumie\u0144 wierszy, z kt\u00f3rych tworzymy du\u017c\u0105 wsp\u00f3ln\u0105 s\u0142owniczek. Je\u015bli s\u0142owniczek staje si\u0119 wi\u0119kszy ni\u017c warto\u015b\u0107 ustawienia, zapisujemy obecny s\u0142ownik na dysku, a pozosta\u0142e wiersze gdzie\u015b \u201eobok\u201d, obok indeks\u00f3w. W rezultacie nigdy nie przeliczymy du\u017cego s\u0142ownika i nie wyst\u0105pi\u0105 problemy z pami\u0119ci\u0105. <\/p>\n<p>Drugie ustawienie nazywa si\u0119 low_cardinality_use_single_dictionary_for_part. Wyobra\u017a sobie, \u017ce w poprzednim schemacie, kiedy wstawiali\u015bmy dane, nasz s\u0142ownik przepe\u0142ni\u0142 si\u0119, a my zapisali\u015bmy go na dysku. Pojawia si\u0119 pytanie, a dlaczego teraz nie tworzy\u0107 jeszcze jednego takiego samego s\u0142ownika? <\/p>\n<p>Kiedy on si\u0119 przepe\u0142ni, znowu zapiszemy go na dysku i zaczniemy tworzy\u0107 trzeci. To ustawienie domy\u015blnie wy\u0142\u0105cza tak\u0105 mo\u017cliwo\u015b\u0107. <\/p>\n<p>W rzeczywisto\u015bci wiele s\u0142ownik\u00f3w mo\u017ce by\u0107 przydatnych, je\u015bli chcemy wstawi\u0107 jak\u0105\u015b ilo\u015b\u0107 wierszy, ale przypadkowo wstawili\u015bmy \u201e\u015bmieci\u201d. Powiedzmy, \u017ce najpierw wstawili\u015bmy z\u0142e wiersze, a potem dobre. Wtedy s\u0142ownik podzieli si\u0119 na wiele ma\u0142ych s\u0142ownik\u00f3w. Cz\u0119\u015b\u0107 z nich b\u0119dzie zawiera\u0142a \u201e\u015bmieci\u201d, ale ostatnie b\u0119d\u0105 zawiera\u0142y dobre wiersze. I je\u015bli przeczytamy, powiedzmy, tylko ostatni\u0105 granul\u0119, to wszystko te\u017c b\u0119dzie dzia\u0142a\u0142o szybko. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/834ba3295ace98870334aa10a78e4781.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZanim zaczniemy m\u00f3wi\u0107 o zaletach LowCardinality, od razu powiem, \u017ce raczej nie osi\u0105gniemy zmniejszenia danych na dysku (chocia\u017c to mo\u017ce si\u0119 zdarzy\u0107), poniewa\u017c ClickHouse kompresuje dane. Domy\u015bln\u0105 opcj\u0105 jest LZ4. Mo\u017cliwe jest r\u00f3wnie\u017c kompresowanie za pomoc\u0105 ZSTD. Ale oba algorytmy ju\u017c implementuj\u0105 kompresj\u0119 s\u0142ownikow\u0105, wi\u0119c nasz zewn\u0119trzny s\u0142ownik ClickHouse nie pomo\u017ce zbytnio. <\/p>\n<p>Aby nie by\u0107 go\u0142os\u0142ownym, wzi\u0105\u0142em kilka danych z metryki \u2014 String, LowCardinality(String) i Enum \u2014 i zapisa\u0142em je w r\u00f3\u017cnych typach danych. Powsta\u0142y trzy kolumny, w kt\u00f3rych zapisano miliard wierszy. W pierwszej kolumnie, CodePage, jest tylko 62 warto\u015bci. Wida\u0107, \u017ce w przypadku LowCardinality(String) zcompressowali\u015bmy je lepiej. String jest nieco gorszy, ale to prawdopodobnie z powodu kr\u00f3tkich ci\u0105g\u00f3w, kt\u00f3rych d\u0142ugo\u015bci przechowujemy, a zajmuj\u0105 one du\u017co miejsca i s\u0142abo si\u0119 kompresuj\u0105. <\/p>\n<p>Je\u015bli we\u017amiemy PhoneModel, jest ich 48 tysi\u0119cy \u2014 ju\u017c wi\u0119cej, a r\u00f3\u017cnice mi\u0119dzy String i LowCardinality(String) s\u0105 niemal niezauwa\u017calne. W przypadku URL r\u00f3wnie\u017c zaoszcz\u0119dzili\u015bmy tylko 2 GB \u2014 my\u015bl\u0119, \u017ce nie warto na tym polega\u0107. <\/p>\n<h3>Ocena wydajno\u015bci pracy<\/h3>\n<p>\n<img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" 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 ze slajdu<\/a><\/noindex><\/b><\/p>\n<p>Teraz ocenimy wydajno\u015b\u0107 pracy. Aby j\u0105 oceni\u0107, u\u017cy\u0142em zbioru danych z opisem przejazd\u00f3w taks\u00f3wek w Nowym Jorku. On <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/toddwschneider\/nyc-taxi-data\">dost\u0119pne<\/a><\/noindex> jest dost\u0119pny na GitHubie. Zawiera nieco ponad miliard przejazd\u00f3w. Zawiera lokalizacj\u0119, czas rozpocz\u0119cia i zako\u0144czenia przejazdu, spos\u00f3b p\u0142atno\u015bci, liczb\u0119 pasa\u017cer\u00f3w oraz rodzaj taks\u00f3wki \u2014 zielona, \u017c\u00f3\u0142ta czy Uber. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/0901669dec01b0f956d6976e3aa8b741.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPierwsze zapytanie wykona\u0142em do\u015b\u0107 prosto \u2014 zapyta\u0142em, gdzie najcz\u0119\u015bciej zamawiano taks\u00f3wki. W tym celu trzeba wzi\u0105\u0107 lokalizacj\u0119, z kt\u00f3rej zamawiano, zrobi\u0107 na niej GROUP BY i policzy\u0107 funkcj\u0119 count. Oto co generuje ClickHouse. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/50983341e20bcbc1b5adbaed35f8624d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAby zmierzy\u0107 pr\u0119dko\u015b\u0107 przetwarzania zapytania, stworzy\u0142em trzy tabele z danymi, ale u\u017cy\u0142em dla naszej lokalizacji startowej trzech r\u00f3\u017cnych typ\u00f3w danych \u2014 String, LowCardinality i Enum. LowCardinality i Enum by\u0142y pi\u0119\u0107 razy szybsze od String. Enum jest szybszy, poniewa\u017c operuje na liczbach. LowCardinality \u2014 poniewa\u017c wdro\u017cono optymalizacj\u0119 GROUP BY. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/e2ce4f2127d8728287488c85c92085fc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJeszcze bardziej skomplikujmy zapytanie \u2014 zapytajmy, gdzie znajduje si\u0119 najpopularniejszy park w Nowym Jorku. Ponownie b\u0119dziemy to mierzy\u0107 wed\u0142ug tego, gdzie najcz\u0119\u015bciej zamawiano taks\u00f3wki, ale tym razem przefiltrujemy tylko te lokalizacje, kt\u00f3re zawieraj\u0105 s\u0142owo \u201epark\u201d. Dodamy r\u00f3wnie\u017c funkcj\u0119 like. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/7cf6fd64751f3ae578581caddde17aaf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPatrzymy na czas \u2014 widzimy, \u017ce Enum nagle zaczyna spowalnia\u0107. Dzia\u0142a nawet wolniej ni\u017c standardowy typ danych String. Dzieje si\u0119 tak, poniewa\u017c funkcja like wcale nie jest zoptymalizowana dla Enum. Musimy konwertowa\u0107 nasze ci\u0105gi z Enum na zwyk\u0142e ci\u0105gi \u2014 wykonujemy wi\u0119cej pracy. LowCardinality(String) r\u00f3wnie\u017c nie jest zoptymalizowany domy\u015blnie, ale w tym przypadku like dzia\u0142a na s\u0142owniku, dlatego zapytanie przyspiesza w por\u00f3wnaniu do String. <\/p>\n<p>Pracuj\u0105c z Enum, napotykamy na wi\u0119kszy problem. Je\u015bli chcemy go zoptymalizowa\u0107, musimy to zrobi\u0107 w ka\u017cdym miejscu w kodzie. Za\u0142\u00f3\u017cmy, \u017ce napisali\u015bmy now\u0105 funkcj\u0119 \u2014 konieczne b\u0119dzie wymy\u015blenie optymalizacji dla Enum. W przypadku LowCardinality wszystko jest zoptymalizowane domy\u015blnie.<\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/459243eb5b3dd993393d0184b224ea09.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrzyjrzyjmy si\u0119 ostatniemu zapytaniu, bardziej sztucznemu. Po prostu policzymy funkcj\u0119 haszuj\u0105c\u0105 naszej lokalizacji. Funkcja haszuj\u0105ca to do\u015b\u0107 wolne zapytanie, trwa d\u0142ugo, wi\u0119c wszystko spowolni si\u0119 oko\u0142o trzy razy.<\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/a5f49c22748971646ec358eb52d3feda.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLowCardinality nadal dzia\u0142a szybciej, cho\u0107 nie ma tu filtrowania. Dzieje si\u0119 tak, poniewa\u017c nasze funkcje dzia\u0142aj\u0105 tylko na s\u0142owniku. Funkcja obliczania hasza ma jeden argument \u2014 mo\u017ce przetwarza\u0107 mniej danych i r\u00f3wnie\u017c mo\u017ce zwr\u00f3ci\u0107 LowCardinality. <\/p>\n<p><img decoding=\"async\" alt=\"Optymalizacja ci\u0105g\u00f3w w ClickHouse. Referat Yandexu\" src=\"\/wp-content\/uploads\/2020\/03\/7842b7eb2debb4a4b1d4cbc3488deb32.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNasz globalny plan polega na osi\u0105gni\u0119ciu pr\u0119dko\u015bci dzia\u0142ania nie ni\u017cszej ni\u017c String w ka\u017cdych okoliczno\u015bciach i utrzymaniu przyspieszenia. A mo\u017ce kiedy\u015b zast\u0105pimy String LowCardinality, zaktualizujesz ClickHouse, a wszystko b\u0119dzie dzia\u0142a\u0107 troch\u0119 szybciej.<br \/>\n<br \/>\u0179r\u00f3d\u0142o: <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.1.1 - 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\/pl\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\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\/pl\/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\udd47Optymalizacja wierszy w ClickHouse. Prezentacja Yandexu | ProHoster","description":"Analityczna baza danych ClickHouse przetwarza wiele r\u00f3\u017cnych wierszy, konsumuj\u0105c zasoby. Aby przyspieszy\u0107 dzia\u0142anie systemu, ci\u0105gle dodawane s\u0105 nowe optymalizacje.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/optimizacziya-strok-v-clickhouse-doklad-yandeksa","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","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\/pl\/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\/pl\/wp-json\/wp\/v2\/posts\/74737","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=74737"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/74737\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/74738"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=74737"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=74737"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=74737"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}