ClickHouse kļūda "Too many partitions for single INSERT block" nozīmē, ka vienā INSERT blokā bija rindas vairāk nekā 100 dažādām partīcijām, tāpēc ClickHouse atteicās to ierakstīt. Parasti tā parādās divās situācijās: kāds ielādē mēnešu vai gadu vēsturi tabulā, kas particionēta pa dienām, vai tabulas PARTITION BY ir pārāk sīka. Pirmajā gadījumā problēmu dažās minūtēs atrisina ielāde pa daļām. Otrajā kļūda ir brīdinājums par shēmas problēmu, kas jums tik un tā vēlāk kaitēs.
Ziņojums ir neparasti garš, jo ClickHouse to izmanto, lai paskaidrotu particionēšanu:
Code: 252. DB::Exception: Too many partitions for single INSERT block (more than 100).
The limit is controlled by 'max_partitions_per_insert_block' setting. Large number of
partitions is a common misconception. It will lead to severe negative performance impact,
including slow server startup, slow INSERT queries and slow SELECT queries. Recommended
total number of partitions for a table is under 1000..10000. ... (TOO_MANY_PARTS)
Ko limits skaita
Pārbaude atrodas failā MergeTreeDataWriter.cpp, kur ClickHouse pirms ierakstīšanas sadala ienākošo rindu bloku pēc partīcijas atslēgas. Katrai jaunai partīcijas vērtībai, ko tas atrod blokā, tas salīdzina līdzšinējo skaitu ar max_partitions_per_insert_block. Kad ar noklusējuma iestatījumu blokā parādās 101. atšķirīgā partīcija, šī bloka ievietošana neizdodas ar kodu 252 (TOO_MANY_PARTS, tas pats kods, kas kļūdai "Too many parts").
Praksē svarīgas trīs detaļas:
- Noklusējums ir 100, un 0 nozīmē bez limita. Limits pastāv kopš versijas 19.5, kā redzams iestatījuma vēsturē failā Settings.cpp.
- Tas skaita partīcijas blokā, nevis tabulā. Tabulai var būt 3000 partīciju, un tā visu dienu pieņems ievietošanu, ja vien katrs bloks skar mazāk nekā 101 no tām. Liels
INSERT ... SELECTtiek apstrādāts kā vairāki bloki, un katrs bloks tiek pārbaudīts atsevišķi. - Katra partīcija blokā kļūst par atsevišķu daļu (part). Particionēšanas labās prakses lapa to apraksta tieši: viena jauna daļa uz ievietošanu vietā ClickHouse izveido vienu jaunu daļu katrai unikālajai partīcijas atslēgas vērtībai ievietotajās rindās. Bloks, kas izkliedēts pa 500 partīcijām, nozīmē 500 mazas daļas uzreiz, un tas ir ceļš uz "Too many parts".
Atrodiet partīcijas atslēgu un partīciju skaitu
Sāciet ar to, pēc kā tabula ir particionēta. Tabulas system.tables kolonna partition_key parāda izteiksmi:
SELECT database, name, partition_key, sorting_key
FROM system.tables
WHERE engine LIKE '%MergeTree%' AND partition_key != ''
ORDER BY database, name;
Tad paskatieties, cik partīciju tabulām jau ir:
SELECT database, table,
uniqExact(partition) AS partitions,
count() AS active_parts
FROM system.parts
WHERE active
GROUP BY database, table
ORDER BY partitions DESC
LIMIT 20;
Ja avota tabulai ir materializētie skati, pārbaudiet arī to mērķa tabulas. Skats raksta savus blokus savā tabulā, un tur skaitās tieši tās tabulas partīcijas atslēga.
Pirms partijas ielādes ar vienu vaicājumu var uzzināt, vai tā ietilps limitā:
-- use the exact expression from partition_key
SELECT uniqExact(toYYYYMMDD(event_time)) AS partitions_in_batch
FROM staging.events_import;
1. gadījums: atslēga ir laba, partija ir par platu
Tabula, kas particionēta pa dienām (toDate vai toYYYYMMDD), ir izplatīta žurnāliem un notikumiem. Ikdienas ievietošana skar vienu vai divas partīcijas, un limitu neviens nepamana, līdz kāds vienā reizē ielādē gada vēsturi. Gads ir 365 dienu partīcijas vienā vaicājumā, tāpēc bloki neizdodas.
Tīrs risinājums ir ielādēt daļās, kas paliek zem limita:
-- viens mēnesis katrā INSERT: ne vairāk kā ~31 dienas partīcija blokā
INSERT INTO analytics.events
SELECT * FROM staging.events_import
WHERE toYYYYMM(event_time) = 202401;
-- tad 202402, 202403, ... ar skriptu, pēc katra pārbaudot rindu skaitu
Katrs mēnesis dod ne vairāk kā aptuveni 31 daļu blokā, tāpēc apvienošana (merge) paliek mierīga, un neizdevušos daļu ir viegli atkārtot. Viens brīdinājums: nepieņemiet, ka neizdevies liels INSERT neko neierakstīja. ClickHouse glosārijs saka, ka ievietošana ir atomāra tikai tad, ja tās rindas ierakstītas kā viens bloks, un ievietošana, kas aptver vairākas partīcijas, ir atomāra atsevišķi katrai partīcijai. Liels INSERT, kas neizdevās vēlākā blokā, var jau būt ierakstījis iepriekšējos. Pirms jebko palaižat atkārtoti, salīdziniet rindu skaitu, citādi dabūsiet dublikātus.
Vienreizējai vēsturisko datu ielādei limitu var palielināt arī tikai savai sesijai:
-- clickhouse-client sesija tikai vienreizējai vēsturisko datu ielādei
SET max_partitions_per_insert_block = 1000;
INSERT INTO analytics.events SELECT * FROM staging.events_import;
Tas ir pieņemami, ja tabulas partīciju skaits ir saprātīgs un jūs precīzi zināt, cik partīciju partija aptver. Pēc tam gaidiet mazu daļu vilni un noslogotu apvienošanas rindu. Neielieciet palielinātu vērtību noklusējuma profilā tikai tāpēc, lai pazustu datu plūsmas kļūda.
ClickHouse 23.8 LTS un jaunākās versijās ir arī throw_on_max_partitions_per_insert_block (noklusējums true). Ja to iestata uz false, ievietošana neizdodas vietā servera žurnālā tiek ierakstīts brīdinājums ar lietotāju, vaicājuma ID un partīciju skaitu. Iestatījumu dokumentācija to iesaka, lai pārbaudītu ietekmi uz lietotājiem pirms max_partitions_per_insert_block maiņas. Tas ir mērīšanas rīks, nevis risinājums.
2. gadījums: partīcijas atslēga ir pārāk sīka
Ja limitu sasniedz parasta ikdienas ievietošana, problēma ir shēmā. Tipiski piemēri ir PARTITION BY customer_id, PARTITION BY (tenant, toDate(ts)), particionēšana pa stundām vai pēc kāda ID, kas vienkārši izskatījās pēc dabiska grupējuma.
ClickHouse dokumentācija par to runā tieši. Pielāgotās partīcijas atslēgas lapa saka, ka vairumā gadījumu partīcijas atslēga nav vajadzīga, un lielākajā daļā pārējo nav vajadzīgs nekas sīkāks par mēnesi, bet dienas partīcijas ir izplatītas novērojamības (observability) datiem. Tā arī saka, ka nevajag partīcijas veidot pēc klientu identifikatoriem vai nosaukumiem, bet identifikatoru likt pirmo ORDER BY. Labās prakses ceļvedis particionēšanu sauc galvenokārt par datu pārvaldības paņēmienu, nevis vaicājumu optimizācijas rīku. Pats kļūdas ziņojums saka to pašu: diapazona vaicājumus ātrus padara kārtošanas atslēga, bet partīcijas ir domātas tādām darbībām kā DROP PARTITION un datu glabāšanas termiņiem.
Partīcijas atslēga ir daļa no tabulas definīcijas, un praksē tās maiņa nozīmē jaunas tabulas izveidi un datu pārvietošanu:
CREATE TABLE analytics.events_new
(
event_time DateTime,
customer_id UInt64,
event_type LowCardinality(String),
payload String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time) -- bija: PARTITION BY (customer_id, toDate(event_time))
ORDER BY (customer_id, event_time);
-- kopējiet pa mēnešiem (tā pati ideja kā sadalītajā ielādē augstāk)
INSERT INTO analytics.events_new
SELECT * FROM analytics.events WHERE toYYYYMM(event_time) = 202401;
-- salīdziniet skaitus, tad atomāri samainiet nosaukumus (Atomic datubāzes dzinējs)
EXCHANGE TABLES analytics.events AND analytics.events_new;
- Kopējiet pa mēnešiem, lai pati kopēšana nesasniegtu limitu.
- Izlemiet, kas notiek ar ierakstiem, kas pienāk kopēšanas laikā. Vai nu apturiet tos, rakstiet abās tabulās, vai tieši pirms samaiņas nokopējiet pēdējo daļu vēlreiz.
- EXCHANGE TABLES atomāri samaina nosaukumus. Tas darbojas tikai ar Atomic un Shared datubāzes dzinējiem; ar citu dzinēju ieplānojiet īsu rakstīšanas pauzi un izmantojiet
RENAME. - Paturiet veco tabulu, līdz atskaites un rindu skaiti sakrīt, tad dzēsiet to.
Replicētā klasterī tie paši soļi notiek ar ON CLUSTER un replicētiem dzinējiem, un kopēšana prasa reālu laiku un diska vietu. Kamēr pastāv abas kopijas, rēķinieties, ka vajadzēs brīvu vietu tabulas izmēra apmērā. Ja jūs vispār tikai pārceļat lielu mantotu datu kopu uz ClickHouse, partīcijas atslēgu vērts izlemt pirms pirmās ielādes; par to rakstījām mūsu ceļvedī par mantoto datu pārcelšanu uz ClickHouse datu noliktavu.
Kā novērst atkārtošanos
- Pārskatiet
PARTITION BY, kad tabula tiek izveidota. Pajautājiet, ko jūs dzēsīsiet vai pārvietosiet kā vienu vienību. Ja atbilde ir "vecos mēnešus", particionējiet pa mēnešiem. - Vēsturisko datu ielādi pēc noklusējuma rakstiet kā sadalītus darbus, vienu partīciju diapazonu katrā vaicājumā, ar rindu skaita pārbaudēm.
- Sekojiet partīciju skaitam katrā tabulā ar iepriekš minēto
system.partsvaicājumu. Pielāgotās particionēšanas lapa brīdina neveidot vairāk par aptuveni tūkstoš partīcijām; pats kļūdas ziņojums kā robežu kopskaitam min 1000..10000. - Meklējiet kodu 252 vaicājumu žurnālā, lai redzētu, kuri lietotāji un darbi sasniedz limitu:
SELECT event_time, user, query_id, left(query, 120) AS q
FROM system.query_log
WHERE exception_code = 252
AND exception LIKE 'Too many partitions%'
AND event_time BETWEEN now() - INTERVAL 7 DAY AND now()
ORDER BY event_time DESC
LIMIT 50;
Galvenās atziņas
- Kļūda nozīmē, ka viens INSERT bloks skāra vairāk nekā
max_partitions_per_insert_blockpartīcijas (noklusējums 100). Pārbaude notiek katram blokam, nevis tabulai. - Katra partīcija blokā kļūst par atsevišķu jaunu daļu, tāpēc ClickHouse šeit jūs aizsargā.
- Vēsturisko datu ielādei ielādējiet pa vienam partīciju diapazonam. Limitu palieliniet tikai vienreizējai sesijai un zināmam partīciju skaitam.
- Ja limitu sasniedz parasta ievietošana, partīcijas atslēga ir pārāk sīka. Pārbūvējiet tabulu ar rupjāku atslēgu, parasti pa mēnešiem, un identifikatoru pārvietojiet uz
ORDER BY. - Neizdevies vairāku bloku INSERT var būt daļēji ierakstīts. Pirms atkārtošanas pārbaudiet rindu skaitu.