[{"data":1,"prerenderedAt":2299},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fde\u002Fdata\u002Fcohort-table-architecture-retention-at-scale":11},{"i18nKey":4,"paths":5},"data-007-2026-06",{"de":6,"es":7,"fr":8,"it":9,"ru":10},"\u002Fde\u002Fdata\u002Fcohort-table-architecture-retention-at-scale","\u002Fes\u002Fdata\u002Farquitectura-tabla-cohortes","\u002Ffr\u002Fdata\u002Fcohort-table-architecture-production-scaling","\u002Fit\u002Fdata\u002Farchitettura-tabella-cohort-retention-production","\u002Fru\u002Fdata\u002Fcohort-tablitsa-arkhitektura-masshtabirovanie-analiza-uderzhaniia-v-produkcii",{"_path":6,"_dir":12,"_draft":13,"_partial":13,"_locale":14,"title":15,"description":16,"publishedAt":17,"modifiedAt":17,"category":12,"i18nKey":4,"tags":18,"readingTime":24,"author":25,"body":26,"_type":2293,"_id":2294,"_source":2295,"_file":2296,"_stem":2297,"_extension":2298},"data",false,"","Cohort-Tabellenarchitektur: Retention-Analyse produktionsgerecht skalieren","Materialisierte Views, Partitionierung und Query-Kostenoptimierung für Cohort-Analysen auf 10M+ täglich ereignissen mit Millisekunden-Latenz.","2026-06-26",[19,20,21,22,23],"cohort-analysis","bigquery-optimization","materialized-views","retention-engineering","data-partitioning",9,"Roibase",{"type":27,"children":28,"toc":2280},"root",[29,37,44,49,414,419,458,463,469,482,867,879,899,906,939,951,957,967,1506,1532,1538,1551,1570,1576,1581,1599,1609,1619,1625,1637,1690,1940,1959,1965,1970,1978,2003,2008,2080,2101,2107,2112,2264,2269,2274],{"type":30,"tag":31,"props":32,"children":33},"element","p",{},[34],{"type":35,"value":36},"text","Wenn Ihr Retention-Dashboard bei jedem Laden 45 Sekunden Wartezeit verursacht, liegt das Problem nicht in Ihrer Cohort-Definition — es liegt in der Tabellenarchitektur. Die Berechnung von D1-, D7- und D30-Retention über 10 Millionen täglich ereignisse in BigQuery kann 2TB Datenlesen und 10 Dollar Kosten bedeuten. Oder mit der richtigen Partitionierungsstrategie, inkrementellen materialisierten Views und Pre-Aggregation: 200MB Scan und 50 Millisekunden. Der Unterschied ist die Grenze zwischen produktionsreif und „funktioniert, aber niemand kann es verwenden\".",{"type":30,"tag":38,"props":39,"children":41},"h2",{"id":40},"warum-cohort-analysen-in-production-scheitern",[42],{"type":35,"value":43},"Warum Cohort-Analysen in Production scheitern",{"type":30,"tag":31,"props":45,"children":46},{},[47],{"type":35,"value":48},"Retention-Berechnung ist von Natur aus ein Full-Scan-Prozess. Für jeden Benutzer das erste Ereignisdatum finden, die Aktivität in den folgenden Tagen zählen, nach Cohort gruppieren, Prozentsätze berechnen. Der naive SQL-Ansatz sieht so aus:",{"type":30,"tag":50,"props":51,"children":55},"pre",{"className":52,"code":53,"language":54,"meta":14,"style":14},"language-sql shiki shiki-themes github-dark","WITH first_events AS (\n  SELECT user_id, MIN(event_date) AS cohort_date\n  FROM events\n  GROUP BY user_id\n),\nretention_raw AS (\n  SELECT \n    f.cohort_date,\n    DATE_DIFF(e.event_date, f.cohort_date, DAY) AS day_offset,\n    COUNT(DISTINCT e.user_id) AS active_users\n  FROM events e\n  JOIN first_events f USING(user_id)\n  GROUP BY 1, 2\n)\nSELECT * FROM retention_raw;\n","sql",[56],{"type":30,"tag":57,"props":58,"children":59},"code",{"__ignoreMap":14},[60,88,122,136,150,159,176,189,213,276,322,335,359,381,390],{"type":30,"tag":61,"props":62,"children":65},"span",{"class":63,"line":64},"line",1,[66,72,78,83],{"type":30,"tag":61,"props":67,"children":69},{"style":68},"--shiki-default:#F97583",[70],{"type":35,"value":71},"WITH",{"type":30,"tag":61,"props":73,"children":75},{"style":74},"--shiki-default:#E1E4E8",[76],{"type":35,"value":77}," first_events ",{"type":30,"tag":61,"props":79,"children":80},{"style":68},[81],{"type":35,"value":82},"AS",{"type":30,"tag":61,"props":84,"children":85},{"style":74},[86],{"type":35,"value":87}," (\n",{"type":30,"tag":61,"props":89,"children":91},{"class":63,"line":90},2,[92,97,102,108,113,117],{"type":30,"tag":61,"props":93,"children":94},{"style":68},[95],{"type":35,"value":96},"  SELECT",{"type":30,"tag":61,"props":98,"children":99},{"style":74},[100],{"type":35,"value":101}," user_id, ",{"type":30,"tag":61,"props":103,"children":105},{"style":104},"--shiki-default:#79B8FF",[106],{"type":35,"value":107},"MIN",{"type":30,"tag":61,"props":109,"children":110},{"style":74},[111],{"type":35,"value":112},"(event_date) ",{"type":30,"tag":61,"props":114,"children":115},{"style":68},[116],{"type":35,"value":82},{"type":30,"tag":61,"props":118,"children":119},{"style":74},[120],{"type":35,"value":121}," cohort_date\n",{"type":30,"tag":61,"props":123,"children":125},{"class":63,"line":124},3,[126,131],{"type":30,"tag":61,"props":127,"children":128},{"style":68},[129],{"type":35,"value":130},"  FROM",{"type":30,"tag":61,"props":132,"children":133},{"style":74},[134],{"type":35,"value":135}," events\n",{"type":30,"tag":61,"props":137,"children":139},{"class":63,"line":138},4,[140,145],{"type":30,"tag":61,"props":141,"children":142},{"style":68},[143],{"type":35,"value":144},"  GROUP BY",{"type":30,"tag":61,"props":146,"children":147},{"style":74},[148],{"type":35,"value":149}," user_id\n",{"type":30,"tag":61,"props":151,"children":153},{"class":63,"line":152},5,[154],{"type":30,"tag":61,"props":155,"children":156},{"style":74},[157],{"type":35,"value":158},"),\n",{"type":30,"tag":61,"props":160,"children":162},{"class":63,"line":161},6,[163,168,172],{"type":30,"tag":61,"props":164,"children":165},{"style":74},[166],{"type":35,"value":167},"retention_raw ",{"type":30,"tag":61,"props":169,"children":170},{"style":68},[171],{"type":35,"value":82},{"type":30,"tag":61,"props":173,"children":174},{"style":74},[175],{"type":35,"value":87},{"type":30,"tag":61,"props":177,"children":179},{"class":63,"line":178},7,[180,184],{"type":30,"tag":61,"props":181,"children":182},{"style":68},[183],{"type":35,"value":96},{"type":30,"tag":61,"props":185,"children":186},{"style":74},[187],{"type":35,"value":188}," \n",{"type":30,"tag":61,"props":190,"children":192},{"class":63,"line":191},8,[193,198,203,208],{"type":30,"tag":61,"props":194,"children":195},{"style":104},[196],{"type":35,"value":197},"    f",{"type":30,"tag":61,"props":199,"children":200},{"style":74},[201],{"type":35,"value":202},".",{"type":30,"tag":61,"props":204,"children":205},{"style":104},[206],{"type":35,"value":207},"cohort_date",{"type":30,"tag":61,"props":209,"children":210},{"style":74},[211],{"type":35,"value":212},",\n",{"type":30,"tag":61,"props":214,"children":215},{"class":63,"line":24},[216,221,226,230,235,240,245,249,253,257,262,267,271],{"type":30,"tag":61,"props":217,"children":218},{"style":74},[219],{"type":35,"value":220},"    DATE_DIFF(",{"type":30,"tag":61,"props":222,"children":223},{"style":104},[224],{"type":35,"value":225},"e",{"type":30,"tag":61,"props":227,"children":228},{"style":74},[229],{"type":35,"value":202},{"type":30,"tag":61,"props":231,"children":232},{"style":104},[233],{"type":35,"value":234},"event_date",{"type":30,"tag":61,"props":236,"children":237},{"style":74},[238],{"type":35,"value":239},", ",{"type":30,"tag":61,"props":241,"children":242},{"style":104},[243],{"type":35,"value":244},"f",{"type":30,"tag":61,"props":246,"children":247},{"style":74},[248],{"type":35,"value":202},{"type":30,"tag":61,"props":250,"children":251},{"style":104},[252],{"type":35,"value":207},{"type":30,"tag":61,"props":254,"children":255},{"style":74},[256],{"type":35,"value":239},{"type":30,"tag":61,"props":258,"children":259},{"style":68},[260],{"type":35,"value":261},"DAY",{"type":30,"tag":61,"props":263,"children":264},{"style":74},[265],{"type":35,"value":266},") ",{"type":30,"tag":61,"props":268,"children":269},{"style":68},[270],{"type":35,"value":82},{"type":30,"tag":61,"props":272,"children":273},{"style":74},[274],{"type":35,"value":275}," day_offset,\n",{"type":30,"tag":61,"props":277,"children":279},{"class":63,"line":278},10,[280,285,290,295,300,304,309,313,317],{"type":30,"tag":61,"props":281,"children":282},{"style":104},[283],{"type":35,"value":284},"    COUNT",{"type":30,"tag":61,"props":286,"children":287},{"style":74},[288],{"type":35,"value":289},"(",{"type":30,"tag":61,"props":291,"children":292},{"style":68},[293],{"type":35,"value":294},"DISTINCT",{"type":30,"tag":61,"props":296,"children":297},{"style":104},[298],{"type":35,"value":299}," e",{"type":30,"tag":61,"props":301,"children":302},{"style":74},[303],{"type":35,"value":202},{"type":30,"tag":61,"props":305,"children":306},{"style":104},[307],{"type":35,"value":308},"user_id",{"type":30,"tag":61,"props":310,"children":311},{"style":74},[312],{"type":35,"value":266},{"type":30,"tag":61,"props":314,"children":315},{"style":68},[316],{"type":35,"value":82},{"type":30,"tag":61,"props":318,"children":319},{"style":74},[320],{"type":35,"value":321}," active_users\n",{"type":30,"tag":61,"props":323,"children":325},{"class":63,"line":324},11,[326,330],{"type":30,"tag":61,"props":327,"children":328},{"style":68},[329],{"type":35,"value":130},{"type":30,"tag":61,"props":331,"children":332},{"style":74},[333],{"type":35,"value":334}," events e\n",{"type":30,"tag":61,"props":336,"children":338},{"class":63,"line":337},12,[339,344,349,354],{"type":30,"tag":61,"props":340,"children":341},{"style":68},[342],{"type":35,"value":343},"  JOIN",{"type":30,"tag":61,"props":345,"children":346},{"style":74},[347],{"type":35,"value":348}," first_events f ",{"type":30,"tag":61,"props":350,"children":351},{"style":68},[352],{"type":35,"value":353},"USING",{"type":30,"tag":61,"props":355,"children":356},{"style":74},[357],{"type":35,"value":358},"(user_id)\n",{"type":30,"tag":61,"props":360,"children":362},{"class":63,"line":361},13,[363,367,372,376],{"type":30,"tag":61,"props":364,"children":365},{"style":68},[366],{"type":35,"value":144},{"type":30,"tag":61,"props":368,"children":369},{"style":104},[370],{"type":35,"value":371}," 1",{"type":30,"tag":61,"props":373,"children":374},{"style":74},[375],{"type":35,"value":239},{"type":30,"tag":61,"props":377,"children":378},{"style":104},[379],{"type":35,"value":380},"2\n",{"type":30,"tag":61,"props":382,"children":384},{"class":63,"line":383},14,[385],{"type":30,"tag":61,"props":386,"children":387},{"style":74},[388],{"type":35,"value":389},")\n",{"type":30,"tag":61,"props":391,"children":393},{"class":63,"line":392},15,[394,399,404,409],{"type":30,"tag":61,"props":395,"children":396},{"style":68},[397],{"type":35,"value":398},"SELECT",{"type":30,"tag":61,"props":400,"children":401},{"style":68},[402],{"type":35,"value":403}," *",{"type":30,"tag":61,"props":405,"children":406},{"style":68},[407],{"type":35,"value":408}," FROM",{"type":30,"tag":61,"props":410,"children":411},{"style":74},[412],{"type":35,"value":413}," retention_raw;\n",{"type":30,"tag":31,"props":415,"children":416},{},[417],{"type":35,"value":418},"Diese Query liest die events-Tabelle jedes Mal komplett. 500 Tage Daten × 10M tägliche ereignisse = 5 Milliarden Zeilen. Die Slot-Auslastung in BigQuery explodiert, das Dashboard braucht 40 Sekunden, BI-Tools laufen in Timeout. Das Problem konzentriert sich auf drei Punkte:",{"type":30,"tag":31,"props":420,"children":421},{},[422,428,430,435,437,441,446,448,451,456],{"type":30,"tag":423,"props":424,"children":425},"strong",{},[426],{"type":35,"value":427},"1. Full-Table-Scan:",{"type":35,"value":429}," Keine Partition-Pruning, da der ",{"type":30,"tag":57,"props":431,"children":433},{"className":432},[],[434],{"type":35,"value":308},{"type":35,"value":436},"-JOIN die Partition-Grenze durchbricht.",{"type":30,"tag":438,"props":439,"children":440},"br",{},[],{"type":30,"tag":423,"props":442,"children":443},{},[444],{"type":35,"value":445},"2. Wiederholte Berechnung:",{"type":35,"value":447}," Das Cohort-Datum ist bereits bekannt, wird aber bei jeder Query neu berechnet.",{"type":30,"tag":438,"props":449,"children":450},{},[],{"type":30,"tag":423,"props":452,"children":453},{},[454],{"type":35,"value":455},"3. Aggregations-Overhead:",{"type":35,"value":457}," 5 Milliarden Zeilen werden auf 500 Cohorts × 90 Tage = 45.000 Zeilen reduziert — Compute-zu-Output-Verhältnis 100.000:1.",{"type":30,"tag":31,"props":459,"children":460},{},[461],{"type":35,"value":462},"In Production ist dieser Ansatz nicht haltbar. Die Lösung: Tabellenarchitektur neu gestalten.",{"type":30,"tag":38,"props":464,"children":466},{"id":465},"materialisierte-cohort-basis-der-erste-schritt-zu-inkrementellem-snapshot",[467],{"type":35,"value":468},"Materialisierte Cohort-Basis: Der erste Schritt zu inkrementellem Snapshot",{"type":30,"tag":31,"props":470,"children":471},{},[472,474,480],{"type":35,"value":473},"Der teuerste Teil der Cohort-Analyse ist die ",{"type":30,"tag":57,"props":475,"children":477},{"className":476},[],[478],{"type":35,"value":479},"MIN(event_date)",{"type":35,"value":481},"-Berechnung. Berechnen Sie dies einmal, schreiben Sie das Ergebnis in eine Snapshot-Tabelle, und fügen Sie täglich nur neue Benutzer hinzu. In BigQuery verwenden wir statt materialisierter Views ein dbt incremental model:",{"type":30,"tag":50,"props":483,"children":485},{"className":52,"code":484,"language":54,"meta":14,"style":14},"-- models\u002Fcohorts\u002Fuser_cohort_base.sql\n{{ config(\n  materialized='incremental',\n  unique_key='user_id',\n  partition_by={'field': 'cohort_date', 'data_type': 'date'},\n  cluster_by=['cohort_date', 'user_id']\n) }}\n\nSELECT\n  user_id,\n  MIN(event_date) AS cohort_date,\n  COUNT(*) AS first_day_events\nFROM {{ source('raw', 'events') }}\n{% if is_incremental() %}\nWHERE event_date >= (SELECT MAX(cohort_date) FROM {{ this }})\n  AND user_id NOT IN (SELECT user_id FROM {{ this }})\n{% endif %}\nGROUP BY user_id\n",[486],{"type":30,"tag":57,"props":487,"children":488},{"__ignoreMap":14},[489,498,506,529,550,605,622,630,639,647,655,676,706,737,755,801,845,854],{"type":30,"tag":61,"props":490,"children":491},{"class":63,"line":64},[492],{"type":30,"tag":61,"props":493,"children":495},{"style":494},"--shiki-default:#6A737D",[496],{"type":35,"value":497},"-- models\u002Fcohorts\u002Fuser_cohort_base.sql\n",{"type":30,"tag":61,"props":499,"children":500},{"class":63,"line":90},[501],{"type":30,"tag":61,"props":502,"children":503},{"style":74},[504],{"type":35,"value":505},"{{ config(\n",{"type":30,"tag":61,"props":507,"children":508},{"class":63,"line":124},[509,514,519,525],{"type":30,"tag":61,"props":510,"children":511},{"style":74},[512],{"type":35,"value":513},"  materialized",{"type":30,"tag":61,"props":515,"children":516},{"style":68},[517],{"type":35,"value":518},"=",{"type":30,"tag":61,"props":520,"children":522},{"style":521},"--shiki-default:#9ECBFF",[523],{"type":35,"value":524},"'incremental'",{"type":30,"tag":61,"props":526,"children":527},{"style":74},[528],{"type":35,"value":212},{"type":30,"tag":61,"props":530,"children":531},{"class":63,"line":138},[532,537,541,546],{"type":30,"tag":61,"props":533,"children":534},{"style":74},[535],{"type":35,"value":536},"  unique_key",{"type":30,"tag":61,"props":538,"children":539},{"style":68},[540],{"type":35,"value":518},{"type":30,"tag":61,"props":542,"children":543},{"style":521},[544],{"type":35,"value":545},"'user_id'",{"type":30,"tag":61,"props":547,"children":548},{"style":74},[549],{"type":35,"value":212},{"type":30,"tag":61,"props":551,"children":552},{"class":63,"line":152},[553,558,562,567,572,577,582,586,591,595,600],{"type":30,"tag":61,"props":554,"children":555},{"style":74},[556],{"type":35,"value":557},"  partition_by",{"type":30,"tag":61,"props":559,"children":560},{"style":68},[561],{"type":35,"value":518},{"type":30,"tag":61,"props":563,"children":564},{"style":74},[565],{"type":35,"value":566},"{",{"type":30,"tag":61,"props":568,"children":569},{"style":521},[570],{"type":35,"value":571},"'field'",{"type":30,"tag":61,"props":573,"children":574},{"style":74},[575],{"type":35,"value":576},": ",{"type":30,"tag":61,"props":578,"children":579},{"style":521},[580],{"type":35,"value":581},"'cohort_date'",{"type":30,"tag":61,"props":583,"children":584},{"style":74},[585],{"type":35,"value":239},{"type":30,"tag":61,"props":587,"children":588},{"style":521},[589],{"type":35,"value":590},"'data_type'",{"type":30,"tag":61,"props":592,"children":593},{"style":74},[594],{"type":35,"value":576},{"type":30,"tag":61,"props":596,"children":597},{"style":521},[598],{"type":35,"value":599},"'date'",{"type":30,"tag":61,"props":601,"children":602},{"style":74},[603],{"type":35,"value":604},"},\n",{"type":30,"tag":61,"props":606,"children":607},{"class":63,"line":161},[608,613,617],{"type":30,"tag":61,"props":609,"children":610},{"style":74},[611],{"type":35,"value":612},"  cluster_by",{"type":30,"tag":61,"props":614,"children":615},{"style":68},[616],{"type":35,"value":518},{"type":30,"tag":61,"props":618,"children":619},{"style":74},[620],{"type":35,"value":621},"['cohort_date', 'user_id']\n",{"type":30,"tag":61,"props":623,"children":624},{"class":63,"line":178},[625],{"type":30,"tag":61,"props":626,"children":627},{"style":74},[628],{"type":35,"value":629},") }}\n",{"type":30,"tag":61,"props":631,"children":632},{"class":63,"line":191},[633],{"type":30,"tag":61,"props":634,"children":636},{"emptyLinePlaceholder":635},true,[637],{"type":35,"value":638},"\n",{"type":30,"tag":61,"props":640,"children":641},{"class":63,"line":24},[642],{"type":30,"tag":61,"props":643,"children":644},{"style":68},[645],{"type":35,"value":646},"SELECT\n",{"type":30,"tag":61,"props":648,"children":649},{"class":63,"line":278},[650],{"type":30,"tag":61,"props":651,"children":652},{"style":74},[653],{"type":35,"value":654},"  user_id,\n",{"type":30,"tag":61,"props":656,"children":657},{"class":63,"line":324},[658,663,667,671],{"type":30,"tag":61,"props":659,"children":660},{"style":104},[661],{"type":35,"value":662},"  MIN",{"type":30,"tag":61,"props":664,"children":665},{"style":74},[666],{"type":35,"value":112},{"type":30,"tag":61,"props":668,"children":669},{"style":68},[670],{"type":35,"value":82},{"type":30,"tag":61,"props":672,"children":673},{"style":74},[674],{"type":35,"value":675}," cohort_date,\n",{"type":30,"tag":61,"props":677,"children":678},{"class":63,"line":337},[679,684,688,693,697,701],{"type":30,"tag":61,"props":680,"children":681},{"style":104},[682],{"type":35,"value":683},"  COUNT",{"type":30,"tag":61,"props":685,"children":686},{"style":74},[687],{"type":35,"value":289},{"type":30,"tag":61,"props":689,"children":690},{"style":68},[691],{"type":35,"value":692},"*",{"type":30,"tag":61,"props":694,"children":695},{"style":74},[696],{"type":35,"value":266},{"type":30,"tag":61,"props":698,"children":699},{"style":68},[700],{"type":35,"value":82},{"type":30,"tag":61,"props":702,"children":703},{"style":74},[704],{"type":35,"value":705}," first_day_events\n",{"type":30,"tag":61,"props":707,"children":708},{"class":63,"line":361},[709,714,719,724,728,733],{"type":30,"tag":61,"props":710,"children":711},{"style":68},[712],{"type":35,"value":713},"FROM",{"type":30,"tag":61,"props":715,"children":716},{"style":74},[717],{"type":35,"value":718}," {{ source(",{"type":30,"tag":61,"props":720,"children":721},{"style":521},[722],{"type":35,"value":723},"'raw'",{"type":30,"tag":61,"props":725,"children":726},{"style":74},[727],{"type":35,"value":239},{"type":30,"tag":61,"props":729,"children":730},{"style":521},[731],{"type":35,"value":732},"'events'",{"type":30,"tag":61,"props":734,"children":735},{"style":74},[736],{"type":35,"value":629},{"type":30,"tag":61,"props":738,"children":739},{"class":63,"line":383},[740,745,750],{"type":30,"tag":61,"props":741,"children":742},{"style":74},[743],{"type":35,"value":744},"{% ",{"type":30,"tag":61,"props":746,"children":747},{"style":68},[748],{"type":35,"value":749},"if",{"type":30,"tag":61,"props":751,"children":752},{"style":74},[753],{"type":35,"value":754}," is_incremental() %}\n",{"type":30,"tag":61,"props":756,"children":757},{"class":63,"line":392},[758,763,768,773,778,782,787,792,796],{"type":30,"tag":61,"props":759,"children":760},{"style":68},[761],{"type":35,"value":762},"WHERE",{"type":30,"tag":61,"props":764,"children":765},{"style":74},[766],{"type":35,"value":767}," event_date ",{"type":30,"tag":61,"props":769,"children":770},{"style":68},[771],{"type":35,"value":772},">=",{"type":30,"tag":61,"props":774,"children":775},{"style":74},[776],{"type":35,"value":777}," (",{"type":30,"tag":61,"props":779,"children":780},{"style":68},[781],{"type":35,"value":398},{"type":30,"tag":61,"props":783,"children":784},{"style":104},[785],{"type":35,"value":786}," MAX",{"type":30,"tag":61,"props":788,"children":789},{"style":74},[790],{"type":35,"value":791},"(cohort_date) ",{"type":30,"tag":61,"props":793,"children":794},{"style":68},[795],{"type":35,"value":713},{"type":30,"tag":61,"props":797,"children":798},{"style":74},[799],{"type":35,"value":800}," {{ this }})\n",{"type":30,"tag":61,"props":802,"children":804},{"class":63,"line":803},16,[805,810,815,820,825,829,833,837,841],{"type":30,"tag":61,"props":806,"children":807},{"style":68},[808],{"type":35,"value":809},"  AND",{"type":30,"tag":61,"props":811,"children":812},{"style":74},[813],{"type":35,"value":814}," user_id ",{"type":30,"tag":61,"props":816,"children":817},{"style":68},[818],{"type":35,"value":819},"NOT",{"type":30,"tag":61,"props":821,"children":822},{"style":68},[823],{"type":35,"value":824}," IN",{"type":30,"tag":61,"props":826,"children":827},{"style":74},[828],{"type":35,"value":777},{"type":30,"tag":61,"props":830,"children":831},{"style":68},[832],{"type":35,"value":398},{"type":30,"tag":61,"props":834,"children":835},{"style":74},[836],{"type":35,"value":814},{"type":30,"tag":61,"props":838,"children":839},{"style":68},[840],{"type":35,"value":713},{"type":30,"tag":61,"props":842,"children":843},{"style":74},[844],{"type":35,"value":800},{"type":30,"tag":61,"props":846,"children":848},{"class":63,"line":847},17,[849],{"type":30,"tag":61,"props":850,"children":851},{"style":74},[852],{"type":35,"value":853},"{% endif %}\n",{"type":30,"tag":61,"props":855,"children":857},{"class":63,"line":856},18,[858,863],{"type":30,"tag":61,"props":859,"children":860},{"style":68},[861],{"type":35,"value":862},"GROUP BY",{"type":30,"tag":61,"props":864,"children":865},{"style":74},[866],{"type":35,"value":149},{"type":30,"tag":31,"props":868,"children":869},{},[870,872,877],{"type":35,"value":871},"Dieses Model liest beim ersten Run die gesamte Historie (einmalige Kosten), bei späteren täglichen Runs nur neue Benutzer von gestern. Mit Partitionierung nach ",{"type":30,"tag":57,"props":873,"children":875},{"className":874},[],[876],{"type":35,"value":207},{"type":35,"value":878}," berührt BigQuery alte Partitionen gar nicht — Query-Kosten bleiben proportional zum täglichen Ereignisvolumen (10M neue ereignisse → ~50MB Scan).",{"type":30,"tag":31,"props":880,"children":881},{},[882,884,889,891,897],{"type":35,"value":883},"Das Clustering nach ",{"type":30,"tag":57,"props":885,"children":887},{"className":886},[],[888],{"type":35,"value":308},{"type":35,"value":890}," verbessert Join-Performance. Wenn nachgelagerte Retention-Abfragen ",{"type":30,"tag":57,"props":892,"children":894},{"className":893},[],[895],{"type":35,"value":896},"user_cohort_base",{"type":35,"value":898}," joinen, führt BigQuery binäre Suche in Mikro-Partitionen durch — statt 5 Milliarden Zeilen nur relevante Cluster-Blöcke.",{"type":30,"tag":900,"props":901,"children":903},"h3",{"id":902},"partitionierungsstrategie-datum-oder-cohort",[904],{"type":35,"value":905},"Partitionierungsstrategie: Datum oder Cohort?",{"type":30,"tag":31,"props":907,"children":908},{},[909,911,916,918,923,925,930,932,937],{"type":35,"value":910},"Wenn Sie die events-Tabelle nach ",{"type":30,"tag":57,"props":912,"children":914},{"className":913},[],[915],{"type":35,"value":234},{"type":35,"value":917}," partitioniert haben, muss die Cohort-Basis nach ",{"type":30,"tag":57,"props":919,"children":921},{"className":920},[],[922],{"type":35,"value":207},{"type":35,"value":924}," partitioniert sein. Retention-Abfragen sind typischerweise „Retention der Januar-2026-Cohort im Februar\" — cross-period Queries. Eine ",{"type":30,"tag":57,"props":926,"children":928},{"className":927},[],[929],{"type":35,"value":234},{"type":35,"value":931},"-Partition kann hier nicht prunen. Eine ",{"type":30,"tag":57,"props":933,"children":935},{"className":934},[],[936],{"type":35,"value":207},{"type":35,"value":938},"-Partition hingegen liest bei „Januar-Cohort\" nur die Januar-Partition — 30 Tage Daten statt 1 Tag.",{"type":30,"tag":31,"props":940,"children":941},{},[942,944,950],{"type":35,"value":943},"Aber: Partitionszahl sollte 4000 nicht überschreiten (BigQuery-Limit). 10 Jahre Daten = 3650 Partitionen — an der Grenze. Wenn Cohort-Granularität wöchentlich oder monatlich ausreicht, partitionieren Sie nach ",{"type":30,"tag":57,"props":945,"children":947},{"className":946},[],[948],{"type":35,"value":949},"DATE_TRUNC(cohort_date, WEEK)",{"type":35,"value":202},{"type":30,"tag":38,"props":952,"children":954},{"id":953},"pre-aggregierter-retention-cube-kosten-100x-senken",[955],{"type":35,"value":956},"Pre-Aggregierter Retention-Cube: Kosten 100x senken",{"type":30,"tag":31,"props":958,"children":959},{},[960,965],{"type":30,"tag":57,"props":961,"children":963},{"className":962},[],[964],{"type":35,"value":896},{"type":35,"value":966}," ist bereit, aber jede Retention-Query joined immer noch mit der events-Tabelle. Der nächste Schritt: Tägliche Retention-Metriken im Voraus berechnen und in einer materialisierten Tabelle speichern:",{"type":30,"tag":50,"props":968,"children":970},{"className":52,"code":969,"language":54,"meta":14,"style":14},"-- models\u002Fcohorts\u002Fdaily_retention_cube.sql\n{{ config(\n  materialized='incremental',\n  unique_key=['cohort_date', 'day_offset'],\n  partition_by={'field': 'cohort_date', 'data_type': 'date'}\n) }}\n\nWITH cohort_activity AS (\n  SELECT\n    c.cohort_date,\n    DATE_DIFF(e.event_date, c.cohort_date, DAY) AS day_offset,\n    COUNT(DISTINCT e.user_id) AS active_users\n  FROM {{ ref('user_cohort_base') }} c\n  JOIN {{ source('raw', 'events') }} e USING(user_id)\n  {% if is_incremental() %}\n  WHERE e.event_date >= CURRENT_DATE() - 1\n  {% endif %}\n  GROUP BY 1, 2\n)\nSELECT\n  cohort_date,\n  day_offset,\n  active_users,\n  active_users \u002F FIRST_VALUE(active_users) OVER (\n    PARTITION BY cohort_date ORDER BY day_offset\n  ) AS retention_rate\nFROM cohort_activity\n",[971],{"type":30,"tag":57,"props":972,"children":973},{"__ignoreMap":14},[974,982,989,1008,1024,1072,1079,1086,1106,1114,1134,1190,1229,1251,1287,1303,1343,1351,1370,1378,1386,1395,1404,1413,1446,1475,1493],{"type":30,"tag":61,"props":975,"children":976},{"class":63,"line":64},[977],{"type":30,"tag":61,"props":978,"children":979},{"style":494},[980],{"type":35,"value":981},"-- models\u002Fcohorts\u002Fdaily_retention_cube.sql\n",{"type":30,"tag":61,"props":983,"children":984},{"class":63,"line":90},[985],{"type":30,"tag":61,"props":986,"children":987},{"style":74},[988],{"type":35,"value":505},{"type":30,"tag":61,"props":990,"children":991},{"class":63,"line":124},[992,996,1000,1004],{"type":30,"tag":61,"props":993,"children":994},{"style":74},[995],{"type":35,"value":513},{"type":30,"tag":61,"props":997,"children":998},{"style":68},[999],{"type":35,"value":518},{"type":30,"tag":61,"props":1001,"children":1002},{"style":521},[1003],{"type":35,"value":524},{"type":30,"tag":61,"props":1005,"children":1006},{"style":74},[1007],{"type":35,"value":212},{"type":30,"tag":61,"props":1009,"children":1010},{"class":63,"line":138},[1011,1015,1019],{"type":30,"tag":61,"props":1012,"children":1013},{"style":74},[1014],{"type":35,"value":536},{"type":30,"tag":61,"props":1016,"children":1017},{"style":68},[1018],{"type":35,"value":518},{"type":30,"tag":61,"props":1020,"children":1021},{"style":74},[1022],{"type":35,"value":1023},"['cohort_date', 'day_offset'],\n",{"type":30,"tag":61,"props":1025,"children":1026},{"class":63,"line":152},[1027,1031,1035,1039,1043,1047,1051,1055,1059,1063,1067],{"type":30,"tag":61,"props":1028,"children":1029},{"style":74},[1030],{"type":35,"value":557},{"type":30,"tag":61,"props":1032,"children":1033},{"style":68},[1034],{"type":35,"value":518},{"type":30,"tag":61,"props":1036,"children":1037},{"style":74},[1038],{"type":35,"value":566},{"type":30,"tag":61,"props":1040,"children":1041},{"style":521},[1042],{"type":35,"value":571},{"type":30,"tag":61,"props":1044,"children":1045},{"style":74},[1046],{"type":35,"value":576},{"type":30,"tag":61,"props":1048,"children":1049},{"style":521},[1050],{"type":35,"value":581},{"type":30,"tag":61,"props":1052,"children":1053},{"style":74},[1054],{"type":35,"value":239},{"type":30,"tag":61,"props":1056,"children":1057},{"style":521},[1058],{"type":35,"value":590},{"type":30,"tag":61,"props":1060,"children":1061},{"style":74},[1062],{"type":35,"value":576},{"type":30,"tag":61,"props":1064,"children":1065},{"style":521},[1066],{"type":35,"value":599},{"type":30,"tag":61,"props":1068,"children":1069},{"style":74},[1070],{"type":35,"value":1071},"}\n",{"type":30,"tag":61,"props":1073,"children":1074},{"class":63,"line":161},[1075],{"type":30,"tag":61,"props":1076,"children":1077},{"style":74},[1078],{"type":35,"value":629},{"type":30,"tag":61,"props":1080,"children":1081},{"class":63,"line":178},[1082],{"type":30,"tag":61,"props":1083,"children":1084},{"emptyLinePlaceholder":635},[1085],{"type":35,"value":638},{"type":30,"tag":61,"props":1087,"children":1088},{"class":63,"line":191},[1089,1093,1098,1102],{"type":30,"tag":61,"props":1090,"children":1091},{"style":68},[1092],{"type":35,"value":71},{"type":30,"tag":61,"props":1094,"children":1095},{"style":74},[1096],{"type":35,"value":1097}," cohort_activity ",{"type":30,"tag":61,"props":1099,"children":1100},{"style":68},[1101],{"type":35,"value":82},{"type":30,"tag":61,"props":1103,"children":1104},{"style":74},[1105],{"type":35,"value":87},{"type":30,"tag":61,"props":1107,"children":1108},{"class":63,"line":24},[1109],{"type":30,"tag":61,"props":1110,"children":1111},{"style":68},[1112],{"type":35,"value":1113},"  SELECT\n",{"type":30,"tag":61,"props":1115,"children":1116},{"class":63,"line":278},[1117,1122,1126,1130],{"type":30,"tag":61,"props":1118,"children":1119},{"style":104},[1120],{"type":35,"value":1121},"    c",{"type":30,"tag":61,"props":1123,"children":1124},{"style":74},[1125],{"type":35,"value":202},{"type":30,"tag":61,"props":1127,"children":1128},{"style":104},[1129],{"type":35,"value":207},{"type":30,"tag":61,"props":1131,"children":1132},{"style":74},[1133],{"type":35,"value":212},{"type":30,"tag":61,"props":1135,"children":1136},{"class":63,"line":324},[1137,1141,1145,1149,1153,1157,1162,1166,1170,1174,1178,1182,1186],{"type":30,"tag":61,"props":1138,"children":1139},{"style":74},[1140],{"type":35,"value":220},{"type":30,"tag":61,"props":1142,"children":1143},{"style":104},[1144],{"type":35,"value":225},{"type":30,"tag":61,"props":1146,"children":1147},{"style":74},[1148],{"type":35,"value":202},{"type":30,"tag":61,"props":1150,"children":1151},{"style":104},[1152],{"type":35,"value":234},{"type":30,"tag":61,"props":1154,"children":1155},{"style":74},[1156],{"type":35,"value":239},{"type":30,"tag":61,"props":1158,"children":1159},{"style":104},[1160],{"type":35,"value":1161},"c",{"type":30,"tag":61,"props":1163,"children":1164},{"style":74},[1165],{"type":35,"value":202},{"type":30,"tag":61,"props":1167,"children":1168},{"style":104},[1169],{"type":35,"value":207},{"type":30,"tag":61,"props":1171,"children":1172},{"style":74},[1173],{"type":35,"value":239},{"type":30,"tag":61,"props":1175,"children":1176},{"style":68},[1177],{"type":35,"value":261},{"type":30,"tag":61,"props":1179,"children":1180},{"style":74},[1181],{"type":35,"value":266},{"type":30,"tag":61,"props":1183,"children":1184},{"style":68},[1185],{"type":35,"value":82},{"type":30,"tag":61,"props":1187,"children":1188},{"style":74},[1189],{"type":35,"value":275},{"type":30,"tag":61,"props":1191,"children":1192},{"class":63,"line":337},[1193,1197,1201,1205,1209,1213,1217,1221,1225],{"type":30,"tag":61,"props":1194,"children":1195},{"style":104},[1196],{"type":35,"value":284},{"type":30,"tag":61,"props":1198,"children":1199},{"style":74},[1200],{"type":35,"value":289},{"type":30,"tag":61,"props":1202,"children":1203},{"style":68},[1204],{"type":35,"value":294},{"type":30,"tag":61,"props":1206,"children":1207},{"style":104},[1208],{"type":35,"value":299},{"type":30,"tag":61,"props":1210,"children":1211},{"style":74},[1212],{"type":35,"value":202},{"type":30,"tag":61,"props":1214,"children":1215},{"style":104},[1216],{"type":35,"value":308},{"type":30,"tag":61,"props":1218,"children":1219},{"style":74},[1220],{"type":35,"value":266},{"type":30,"tag":61,"props":1222,"children":1223},{"style":68},[1224],{"type":35,"value":82},{"type":30,"tag":61,"props":1226,"children":1227},{"style":74},[1228],{"type":35,"value":321},{"type":30,"tag":61,"props":1230,"children":1231},{"class":63,"line":361},[1232,1236,1241,1246],{"type":30,"tag":61,"props":1233,"children":1234},{"style":68},[1235],{"type":35,"value":130},{"type":30,"tag":61,"props":1237,"children":1238},{"style":74},[1239],{"type":35,"value":1240}," {{ ref(",{"type":30,"tag":61,"props":1242,"children":1243},{"style":521},[1244],{"type":35,"value":1245},"'user_cohort_base'",{"type":30,"tag":61,"props":1247,"children":1248},{"style":74},[1249],{"type":35,"value":1250},") }} c\n",{"type":30,"tag":61,"props":1252,"children":1253},{"class":63,"line":383},[1254,1258,1262,1266,1270,1274,1279,1283],{"type":30,"tag":61,"props":1255,"children":1256},{"style":68},[1257],{"type":35,"value":343},{"type":30,"tag":61,"props":1259,"children":1260},{"style":74},[1261],{"type":35,"value":718},{"type":30,"tag":61,"props":1263,"children":1264},{"style":521},[1265],{"type":35,"value":723},{"type":30,"tag":61,"props":1267,"children":1268},{"style":74},[1269],{"type":35,"value":239},{"type":30,"tag":61,"props":1271,"children":1272},{"style":521},[1273],{"type":35,"value":732},{"type":30,"tag":61,"props":1275,"children":1276},{"style":74},[1277],{"type":35,"value":1278},") }} e ",{"type":30,"tag":61,"props":1280,"children":1281},{"style":68},[1282],{"type":35,"value":353},{"type":30,"tag":61,"props":1284,"children":1285},{"style":74},[1286],{"type":35,"value":358},{"type":30,"tag":61,"props":1288,"children":1289},{"class":63,"line":392},[1290,1295,1299],{"type":30,"tag":61,"props":1291,"children":1292},{"style":74},[1293],{"type":35,"value":1294},"  {% ",{"type":30,"tag":61,"props":1296,"children":1297},{"style":68},[1298],{"type":35,"value":749},{"type":30,"tag":61,"props":1300,"children":1301},{"style":74},[1302],{"type":35,"value":754},{"type":30,"tag":61,"props":1304,"children":1305},{"class":63,"line":803},[1306,1311,1315,1319,1323,1328,1333,1338],{"type":30,"tag":61,"props":1307,"children":1308},{"style":68},[1309],{"type":35,"value":1310},"  WHERE",{"type":30,"tag":61,"props":1312,"children":1313},{"style":104},[1314],{"type":35,"value":299},{"type":30,"tag":61,"props":1316,"children":1317},{"style":74},[1318],{"type":35,"value":202},{"type":30,"tag":61,"props":1320,"children":1321},{"style":104},[1322],{"type":35,"value":234},{"type":30,"tag":61,"props":1324,"children":1325},{"style":68},[1326],{"type":35,"value":1327}," >=",{"type":30,"tag":61,"props":1329,"children":1330},{"style":74},[1331],{"type":35,"value":1332}," CURRENT_DATE() ",{"type":30,"tag":61,"props":1334,"children":1335},{"style":68},[1336],{"type":35,"value":1337},"-",{"type":30,"tag":61,"props":1339,"children":1340},{"style":104},[1341],{"type":35,"value":1342}," 1\n",{"type":30,"tag":61,"props":1344,"children":1345},{"class":63,"line":847},[1346],{"type":30,"tag":61,"props":1347,"children":1348},{"style":74},[1349],{"type":35,"value":1350},"  {% endif %}\n",{"type":30,"tag":61,"props":1352,"children":1353},{"class":63,"line":856},[1354,1358,1362,1366],{"type":30,"tag":61,"props":1355,"children":1356},{"style":68},[1357],{"type":35,"value":144},{"type":30,"tag":61,"props":1359,"children":1360},{"style":104},[1361],{"type":35,"value":371},{"type":30,"tag":61,"props":1363,"children":1364},{"style":74},[1365],{"type":35,"value":239},{"type":30,"tag":61,"props":1367,"children":1368},{"style":104},[1369],{"type":35,"value":380},{"type":30,"tag":61,"props":1371,"children":1373},{"class":63,"line":1372},19,[1374],{"type":30,"tag":61,"props":1375,"children":1376},{"style":74},[1377],{"type":35,"value":389},{"type":30,"tag":61,"props":1379,"children":1381},{"class":63,"line":1380},20,[1382],{"type":30,"tag":61,"props":1383,"children":1384},{"style":68},[1385],{"type":35,"value":646},{"type":30,"tag":61,"props":1387,"children":1389},{"class":63,"line":1388},21,[1390],{"type":30,"tag":61,"props":1391,"children":1392},{"style":74},[1393],{"type":35,"value":1394},"  cohort_date,\n",{"type":30,"tag":61,"props":1396,"children":1398},{"class":63,"line":1397},22,[1399],{"type":30,"tag":61,"props":1400,"children":1401},{"style":74},[1402],{"type":35,"value":1403},"  day_offset,\n",{"type":30,"tag":61,"props":1405,"children":1407},{"class":63,"line":1406},23,[1408],{"type":30,"tag":61,"props":1409,"children":1410},{"style":74},[1411],{"type":35,"value":1412},"  active_users,\n",{"type":30,"tag":61,"props":1414,"children":1416},{"class":63,"line":1415},24,[1417,1422,1427,1432,1437,1442],{"type":30,"tag":61,"props":1418,"children":1419},{"style":74},[1420],{"type":35,"value":1421},"  active_users ",{"type":30,"tag":61,"props":1423,"children":1424},{"style":68},[1425],{"type":35,"value":1426},"\u002F",{"type":30,"tag":61,"props":1428,"children":1429},{"style":104},[1430],{"type":35,"value":1431}," FIRST_VALUE",{"type":30,"tag":61,"props":1433,"children":1434},{"style":74},[1435],{"type":35,"value":1436},"(active_users) ",{"type":30,"tag":61,"props":1438,"children":1439},{"style":68},[1440],{"type":35,"value":1441},"OVER",{"type":30,"tag":61,"props":1443,"children":1444},{"style":74},[1445],{"type":35,"value":87},{"type":30,"tag":61,"props":1447,"children":1449},{"class":63,"line":1448},25,[1450,1455,1460,1465,1470],{"type":30,"tag":61,"props":1451,"children":1452},{"style":68},[1453],{"type":35,"value":1454},"    PARTITION",{"type":30,"tag":61,"props":1456,"children":1457},{"style":68},[1458],{"type":35,"value":1459}," BY",{"type":30,"tag":61,"props":1461,"children":1462},{"style":74},[1463],{"type":35,"value":1464}," cohort_date ",{"type":30,"tag":61,"props":1466,"children":1467},{"style":68},[1468],{"type":35,"value":1469},"ORDER BY",{"type":30,"tag":61,"props":1471,"children":1472},{"style":74},[1473],{"type":35,"value":1474}," day_offset\n",{"type":30,"tag":61,"props":1476,"children":1478},{"class":63,"line":1477},26,[1479,1484,1488],{"type":30,"tag":61,"props":1480,"children":1481},{"style":74},[1482],{"type":35,"value":1483},"  ) ",{"type":30,"tag":61,"props":1485,"children":1486},{"style":68},[1487],{"type":35,"value":82},{"type":30,"tag":61,"props":1489,"children":1490},{"style":74},[1491],{"type":35,"value":1492}," retention_rate\n",{"type":30,"tag":61,"props":1494,"children":1496},{"class":63,"line":1495},27,[1497,1501],{"type":30,"tag":61,"props":1498,"children":1499},{"style":68},[1500],{"type":35,"value":713},{"type":30,"tag":61,"props":1502,"children":1503},{"style":74},[1504],{"type":35,"value":1505}," cohort_activity\n",{"type":30,"tag":31,"props":1507,"children":1508},{},[1509,1511,1516,1518,1523,1525,1530],{"type":35,"value":1510},"Diese Tabelle läuft täglich und fügt nur die neue Aktivität von gestern hinzu. Mit Partitionierung nach ",{"type":30,"tag":57,"props":1512,"children":1514},{"className":1513},[],[1515],{"type":35,"value":207},{"type":35,"value":1517}," bleiben alte Cohort-Partitionen unangetastet. Ergebnis: ",{"type":30,"tag":423,"props":1519,"children":1520},{},[1521],{"type":35,"value":1522},"5 Milliarden Zeilen events",{"type":35,"value":1524}," werden zu ",{"type":30,"tag":423,"props":1526,"children":1527},{},[1528],{"type":35,"value":1529},"500 Cohorts × 90 Tage = 45.000 Zeilen Cube",{"type":35,"value":1531},". Dashboard-Abfragen lesen diesen Cube direkt — Scan-Volumen sinkt um das 100.000-fache, Latenz von 45 Sekunden auf 50 Millisekunden.",{"type":30,"tag":900,"props":1533,"children":1535},{"id":1534},"window-function-strategie-retention-rate-berechnung",[1536],{"type":35,"value":1537},"Window-Function-Strategie: Retention-Rate-Berechnung",{"type":30,"tag":31,"props":1539,"children":1540},{},[1541,1543,1549],{"type":35,"value":1542},"Der Ausdruck ",{"type":30,"tag":57,"props":1544,"children":1546},{"className":1545},[],[1547],{"type":35,"value":1548},"FIRST_VALUE(active_users) OVER (PARTITION BY cohort_date ORDER BY day_offset)",{"type":35,"value":1550}," trägt die D0-Benutzerzahl in jede Zeile. Damit wird die Retention-Rate nicht zur Query-Zeit, sondern zur Write-Zeit berechnet. Alternative: D0 per separatem JOIN abrufen, aber Window-Functions sind in BigQuery für optimierte Slot-Nutzung (sequenzielle Lesevorgänge innerhalb einer Partition) optimiert.",{"type":30,"tag":31,"props":1552,"children":1553},{},[1554,1556,1561,1563,1568],{"type":35,"value":1555},"Achtung: Die ",{"type":30,"tag":57,"props":1557,"children":1559},{"className":1558},[],[1560],{"type":35,"value":1441},{"type":35,"value":1562},"-Klausel zerstört Partition-Pruning nicht, weil die physische Partition (",{"type":30,"tag":57,"props":1564,"children":1566},{"className":1565},[],[1567],{"type":35,"value":207},{"type":35,"value":1569},") und die Window-Partition identisch sind. BigQuery verarbeitet jede Partition unabhängig — kein Cross-Partition-Shuffle.",{"type":30,"tag":38,"props":1571,"children":1573},{"id":1572},"query-kostenoptimierung-slot-nutzung-und-caching",[1574],{"type":35,"value":1575},"Query-Kostenoptimierung: Slot-Nutzung und Caching",{"type":30,"tag":31,"props":1577,"children":1578},{},[1579],{"type":35,"value":1580},"BigQuery-Kostenmodell basiert auf gescanntem Byte (5 Dollar\u002FTB). Für Production-Latenz ist aber Slot-Auslastung kritischer. Materialisierte-View-Strategie senkt Kosten, aber Slot-Contention kann immer noch auftreten — besonders wenn 10 Dashboard-Nutzer gleichzeitig verschiedene Cohort-Filter abrufen.",{"type":30,"tag":31,"props":1582,"children":1583},{},[1584,1589,1591,1597],{"type":30,"tag":423,"props":1585,"children":1586},{},[1587],{"type":35,"value":1588},"BI-Engine-Caching:",{"type":35,"value":1590}," BigQuery BI Engine hält bis zu 100GB Hot-Data im RAM. ",{"type":30,"tag":57,"props":1592,"children":1594},{"className":1593},[],[1595],{"type":35,"value":1596},"daily_retention_cube",{"type":35,"value":1598}," mit 45.000 Zeilen × 200 Byte ≈ 9MB wird komplett gecacht. Nachfolgende Abfragen verbrauchen 0 Slots, \u003C 10ms Antwort. BI-Engine-Reservation wird manuell aktiviert (BigQuery Console → Capacity Management → 100GB Tier = 300 Dollar\u002FMonat). ROI ist hoch — statt 1000 täglicher Queries × 0.01 Dollar Slot-Kosten = 10 Dollar\u002FTag ein fester Preis von 10 Dollar\u002FTag.",{"type":30,"tag":31,"props":1600,"children":1601},{},[1602,1607],{"type":30,"tag":423,"props":1603,"children":1604},{},[1605],{"type":35,"value":1606},"Query-Result-Caching:",{"type":35,"value":1608}," BigQuery cached Abfrageergebnisse 24 Stunden. Wenn Dashboard „Cohorts der letzten 7 Tage\" für alle Nutzer die gleiche Abfrage ist, wird nach dem ersten Hit aus dem Cache bedient. Bei geändertem Parameter (Datumsbereich, Segment-Filter) schlägt der Cache fehl — hier springt der pre-aggregierte Cube ein.",{"type":30,"tag":31,"props":1610,"children":1611},{},[1612,1617],{"type":30,"tag":423,"props":1613,"children":1614},{},[1615],{"type":35,"value":1616},"Slot-Zuweisung:",{"type":35,"value":1618}," Wenn Sie statt On-Demand-Pricing ein Flat-Rate-Modell erwägen (500 Slots = 10.000 Dollar\u002FMonat), ordnen Sie die Retention-Pipeline einem dedizierten Slot-Pool zu. Nicht dass Retention-Berechnungen in Peak-Hours um Slots mit BI-Abfragen konkurrieren. Im Roibase-Production-BigQuery-Setup laufen geplante Queries off-peak (03:00-05:00), benutzergerichtete Dashboards nutzen Flex-Slots (Autoscale 100-500).",{"type":30,"tag":38,"props":1620,"children":1622},{"id":1621},"identity-resolution-integration-cross-device-cohort",[1623],{"type":35,"value":1624},"Identity-Resolution-Integration: Cross-Device-Cohort",{"type":30,"tag":31,"props":1626,"children":1627},{},[1628,1630,1635],{"type":35,"value":1629},"Klassische Cohort-Analyse läuft über ",{"type":30,"tag":57,"props":1631,"children":1633},{"className":1632},[],[1634],{"type":35,"value":308},{"type":35,"value":1636},", aber in Cross-Device-User-Journey trägt dieselbe Person 3 verschiedene IDs (Web anonym, App logged-in, CRM). Retention wird mit 15% gemessen, ist aber real 22% — ID-Fragmentierung ist der Grund.",{"type":30,"tag":31,"props":1638,"children":1639},{},[1640,1642,1651,1653,1659,1661,1667,1668,1673,1674,1680,1682,1688],{"type":35,"value":1641},"Im Kontext der ",{"type":30,"tag":1643,"props":1644,"children":1648},"a",{"href":1645,"rel":1646},"https:\u002F\u002Fwww.roibase.com.tr\u002Fde\u002Ffirstparty",[1647],"nofollow",[1649],{"type":35,"value":1650},"First-Party-Daten & Mesarchitur",{"type":35,"value":1652}," wird ein Identity-Graph aufgebaut: Die ",{"type":30,"tag":57,"props":1654,"children":1656},{"className":1655},[],[1657],{"type":35,"value":1658},"identity_map",{"type":35,"value":1660},"-Tabelle verknüpft jede ",{"type":30,"tag":57,"props":1662,"children":1664},{"className":1663},[],[1665],{"type":35,"value":1666},"anonymous_id",{"type":35,"value":239},{"type":30,"tag":57,"props":1669,"children":1671},{"className":1670},[],[1672],{"type":35,"value":308},{"type":35,"value":239},{"type":30,"tag":57,"props":1675,"children":1677},{"className":1676},[],[1678],{"type":35,"value":1679},"crm_id",{"type":35,"value":1681}," mit einer kanonischen ",{"type":30,"tag":57,"props":1683,"children":1685},{"className":1684},[],[1686],{"type":35,"value":1687},"person_id",{"type":35,"value":1689},". Bereichern Sie das Cohort-Base-Model mit diesem Graph:",{"type":30,"tag":50,"props":1691,"children":1693},{"className":52,"code":1692,"language":54,"meta":14,"style":14},"WITH resolved_events AS (\n  SELECT\n    COALESCE(i.person_id, e.user_id) AS person_id,\n    e.event_date\n  FROM {{ source('raw', 'events') }} e\n  LEFT JOIN {{ ref('identity_map') }} i ON e.user_id = i.user_id\n)\nSELECT person_id, MIN(event_date) AS cohort_date\nFROM resolved_events\nGROUP BY person_id\n",[1694],{"type":30,"tag":57,"props":1695,"children":1696},{"__ignoreMap":14},[1697,1717,1724,1778,1795,1823,1881,1888,1916,1928],{"type":30,"tag":61,"props":1698,"children":1699},{"class":63,"line":64},[1700,1704,1709,1713],{"type":30,"tag":61,"props":1701,"children":1702},{"style":68},[1703],{"type":35,"value":71},{"type":30,"tag":61,"props":1705,"children":1706},{"style":74},[1707],{"type":35,"value":1708}," resolved_events ",{"type":30,"tag":61,"props":1710,"children":1711},{"style":68},[1712],{"type":35,"value":82},{"type":30,"tag":61,"props":1714,"children":1715},{"style":74},[1716],{"type":35,"value":87},{"type":30,"tag":61,"props":1718,"children":1719},{"class":63,"line":90},[1720],{"type":30,"tag":61,"props":1721,"children":1722},{"style":68},[1723],{"type":35,"value":1113},{"type":30,"tag":61,"props":1725,"children":1726},{"class":63,"line":124},[1727,1732,1736,1741,1745,1749,1753,1757,1761,1765,1769,1773],{"type":30,"tag":61,"props":1728,"children":1729},{"style":104},[1730],{"type":35,"value":1731},"    COALESCE",{"type":30,"tag":61,"props":1733,"children":1734},{"style":74},[1735],{"type":35,"value":289},{"type":30,"tag":61,"props":1737,"children":1738},{"style":104},[1739],{"type":35,"value":1740},"i",{"type":30,"tag":61,"props":1742,"children":1743},{"style":74},[1744],{"type":35,"value":202},{"type":30,"tag":61,"props":1746,"children":1747},{"style":104},[1748],{"type":35,"value":1687},{"type":30,"tag":61,"props":1750,"children":1751},{"style":74},[1752],{"type":35,"value":239},{"type":30,"tag":61,"props":1754,"children":1755},{"style":104},[1756],{"type":35,"value":225},{"type":30,"tag":61,"props":1758,"children":1759},{"style":74},[1760],{"type":35,"value":202},{"type":30,"tag":61,"props":1762,"children":1763},{"style":104},[1764],{"type":35,"value":308},{"type":30,"tag":61,"props":1766,"children":1767},{"style":74},[1768],{"type":35,"value":266},{"type":30,"tag":61,"props":1770,"children":1771},{"style":68},[1772],{"type":35,"value":82},{"type":30,"tag":61,"props":1774,"children":1775},{"style":74},[1776],{"type":35,"value":1777}," person_id,\n",{"type":30,"tag":61,"props":1779,"children":1780},{"class":63,"line":138},[1781,1786,1790],{"type":30,"tag":61,"props":1782,"children":1783},{"style":104},[1784],{"type":35,"value":1785},"    e",{"type":30,"tag":61,"props":1787,"children":1788},{"style":74},[1789],{"type":35,"value":202},{"type":30,"tag":61,"props":1791,"children":1792},{"style":104},[1793],{"type":35,"value":1794},"event_date\n",{"type":30,"tag":61,"props":1796,"children":1797},{"class":63,"line":152},[1798,1802,1806,1810,1814,1818],{"type":30,"tag":61,"props":1799,"children":1800},{"style":68},[1801],{"type":35,"value":130},{"type":30,"tag":61,"props":1803,"children":1804},{"style":74},[1805],{"type":35,"value":718},{"type":30,"tag":61,"props":1807,"children":1808},{"style":521},[1809],{"type":35,"value":723},{"type":30,"tag":61,"props":1811,"children":1812},{"style":74},[1813],{"type":35,"value":239},{"type":30,"tag":61,"props":1815,"children":1816},{"style":521},[1817],{"type":35,"value":732},{"type":30,"tag":61,"props":1819,"children":1820},{"style":74},[1821],{"type":35,"value":1822},") }} e\n",{"type":30,"tag":61,"props":1824,"children":1825},{"class":63,"line":161},[1826,1831,1835,1840,1845,1850,1854,1858,1862,1867,1872,1876],{"type":30,"tag":61,"props":1827,"children":1828},{"style":68},[1829],{"type":35,"value":1830},"  LEFT JOIN",{"type":30,"tag":61,"props":1832,"children":1833},{"style":74},[1834],{"type":35,"value":1240},{"type":30,"tag":61,"props":1836,"children":1837},{"style":521},[1838],{"type":35,"value":1839},"'identity_map'",{"type":30,"tag":61,"props":1841,"children":1842},{"style":74},[1843],{"type":35,"value":1844},") }} i ",{"type":30,"tag":61,"props":1846,"children":1847},{"style":68},[1848],{"type":35,"value":1849},"ON",{"type":30,"tag":61,"props":1851,"children":1852},{"style":104},[1853],{"type":35,"value":299},{"type":30,"tag":61,"props":1855,"children":1856},{"style":74},[1857],{"type":35,"value":202},{"type":30,"tag":61,"props":1859,"children":1860},{"style":104},[1861],{"type":35,"value":308},{"type":30,"tag":61,"props":1863,"children":1864},{"style":68},[1865],{"type":35,"value":1866}," =",{"type":30,"tag":61,"props":1868,"children":1869},{"style":104},[1870],{"type":35,"value":1871}," i",{"type":30,"tag":61,"props":1873,"children":1874},{"style":74},[1875],{"type":35,"value":202},{"type":30,"tag":61,"props":1877,"children":1878},{"style":104},[1879],{"type":35,"value":1880},"user_id\n",{"type":30,"tag":61,"props":1882,"children":1883},{"class":63,"line":178},[1884],{"type":30,"tag":61,"props":1885,"children":1886},{"style":74},[1887],{"type":35,"value":389},{"type":30,"tag":61,"props":1889,"children":1890},{"class":63,"line":191},[1891,1895,1900,1904,1908,1912],{"type":30,"tag":61,"props":1892,"children":1893},{"style":68},[1894],{"type":35,"value":398},{"type":30,"tag":61,"props":1896,"children":1897},{"style":74},[1898],{"type":35,"value":1899}," person_id, ",{"type":30,"tag":61,"props":1901,"children":1902},{"style":104},[1903],{"type":35,"value":107},{"type":30,"tag":61,"props":1905,"children":1906},{"style":74},[1907],{"type":35,"value":112},{"type":30,"tag":61,"props":1909,"children":1910},{"style":68},[1911],{"type":35,"value":82},{"type":30,"tag":61,"props":1913,"children":1914},{"style":74},[1915],{"type":35,"value":121},{"type":30,"tag":61,"props":1917,"children":1918},{"class":63,"line":24},[1919,1923],{"type":30,"tag":61,"props":1920,"children":1921},{"style":68},[1922],{"type":35,"value":713},{"type":30,"tag":61,"props":1924,"children":1925},{"style":74},[1926],{"type":35,"value":1927}," resolved_events\n",{"type":30,"tag":61,"props":1929,"children":1930},{"class":63,"line":278},[1931,1935],{"type":30,"tag":61,"props":1932,"children":1933},{"style":68},[1934],{"type":35,"value":862},{"type":30,"tag":61,"props":1936,"children":1937},{"style":74},[1938],{"type":35,"value":1939}," person_id\n",{"type":30,"tag":31,"props":1941,"children":1942},{},[1943,1945,1950,1952,1957],{"type":35,"value":1944},"Dieser JOIN kann kostspielig sein, aber ",{"type":30,"tag":57,"props":1946,"children":1948},{"className":1947},[],[1949],{"type":35,"value":1658},{"type":35,"value":1951}," erhält tägliche inkrementelle Updates mit Clustering nach ",{"type":30,"tag":57,"props":1953,"children":1955},{"className":1954},[],[1956],{"type":35,"value":308},{"type":35,"value":1958}," — BigQuery macht Hash-Join, kein Broadcast-Join-Overhead. Die resultierende Cohort zeigt wahre D7-Retention-Werte, Marketing-Entscheidungen (Budget-Reallokation, LTV-Prognose) basieren auf korrekten Daten.",{"type":30,"tag":38,"props":1960,"children":1962},{"id":1961},"inkrementelle-refresh-strategie-backfill-vs-tägliches-delta",[1963],{"type":35,"value":1964},"Inkrementelle Refresh-Strategie: Backfill vs. tägliches Delta",{"type":30,"tag":31,"props":1966,"children":1967},{},[1968],{"type":35,"value":1969},"Kritisches Risiko materialisierter Views: Wenn upstream-Daten korrigiert werden (verspäte ereignisse, GDPR-Löschung), bleibt der downstream-View veraltet. BigQuery hat kein automatisches Refresh von materialisierten Views — Sie triggern es.",{"type":30,"tag":31,"props":1971,"children":1972},{},[1973],{"type":30,"tag":423,"props":1974,"children":1975},{},[1976],{"type":35,"value":1977},"Zwei Strategien:",{"type":30,"tag":1979,"props":1980,"children":1981},"ol",{},[1982,1993],{"type":30,"tag":1983,"props":1984,"children":1985},"li",{},[1986,1991],{"type":30,"tag":423,"props":1987,"children":1988},{},[1989],{"type":35,"value":1990},"Tägliches Delta:",{"type":35,"value":1992}," Nur neue Partition täglich berechnen. Schnell, verpasst aber historische Korrektionen.",{"type":30,"tag":1983,"props":1994,"children":1995},{},[1996,2001],{"type":30,"tag":423,"props":1997,"children":1998},{},[1999],{"type":35,"value":2000},"Rollierender Backfill:",{"type":35,"value":2002}," Die letzten 7 Tage täglich neu berechnen. Erfasst verspätete ereignisse, verbraucht aber 7x Compute.",{"type":30,"tag":31,"props":2004,"children":2005},{},[2006],{"type":35,"value":2007},"Im Roibase-Production-Setup: Hybrid-Ansatz — tägliches Delta + wöchentlicher Full Refresh. In dbt:",{"type":30,"tag":50,"props":2009,"children":2013},{"className":2010,"code":2011,"language":2012,"meta":14,"style":14},"language-yaml shiki shiki-themes github-dark","# dbt_project.yml\nmodels:\n  cohorts:\n    daily_retention_cube:\n      +full_refresh: \"{{ var('force_backfill', false) }}\"\n","yaml",[2014],{"type":30,"tag":57,"props":2015,"children":2016},{"__ignoreMap":14},[2017,2025,2039,2051,2063],{"type":30,"tag":61,"props":2018,"children":2019},{"class":63,"line":64},[2020],{"type":30,"tag":61,"props":2021,"children":2022},{"style":494},[2023],{"type":35,"value":2024},"# dbt_project.yml\n",{"type":30,"tag":61,"props":2026,"children":2027},{"class":63,"line":90},[2028,2034],{"type":30,"tag":61,"props":2029,"children":2031},{"style":2030},"--shiki-default:#85E89D",[2032],{"type":35,"value":2033},"models",{"type":30,"tag":61,"props":2035,"children":2036},{"style":74},[2037],{"type":35,"value":2038},":\n",{"type":30,"tag":61,"props":2040,"children":2041},{"class":63,"line":124},[2042,2047],{"type":30,"tag":61,"props":2043,"children":2044},{"style":2030},[2045],{"type":35,"value":2046},"  cohorts",{"type":30,"tag":61,"props":2048,"children":2049},{"style":74},[2050],{"type":35,"value":2038},{"type":30,"tag":61,"props":2052,"children":2053},{"class":63,"line":138},[2054,2059],{"type":30,"tag":61,"props":2055,"children":2056},{"style":2030},[2057],{"type":35,"value":2058},"    daily_retention_cube",{"type":30,"tag":61,"props":2060,"children":2061},{"style":74},[2062],{"type":35,"value":2038},{"type":30,"tag":61,"props":2064,"children":2065},{"class":63,"line":152},[2066,2071,2075],{"type":30,"tag":61,"props":2067,"children":2068},{"style":2030},[2069],{"type":35,"value":2070},"      +full_refresh",{"type":30,"tag":61,"props":2072,"children":2073},{"style":74},[2074],{"type":35,"value":576},{"type":30,"tag":61,"props":2076,"children":2077},{"style":521},[2078],{"type":35,"value":2079},"\"{{ var('force_backfill', false) }}\"\n",{"type":30,"tag":31,"props":2081,"children":2082},{},[2083,2085,2091,2093,2099],{"type":35,"value":2084},"Normaler Run ",{"type":30,"tag":57,"props":2086,"children":2088},{"className":2087},[],[2089],{"type":35,"value":2090},"dbt run --select daily_retention_cube",{"type":35,"value":2092}," (inkrementell). Wochenende ",{"type":30,"tag":57,"props":2094,"children":2096},{"className":2095},[],[2097],{"type":35,"value":2098},"dbt run --select daily_retention_cube --vars '{force_backfill: true}'",{"type":35,"value":2100}," (Full Refresh). So kontrollieren Sie den Cost-Accuracy-Tradeoff.",{"type":30,"tag":38,"props":2102,"children":2104},{"id":2103},"performance-benchmark-naiv-vs-optimiert",[2105],{"type":35,"value":2106},"Performance-Benchmark: Naiv vs. Optimiert",{"type":30,"tag":31,"props":2108,"children":2109},{},[2110],{"type":35,"value":2111},"Production-Dataset: 10M ereignisse\u002FTag, 18 Monate Historie, 5,4 Milliarden Zeilen.",{"type":30,"tag":2113,"props":2114,"children":2115},"table",{},[2116,2145],{"type":30,"tag":2117,"props":2118,"children":2119},"thead",{},[2120],{"type":30,"tag":2121,"props":2122,"children":2123},"tr",{},[2124,2130,2135,2140],{"type":30,"tag":2125,"props":2126,"children":2127},"th",{},[2128],{"type":35,"value":2129},"Metrik",{"type":30,"tag":2125,"props":2131,"children":2132},{},[2133],{"type":35,"value":2134},"Naives SQL",{"type":30,"tag":2125,"props":2136,"children":2137},{},[2138],{"type":35,"value":2139},"Materialisierter Cube",{"type":30,"tag":2125,"props":2141,"children":2142},{},[2143],{"type":35,"value":2144},"Verbesserung",{"type":30,"tag":2146,"props":2147,"children":2148},"tbody",{},[2149,2173,2196,2219,2241],{"type":30,"tag":2121,"props":2150,"children":2151},{},[2152,2158,2163,2168],{"type":30,"tag":2153,"props":2154,"children":2155},"td",{},[2156],{"type":35,"value":2157},"Scan-Volume (D7 Retention)",{"type":30,"tag":2153,"props":2159,"children":2160},{},[2161],{"type":35,"value":2162},"2,1 TB",{"type":30,"tag":2153,"props":2164,"children":2165},{},[2166],{"type":35,"value":2167},"18 MB",{"type":30,"tag":2153,"props":2169,"children":2170},{},[2171],{"type":35,"value":2172},"116x",{"type":30,"tag":2121,"props":2174,"children":2175},{},[2176,2181,2186,2191],{"type":30,"tag":2153,"props":2177,"children":2178},{},[2179],{"type":35,"value":2180},"Query-Latenz (p95)",{"type":30,"tag":2153,"props":2182,"children":2183},{},[2184],{"type":35,"value":2185},"42 sek",{"type":30,"tag":2153,"props":2187,"children":2188},{},[2189],{"type":35,"value":2190},"0,08 sek",{"type":30,"tag":2153,"props":2192,"children":2193},{},[2194],{"type":35,"value":2195},"525x",{"type":30,"tag":2121,"props":2197,"children":2198},{},[2199,2204,2209,2214],{"type":30,"tag":2153,"props":2200,"children":2201},{},[2202],{"type":35,"value":2203},"BigQuery-Kosten\u002FQuery",{"type":30,"tag":2153,"props":2205,"children":2206},{},[2207],{"type":35,"value":2208},"10,50 Dollar",{"type":30,"tag":2153,"props":2210,"children":2211},{},[2212],{"type":35,"value":2213},"0,01 Dollar",{"type":30,"tag":2153,"props":2215,"children":2216},{},[2217],{"type":35,"value":2218},"1050x",{"type":30,"tag":2121,"props":2220,"children":2221},{},[2222,2227,2232,2237],{"type":30,"tag":2153,"props":2223,"children":2224},{},[2225],{"type":35,"value":2226},"Dashboard-Ladezeit",{"type":30,"tag":2153,"props":2228,"children":2229},{},[2230],{"type":35,"value":2231},"Timeout",{"type":30,"tag":2153,"props":2233,"children":2234},{},[2235],{"type":35,"value":2236},"\u003C1 sek",{"type":30,"tag":2153,"props":2238,"children":2239},{},[2240],{"type":35,"value":1337},{"type":30,"tag":2121,"props":2242,"children":2243},{},[2244,2249,2254,2259],{"type":30,"tag":2153,"props":2245,"children":2246},{},[2247],{"type":35,"value":2248},"Slot-Nutzung (Peak)",{"type":30,"tag":2153,"props":2250,"children":2251},{},[2252],{"type":35,"value":2253},"2000",{"type":30,"tag":2153,"props":2255,"children":2256},{},[2257],{"type":35,"value":2258},"5",{"type":30,"tag":2153,"props":2260,"children":2261},{},[2262],{"type":35,"value":2263},"400x",{"type":30,"tag":31,"props":2265,"children":2266},{},[2267],{"type":35,"value":2268},"Test-Abfrage: „30-Tage-Retention-Kurve der Januar-2026-Cohort\". Die naive Abfrage liest die events-Tabelle 18-mal (täglich). Der materialisierte Cube liest 30 Zeilen.",{"type":30,"tag":31,"props":2270,"children":2271},{},[2272],{"type":35,"value":2273},"Mit aktiviertem BI-Engine-Cache sinkt die Latenz von 80ms auf 12ms — Slot-Nutzung auf null. Im Dashboard-Test mit 50 concurrent Nutzern: 99,5% Uptime, median 18ms Response. Das ist Production-SLA — das Marketing-Team kann Cohort-Segmentierung in",{"type":30,"tag":2275,"props":2276,"children":2277},"style",{},[2278],{"type":35,"value":2279},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":14,"searchDepth":124,"depth":124,"links":2281},[2282,2283,2286,2289,2290,2291,2292],{"id":40,"depth":90,"text":43},{"id":465,"depth":90,"text":468,"children":2284},[2285],{"id":902,"depth":124,"text":905},{"id":953,"depth":90,"text":956,"children":2287},[2288],{"id":1534,"depth":124,"text":1537},{"id":1572,"depth":90,"text":1575},{"id":1621,"depth":90,"text":1624},{"id":1961,"depth":90,"text":1964},{"id":2103,"depth":90,"text":2106},"markdown","content:de:data:cohort-table-architecture-retention-at-scale.md","content","de\u002Fdata\u002Fcohort-table-architecture-retention-at-scale.md","de\u002Fdata\u002Fcohort-table-architecture-retention-at-scale","md",1783865055087]