[{"data":1,"prerenderedAt":2691},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fen\u002Fdata\u002Fcohort-table-architecture-scaling-retention-analysis-production":13},{"i18nKey":4,"paths":5},"data-007-2026-05",{"de":6,"en":7,"es":8,"fr":9,"it":10,"ru":11,"tr":12},"\u002Fde\u002Fdata\u002Fcohort-tabellenstruktur","\u002Fen\u002Fdata\u002Fcohort-table-architecture-scaling-retention-analysis-production","\u002Fes\u002Fdata\u002Farquitectura-tabla-cohort","\u002Ffr\u002Fdata\u002Fcohort-table-architecture","\u002Fit\u002Fdata\u002Farchitettura-tabella-cohort-retention-production","\u002Fru\u002Fdata\u002Fcohort-tablesql-architecture-production-retention","\u002Ftr\u002Fdata\u002Fcohort-tablo-mimarisi-retention-analizinin-productionda-olceklenmesi",{"_path":7,"_dir":14,"_draft":15,"_partial":15,"_locale":16,"title":17,"description":18,"publishedAt":19,"modifiedAt":19,"category":14,"i18nKey":4,"tags":20,"readingTime":26,"author":27,"body":28,"_type":2685,"_id":2686,"_source":2687,"_file":2688,"_stem":2689,"_extension":2690},"data",false,"","Cohort Table Architecture: Scaling Retention Analysis in Production","Production-ready BigQuery architecture for cohort analysis across millions of users: materialized views, partitioning, and query cost optimization strategies.","2026-05-22",[21,22,23,24,25],"cohort-analysis","bigquery","materialized-views","retention-engineering","query-optimization",8,"Roibase",{"type":29,"children":30,"toc":2675},"root",[31,39,46,51,531,544,550,578,670,675,681,686,848,860,865,1195,1200,1206,1211,1253,1258,2141,2157,2163,2168,2206,2211,2298,2303,2309,2314,2328,2333,2423,2428,2434,2439,2472,2486,2492,2497,2530,2535,2659,2664,2669],{"type":32,"tag":33,"props":34,"children":35},"element","p",{},[36],{"type":37,"value":38},"text","Retention analysis is one of the most powerful ways to understand user behavior. But at real scale — millions of events per day, hundreds of thousands of users — naive SQL queries timeout in 30 seconds or exhaust slot capacity. Sustainable cohort analysis in production requires optimizing table architecture to match the query engine. This article shows how to scale cohort tables on BigQuery using materialized views, partitioning, and incremental refresh strategies.",{"type":32,"tag":40,"props":41,"children":43},"h2",{"id":42},"why-naive-cohort-queries-fail",[44],{"type":37,"value":45},"Why Naive Cohort Queries Fail",{"type":32,"tag":33,"props":47,"children":48},{},[49],{"type":37,"value":50},"Classical cohort analysis works like this: find the user's first activity date (cohort_date), calculate all subsequent activities as \"Day N\" relative to that date, aggregate retention rates by group. The following SQL is logically correct but fails in production:",{"type":32,"tag":52,"props":53,"children":57},"pre",{"className":54,"code":55,"language":56,"meta":16,"style":16},"language-sql shiki shiki-themes github-dark","WITH first_event AS (\n  SELECT user_id, MIN(DATE(event_timestamp)) AS cohort_date\n  FROM `project.dataset.events`\n  GROUP BY user_id\n),\ndaily_activity AS (\n  SELECT e.user_id, DATE(e.event_timestamp) AS activity_date\n  FROM `project.dataset.events` e\n  GROUP BY 1,2\n)\nSELECT \n  f.cohort_date,\n  DATE_DIFF(d.activity_date, f.cohort_date, DAY) AS day_n,\n  COUNT(DISTINCT d.user_id) AS retained_users\nFROM first_event f\nJOIN daily_activity d USING(user_id)\nGROUP BY 1,2\nORDER BY 1,2;\n","sql",[58],{"type":32,"tag":59,"props":60,"children":61},"code",{"__ignoreMap":16},[62,90,134,149,163,172,189,253,270,293,302,316,339,401,445,459,483,504],{"type":32,"tag":63,"props":64,"children":67},"span",{"class":65,"line":66},"line",1,[68,74,80,85],{"type":32,"tag":63,"props":69,"children":71},{"style":70},"--shiki-default:#F97583",[72],{"type":37,"value":73},"WITH",{"type":32,"tag":63,"props":75,"children":77},{"style":76},"--shiki-default:#E1E4E8",[78],{"type":37,"value":79}," first_event ",{"type":32,"tag":63,"props":81,"children":82},{"style":70},[83],{"type":37,"value":84},"AS",{"type":32,"tag":63,"props":86,"children":87},{"style":76},[88],{"type":37,"value":89}," (\n",{"type":32,"tag":63,"props":91,"children":93},{"class":65,"line":92},2,[94,99,104,110,115,120,125,129],{"type":32,"tag":63,"props":95,"children":96},{"style":70},[97],{"type":37,"value":98},"  SELECT",{"type":32,"tag":63,"props":100,"children":101},{"style":76},[102],{"type":37,"value":103}," user_id, ",{"type":32,"tag":63,"props":105,"children":107},{"style":106},"--shiki-default:#79B8FF",[108],{"type":37,"value":109},"MIN",{"type":32,"tag":63,"props":111,"children":112},{"style":76},[113],{"type":37,"value":114},"(",{"type":32,"tag":63,"props":116,"children":117},{"style":70},[118],{"type":37,"value":119},"DATE",{"type":32,"tag":63,"props":121,"children":122},{"style":76},[123],{"type":37,"value":124},"(event_timestamp)) ",{"type":32,"tag":63,"props":126,"children":127},{"style":70},[128],{"type":37,"value":84},{"type":32,"tag":63,"props":130,"children":131},{"style":76},[132],{"type":37,"value":133}," cohort_date\n",{"type":32,"tag":63,"props":135,"children":137},{"class":65,"line":136},3,[138,143],{"type":32,"tag":63,"props":139,"children":140},{"style":70},[141],{"type":37,"value":142},"  FROM",{"type":32,"tag":63,"props":144,"children":146},{"style":145},"--shiki-default:#9ECBFF",[147],{"type":37,"value":148}," `project.dataset.events`\n",{"type":32,"tag":63,"props":150,"children":152},{"class":65,"line":151},4,[153,158],{"type":32,"tag":63,"props":154,"children":155},{"style":70},[156],{"type":37,"value":157},"  GROUP BY",{"type":32,"tag":63,"props":159,"children":160},{"style":76},[161],{"type":37,"value":162}," user_id\n",{"type":32,"tag":63,"props":164,"children":166},{"class":65,"line":165},5,[167],{"type":32,"tag":63,"props":168,"children":169},{"style":76},[170],{"type":37,"value":171},"),\n",{"type":32,"tag":63,"props":173,"children":175},{"class":65,"line":174},6,[176,181,185],{"type":32,"tag":63,"props":177,"children":178},{"style":76},[179],{"type":37,"value":180},"daily_activity ",{"type":32,"tag":63,"props":182,"children":183},{"style":70},[184],{"type":37,"value":84},{"type":32,"tag":63,"props":186,"children":187},{"style":76},[188],{"type":37,"value":89},{"type":32,"tag":63,"props":190,"children":192},{"class":65,"line":191},7,[193,197,202,207,212,217,221,225,230,234,239,244,248],{"type":32,"tag":63,"props":194,"children":195},{"style":70},[196],{"type":37,"value":98},{"type":32,"tag":63,"props":198,"children":199},{"style":106},[200],{"type":37,"value":201}," e",{"type":32,"tag":63,"props":203,"children":204},{"style":76},[205],{"type":37,"value":206},".",{"type":32,"tag":63,"props":208,"children":209},{"style":106},[210],{"type":37,"value":211},"user_id",{"type":32,"tag":63,"props":213,"children":214},{"style":76},[215],{"type":37,"value":216},", ",{"type":32,"tag":63,"props":218,"children":219},{"style":70},[220],{"type":37,"value":119},{"type":32,"tag":63,"props":222,"children":223},{"style":76},[224],{"type":37,"value":114},{"type":32,"tag":63,"props":226,"children":227},{"style":106},[228],{"type":37,"value":229},"e",{"type":32,"tag":63,"props":231,"children":232},{"style":76},[233],{"type":37,"value":206},{"type":32,"tag":63,"props":235,"children":236},{"style":106},[237],{"type":37,"value":238},"event_timestamp",{"type":32,"tag":63,"props":240,"children":241},{"style":76},[242],{"type":37,"value":243},") ",{"type":32,"tag":63,"props":245,"children":246},{"style":70},[247],{"type":37,"value":84},{"type":32,"tag":63,"props":249,"children":250},{"style":76},[251],{"type":37,"value":252}," activity_date\n",{"type":32,"tag":63,"props":254,"children":255},{"class":65,"line":26},[256,260,265],{"type":32,"tag":63,"props":257,"children":258},{"style":70},[259],{"type":37,"value":142},{"type":32,"tag":63,"props":261,"children":262},{"style":145},[263],{"type":37,"value":264}," `project.dataset.events`",{"type":32,"tag":63,"props":266,"children":267},{"style":76},[268],{"type":37,"value":269}," e\n",{"type":32,"tag":63,"props":271,"children":273},{"class":65,"line":272},9,[274,278,283,288],{"type":32,"tag":63,"props":275,"children":276},{"style":70},[277],{"type":37,"value":157},{"type":32,"tag":63,"props":279,"children":280},{"style":106},[281],{"type":37,"value":282}," 1",{"type":32,"tag":63,"props":284,"children":285},{"style":76},[286],{"type":37,"value":287},",",{"type":32,"tag":63,"props":289,"children":290},{"style":106},[291],{"type":37,"value":292},"2\n",{"type":32,"tag":63,"props":294,"children":296},{"class":65,"line":295},10,[297],{"type":32,"tag":63,"props":298,"children":299},{"style":76},[300],{"type":37,"value":301},")\n",{"type":32,"tag":63,"props":303,"children":305},{"class":65,"line":304},11,[306,311],{"type":32,"tag":63,"props":307,"children":308},{"style":70},[309],{"type":37,"value":310},"SELECT",{"type":32,"tag":63,"props":312,"children":313},{"style":76},[314],{"type":37,"value":315}," \n",{"type":32,"tag":63,"props":317,"children":319},{"class":65,"line":318},12,[320,325,329,334],{"type":32,"tag":63,"props":321,"children":322},{"style":106},[323],{"type":37,"value":324},"  f",{"type":32,"tag":63,"props":326,"children":327},{"style":76},[328],{"type":37,"value":206},{"type":32,"tag":63,"props":330,"children":331},{"style":106},[332],{"type":37,"value":333},"cohort_date",{"type":32,"tag":63,"props":335,"children":336},{"style":76},[337],{"type":37,"value":338},",\n",{"type":32,"tag":63,"props":340,"children":342},{"class":65,"line":341},13,[343,348,353,357,362,366,371,375,379,383,388,392,396],{"type":32,"tag":63,"props":344,"children":345},{"style":76},[346],{"type":37,"value":347},"  DATE_DIFF(",{"type":32,"tag":63,"props":349,"children":350},{"style":106},[351],{"type":37,"value":352},"d",{"type":32,"tag":63,"props":354,"children":355},{"style":76},[356],{"type":37,"value":206},{"type":32,"tag":63,"props":358,"children":359},{"style":106},[360],{"type":37,"value":361},"activity_date",{"type":32,"tag":63,"props":363,"children":364},{"style":76},[365],{"type":37,"value":216},{"type":32,"tag":63,"props":367,"children":368},{"style":106},[369],{"type":37,"value":370},"f",{"type":32,"tag":63,"props":372,"children":373},{"style":76},[374],{"type":37,"value":206},{"type":32,"tag":63,"props":376,"children":377},{"style":106},[378],{"type":37,"value":333},{"type":32,"tag":63,"props":380,"children":381},{"style":76},[382],{"type":37,"value":216},{"type":32,"tag":63,"props":384,"children":385},{"style":70},[386],{"type":37,"value":387},"DAY",{"type":32,"tag":63,"props":389,"children":390},{"style":76},[391],{"type":37,"value":243},{"type":32,"tag":63,"props":393,"children":394},{"style":70},[395],{"type":37,"value":84},{"type":32,"tag":63,"props":397,"children":398},{"style":76},[399],{"type":37,"value":400}," day_n,\n",{"type":32,"tag":63,"props":402,"children":404},{"class":65,"line":403},14,[405,410,414,419,424,428,432,436,440],{"type":32,"tag":63,"props":406,"children":407},{"style":106},[408],{"type":37,"value":409},"  COUNT",{"type":32,"tag":63,"props":411,"children":412},{"style":76},[413],{"type":37,"value":114},{"type":32,"tag":63,"props":415,"children":416},{"style":70},[417],{"type":37,"value":418},"DISTINCT",{"type":32,"tag":63,"props":420,"children":421},{"style":106},[422],{"type":37,"value":423}," d",{"type":32,"tag":63,"props":425,"children":426},{"style":76},[427],{"type":37,"value":206},{"type":32,"tag":63,"props":429,"children":430},{"style":106},[431],{"type":37,"value":211},{"type":32,"tag":63,"props":433,"children":434},{"style":76},[435],{"type":37,"value":243},{"type":32,"tag":63,"props":437,"children":438},{"style":70},[439],{"type":37,"value":84},{"type":32,"tag":63,"props":441,"children":442},{"style":76},[443],{"type":37,"value":444}," retained_users\n",{"type":32,"tag":63,"props":446,"children":448},{"class":65,"line":447},15,[449,454],{"type":32,"tag":63,"props":450,"children":451},{"style":70},[452],{"type":37,"value":453},"FROM",{"type":32,"tag":63,"props":455,"children":456},{"style":76},[457],{"type":37,"value":458}," first_event f\n",{"type":32,"tag":63,"props":460,"children":462},{"class":65,"line":461},16,[463,468,473,478],{"type":32,"tag":63,"props":464,"children":465},{"style":70},[466],{"type":37,"value":467},"JOIN",{"type":32,"tag":63,"props":469,"children":470},{"style":76},[471],{"type":37,"value":472}," daily_activity d ",{"type":32,"tag":63,"props":474,"children":475},{"style":70},[476],{"type":37,"value":477},"USING",{"type":32,"tag":63,"props":479,"children":480},{"style":76},[481],{"type":37,"value":482},"(user_id)\n",{"type":32,"tag":63,"props":484,"children":486},{"class":65,"line":485},17,[487,492,496,500],{"type":32,"tag":63,"props":488,"children":489},{"style":70},[490],{"type":37,"value":491},"GROUP BY",{"type":32,"tag":63,"props":493,"children":494},{"style":106},[495],{"type":37,"value":282},{"type":32,"tag":63,"props":497,"children":498},{"style":76},[499],{"type":37,"value":287},{"type":32,"tag":63,"props":501,"children":502},{"style":106},[503],{"type":37,"value":292},{"type":32,"tag":63,"props":505,"children":507},{"class":65,"line":506},18,[508,513,517,521,526],{"type":32,"tag":63,"props":509,"children":510},{"style":70},[511],{"type":37,"value":512},"ORDER BY",{"type":32,"tag":63,"props":514,"children":515},{"style":106},[516],{"type":37,"value":282},{"type":32,"tag":63,"props":518,"children":519},{"style":76},[520],{"type":37,"value":287},{"type":32,"tag":63,"props":522,"children":523},{"style":106},[524],{"type":37,"value":525},"2",{"type":32,"tag":63,"props":527,"children":528},{"style":76},[529],{"type":37,"value":530},";\n",{"type":32,"tag":33,"props":532,"children":533},{},[534,536,542],{"type":37,"value":535},"Two critical problems here: (1) the ",{"type":32,"tag":59,"props":537,"children":539},{"className":538},[],[540],{"type":37,"value":541},"events",{"type":37,"value":543}," table is fully scanned each time — no partition pruning, (2) for each cohort_date, all user activities are joined — Cartesian explosion risk. On 100M events, this query processes 400GB of data and completes in 2 minutes, but daily refresh at this cost is unsustainable. Your BigQuery bill explodes 10x by month-end.",{"type":32,"tag":40,"props":545,"children":547},{"id":546},"reduce-filter-burden-with-partitioned-base-table",[548],{"type":37,"value":549},"Reduce Filter Burden with Partitioned Base Table",{"type":32,"tag":33,"props":551,"children":552},{},[553,555,560,562,568,570,576],{"type":37,"value":554},"First step: partition the ",{"type":32,"tag":59,"props":556,"children":558},{"className":557},[],[559],{"type":37,"value":541},{"type":37,"value":561}," table by ",{"type":32,"tag":59,"props":563,"children":565},{"className":564},[],[566],{"type":37,"value":567},"DATE(event_timestamp)",{"type":37,"value":569},". This ensures only relevant partitions are scanned when a ",{"type":32,"tag":59,"props":571,"children":573},{"className":572},[],[574],{"type":37,"value":575},"WHERE DATE(event_timestamp) BETWEEN X AND Y",{"type":37,"value":577}," clause is added:",{"type":32,"tag":52,"props":579,"children":581},{"className":54,"code":580,"language":56,"meta":16,"style":16},"CREATE TABLE `project.dataset.events`\nPARTITION BY DATE(event_timestamp)\nCLUSTER BY user_id, event_name\nAS SELECT * FROM ...;\n",[582],{"type":32,"tag":59,"props":583,"children":584},{"__ignoreMap":16},[585,602,625,643],{"type":32,"tag":63,"props":586,"children":587},{"class":65,"line":66},[588,593,598],{"type":32,"tag":63,"props":589,"children":590},{"style":70},[591],{"type":37,"value":592},"CREATE",{"type":32,"tag":63,"props":594,"children":595},{"style":70},[596],{"type":37,"value":597}," TABLE",{"type":32,"tag":63,"props":599,"children":600},{"style":145},[601],{"type":37,"value":148},{"type":32,"tag":63,"props":603,"children":604},{"class":65,"line":92},[605,610,615,620],{"type":32,"tag":63,"props":606,"children":607},{"style":70},[608],{"type":37,"value":609},"PARTITION",{"type":32,"tag":63,"props":611,"children":612},{"style":70},[613],{"type":37,"value":614}," BY",{"type":32,"tag":63,"props":616,"children":617},{"style":70},[618],{"type":37,"value":619}," DATE",{"type":32,"tag":63,"props":621,"children":622},{"style":76},[623],{"type":37,"value":624},"(event_timestamp)\n",{"type":32,"tag":63,"props":626,"children":627},{"class":65,"line":136},[628,633,638],{"type":32,"tag":63,"props":629,"children":630},{"style":76},[631],{"type":37,"value":632},"CLUSTER ",{"type":32,"tag":63,"props":634,"children":635},{"style":70},[636],{"type":37,"value":637},"BY",{"type":32,"tag":63,"props":639,"children":640},{"style":76},[641],{"type":37,"value":642}," user_id, event_name\n",{"type":32,"tag":63,"props":644,"children":645},{"class":65,"line":151},[646,650,655,660,665],{"type":32,"tag":63,"props":647,"children":648},{"style":70},[649],{"type":37,"value":84},{"type":32,"tag":63,"props":651,"children":652},{"style":70},[653],{"type":37,"value":654}," SELECT",{"type":32,"tag":63,"props":656,"children":657},{"style":70},[658],{"type":37,"value":659}," *",{"type":32,"tag":63,"props":661,"children":662},{"style":70},[663],{"type":37,"value":664}," FROM",{"type":32,"tag":63,"props":666,"children":667},{"style":76},[668],{"type":37,"value":669}," ...;\n",{"type":32,"tag":33,"props":671,"children":672},{},[673],{"type":37,"value":674},"Clustering on (user_id, event_name) places the same user's events in physically adjacent blocks — join performance improves 30–50%. But this alone isn't enough; cohort calculation logic runs from scratch in every query. This is where materialized views enter.",{"type":32,"tag":40,"props":676,"children":678},{"id":677},"materialized-views-incremental-cohort-table",[679],{"type":37,"value":680},"Materialized Views: Incremental Cohort Table",{"type":32,"tag":33,"props":682,"children":683},{},[684],{"type":37,"value":685},"BigQuery materialized views store query results physically and auto-refresh when base tables change. For cohort analysis, use this structure:",{"type":32,"tag":52,"props":687,"children":689},{"className":54,"code":688,"language":56,"meta":16,"style":16},"CREATE MATERIALIZED VIEW `project.dataset.user_cohorts`\nPARTITION BY cohort_date\nCLUSTER BY user_id\nAS\nSELECT \n  user_id,\n  MIN(DATE(event_timestamp)) AS cohort_date,\n  COUNT(*) AS first_day_events\nFROM `project.dataset.events`\nGROUP BY user_id;\n",[690],{"type":32,"tag":59,"props":691,"children":692},{"__ignoreMap":16},[693,710,725,740,748,759,767,796,825,836],{"type":32,"tag":63,"props":694,"children":695},{"class":65,"line":66},[696,700,705],{"type":32,"tag":63,"props":697,"children":698},{"style":70},[699],{"type":37,"value":592},{"type":32,"tag":63,"props":701,"children":702},{"style":76},[703],{"type":37,"value":704}," MATERIALIZED VIEW ",{"type":32,"tag":63,"props":706,"children":707},{"style":145},[708],{"type":37,"value":709},"`project.dataset.user_cohorts`\n",{"type":32,"tag":63,"props":711,"children":712},{"class":65,"line":92},[713,717,721],{"type":32,"tag":63,"props":714,"children":715},{"style":70},[716],{"type":37,"value":609},{"type":32,"tag":63,"props":718,"children":719},{"style":70},[720],{"type":37,"value":614},{"type":32,"tag":63,"props":722,"children":723},{"style":76},[724],{"type":37,"value":133},{"type":32,"tag":63,"props":726,"children":727},{"class":65,"line":136},[728,732,736],{"type":32,"tag":63,"props":729,"children":730},{"style":76},[731],{"type":37,"value":632},{"type":32,"tag":63,"props":733,"children":734},{"style":70},[735],{"type":37,"value":637},{"type":32,"tag":63,"props":737,"children":738},{"style":76},[739],{"type":37,"value":162},{"type":32,"tag":63,"props":741,"children":742},{"class":65,"line":151},[743],{"type":32,"tag":63,"props":744,"children":745},{"style":70},[746],{"type":37,"value":747},"AS\n",{"type":32,"tag":63,"props":749,"children":750},{"class":65,"line":165},[751,755],{"type":32,"tag":63,"props":752,"children":753},{"style":70},[754],{"type":37,"value":310},{"type":32,"tag":63,"props":756,"children":757},{"style":76},[758],{"type":37,"value":315},{"type":32,"tag":63,"props":760,"children":761},{"class":65,"line":174},[762],{"type":32,"tag":63,"props":763,"children":764},{"style":76},[765],{"type":37,"value":766},"  user_id,\n",{"type":32,"tag":63,"props":768,"children":769},{"class":65,"line":191},[770,775,779,783,787,791],{"type":32,"tag":63,"props":771,"children":772},{"style":106},[773],{"type":37,"value":774},"  MIN",{"type":32,"tag":63,"props":776,"children":777},{"style":76},[778],{"type":37,"value":114},{"type":32,"tag":63,"props":780,"children":781},{"style":70},[782],{"type":37,"value":119},{"type":32,"tag":63,"props":784,"children":785},{"style":76},[786],{"type":37,"value":124},{"type":32,"tag":63,"props":788,"children":789},{"style":70},[790],{"type":37,"value":84},{"type":32,"tag":63,"props":792,"children":793},{"style":76},[794],{"type":37,"value":795}," cohort_date,\n",{"type":32,"tag":63,"props":797,"children":798},{"class":65,"line":26},[799,803,807,812,816,820],{"type":32,"tag":63,"props":800,"children":801},{"style":106},[802],{"type":37,"value":409},{"type":32,"tag":63,"props":804,"children":805},{"style":76},[806],{"type":37,"value":114},{"type":32,"tag":63,"props":808,"children":809},{"style":70},[810],{"type":37,"value":811},"*",{"type":32,"tag":63,"props":813,"children":814},{"style":76},[815],{"type":37,"value":243},{"type":32,"tag":63,"props":817,"children":818},{"style":70},[819],{"type":37,"value":84},{"type":32,"tag":63,"props":821,"children":822},{"style":76},[823],{"type":37,"value":824}," first_day_events\n",{"type":32,"tag":63,"props":826,"children":827},{"class":65,"line":272},[828,832],{"type":32,"tag":63,"props":829,"children":830},{"style":70},[831],{"type":37,"value":453},{"type":32,"tag":63,"props":833,"children":834},{"style":145},[835],{"type":37,"value":148},{"type":32,"tag":63,"props":837,"children":838},{"class":65,"line":295},[839,843],{"type":32,"tag":63,"props":840,"children":841},{"style":70},[842],{"type":37,"value":491},{"type":32,"tag":63,"props":844,"children":845},{"style":76},[846],{"type":37,"value":847}," user_id;\n",{"type":32,"tag":33,"props":849,"children":850},{},[851,853,859],{"type":37,"value":852},"This view calculates each user's first seen date (cohort_date) once and persists it. When new events arrive, BigQuery processes only the delta — no full rescan. Partitioning by cohort_date enables pruning in retention queries with ",{"type":32,"tag":59,"props":854,"children":856},{"className":855},[],[857],{"type":37,"value":858},"WHERE cohort_date = '2026-05-01'",{"type":37,"value":206},{"type":32,"tag":33,"props":861,"children":862},{},[863],{"type":37,"value":864},"Now the retention calculation query reduces to:",{"type":32,"tag":52,"props":866,"children":868},{"className":54,"code":867,"language":56,"meta":16,"style":16},"SELECT \n  c.cohort_date,\n  DATE_DIFF(DATE(e.event_timestamp), c.cohort_date, DAY) AS day_n,\n  COUNT(DISTINCT e.user_id) AS retained_users\nFROM `project.dataset.user_cohorts` c\nJOIN `project.dataset.events` e \n  ON c.user_id = e.user_id \n  AND DATE(e.event_timestamp) >= c.cohort_date\nWHERE c.cohort_date BETWEEN '2026-05-01' AND '2026-05-15'\nGROUP BY 1,2;\n",[869],{"type":32,"tag":59,"props":870,"children":871},{"__ignoreMap":16},[872,883,903,968,1007,1024,1040,1082,1132,1172],{"type":32,"tag":63,"props":873,"children":874},{"class":65,"line":66},[875,879],{"type":32,"tag":63,"props":876,"children":877},{"style":70},[878],{"type":37,"value":310},{"type":32,"tag":63,"props":880,"children":881},{"style":76},[882],{"type":37,"value":315},{"type":32,"tag":63,"props":884,"children":885},{"class":65,"line":92},[886,891,895,899],{"type":32,"tag":63,"props":887,"children":888},{"style":106},[889],{"type":37,"value":890},"  c",{"type":32,"tag":63,"props":892,"children":893},{"style":76},[894],{"type":37,"value":206},{"type":32,"tag":63,"props":896,"children":897},{"style":106},[898],{"type":37,"value":333},{"type":32,"tag":63,"props":900,"children":901},{"style":76},[902],{"type":37,"value":338},{"type":32,"tag":63,"props":904,"children":905},{"class":65,"line":136},[906,910,914,918,922,926,930,935,940,944,948,952,956,960,964],{"type":32,"tag":63,"props":907,"children":908},{"style":76},[909],{"type":37,"value":347},{"type":32,"tag":63,"props":911,"children":912},{"style":70},[913],{"type":37,"value":119},{"type":32,"tag":63,"props":915,"children":916},{"style":76},[917],{"type":37,"value":114},{"type":32,"tag":63,"props":919,"children":920},{"style":106},[921],{"type":37,"value":229},{"type":32,"tag":63,"props":923,"children":924},{"style":76},[925],{"type":37,"value":206},{"type":32,"tag":63,"props":927,"children":928},{"style":106},[929],{"type":37,"value":238},{"type":32,"tag":63,"props":931,"children":932},{"style":76},[933],{"type":37,"value":934},"), ",{"type":32,"tag":63,"props":936,"children":937},{"style":106},[938],{"type":37,"value":939},"c",{"type":32,"tag":63,"props":941,"children":942},{"style":76},[943],{"type":37,"value":206},{"type":32,"tag":63,"props":945,"children":946},{"style":106},[947],{"type":37,"value":333},{"type":32,"tag":63,"props":949,"children":950},{"style":76},[951],{"type":37,"value":216},{"type":32,"tag":63,"props":953,"children":954},{"style":70},[955],{"type":37,"value":387},{"type":32,"tag":63,"props":957,"children":958},{"style":76},[959],{"type":37,"value":243},{"type":32,"tag":63,"props":961,"children":962},{"style":70},[963],{"type":37,"value":84},{"type":32,"tag":63,"props":965,"children":966},{"style":76},[967],{"type":37,"value":400},{"type":32,"tag":63,"props":969,"children":970},{"class":65,"line":151},[971,975,979,983,987,991,995,999,1003],{"type":32,"tag":63,"props":972,"children":973},{"style":106},[974],{"type":37,"value":409},{"type":32,"tag":63,"props":976,"children":977},{"style":76},[978],{"type":37,"value":114},{"type":32,"tag":63,"props":980,"children":981},{"style":70},[982],{"type":37,"value":418},{"type":32,"tag":63,"props":984,"children":985},{"style":106},[986],{"type":37,"value":201},{"type":32,"tag":63,"props":988,"children":989},{"style":76},[990],{"type":37,"value":206},{"type":32,"tag":63,"props":992,"children":993},{"style":106},[994],{"type":37,"value":211},{"type":32,"tag":63,"props":996,"children":997},{"style":76},[998],{"type":37,"value":243},{"type":32,"tag":63,"props":1000,"children":1001},{"style":70},[1002],{"type":37,"value":84},{"type":32,"tag":63,"props":1004,"children":1005},{"style":76},[1006],{"type":37,"value":444},{"type":32,"tag":63,"props":1008,"children":1009},{"class":65,"line":165},[1010,1014,1019],{"type":32,"tag":63,"props":1011,"children":1012},{"style":70},[1013],{"type":37,"value":453},{"type":32,"tag":63,"props":1015,"children":1016},{"style":145},[1017],{"type":37,"value":1018}," `project.dataset.user_cohorts`",{"type":32,"tag":63,"props":1020,"children":1021},{"style":76},[1022],{"type":37,"value":1023}," c\n",{"type":32,"tag":63,"props":1025,"children":1026},{"class":65,"line":174},[1027,1031,1035],{"type":32,"tag":63,"props":1028,"children":1029},{"style":70},[1030],{"type":37,"value":467},{"type":32,"tag":63,"props":1032,"children":1033},{"style":145},[1034],{"type":37,"value":264},{"type":32,"tag":63,"props":1036,"children":1037},{"style":76},[1038],{"type":37,"value":1039}," e \n",{"type":32,"tag":63,"props":1041,"children":1042},{"class":65,"line":191},[1043,1048,1053,1057,1061,1066,1070,1074,1078],{"type":32,"tag":63,"props":1044,"children":1045},{"style":70},[1046],{"type":37,"value":1047},"  ON",{"type":32,"tag":63,"props":1049,"children":1050},{"style":106},[1051],{"type":37,"value":1052}," c",{"type":32,"tag":63,"props":1054,"children":1055},{"style":76},[1056],{"type":37,"value":206},{"type":32,"tag":63,"props":1058,"children":1059},{"style":106},[1060],{"type":37,"value":211},{"type":32,"tag":63,"props":1062,"children":1063},{"style":70},[1064],{"type":37,"value":1065}," =",{"type":32,"tag":63,"props":1067,"children":1068},{"style":106},[1069],{"type":37,"value":201},{"type":32,"tag":63,"props":1071,"children":1072},{"style":76},[1073],{"type":37,"value":206},{"type":32,"tag":63,"props":1075,"children":1076},{"style":106},[1077],{"type":37,"value":211},{"type":32,"tag":63,"props":1079,"children":1080},{"style":76},[1081],{"type":37,"value":315},{"type":32,"tag":63,"props":1083,"children":1084},{"class":65,"line":26},[1085,1090,1094,1098,1102,1106,1110,1114,1119,1123,1127],{"type":32,"tag":63,"props":1086,"children":1087},{"style":70},[1088],{"type":37,"value":1089},"  AND",{"type":32,"tag":63,"props":1091,"children":1092},{"style":70},[1093],{"type":37,"value":619},{"type":32,"tag":63,"props":1095,"children":1096},{"style":76},[1097],{"type":37,"value":114},{"type":32,"tag":63,"props":1099,"children":1100},{"style":106},[1101],{"type":37,"value":229},{"type":32,"tag":63,"props":1103,"children":1104},{"style":76},[1105],{"type":37,"value":206},{"type":32,"tag":63,"props":1107,"children":1108},{"style":106},[1109],{"type":37,"value":238},{"type":32,"tag":63,"props":1111,"children":1112},{"style":76},[1113],{"type":37,"value":243},{"type":32,"tag":63,"props":1115,"children":1116},{"style":70},[1117],{"type":37,"value":1118},">=",{"type":32,"tag":63,"props":1120,"children":1121},{"style":106},[1122],{"type":37,"value":1052},{"type":32,"tag":63,"props":1124,"children":1125},{"style":76},[1126],{"type":37,"value":206},{"type":32,"tag":63,"props":1128,"children":1129},{"style":106},[1130],{"type":37,"value":1131},"cohort_date\n",{"type":32,"tag":63,"props":1133,"children":1134},{"class":65,"line":272},[1135,1140,1144,1148,1152,1157,1162,1167],{"type":32,"tag":63,"props":1136,"children":1137},{"style":70},[1138],{"type":37,"value":1139},"WHERE",{"type":32,"tag":63,"props":1141,"children":1142},{"style":106},[1143],{"type":37,"value":1052},{"type":32,"tag":63,"props":1145,"children":1146},{"style":76},[1147],{"type":37,"value":206},{"type":32,"tag":63,"props":1149,"children":1150},{"style":106},[1151],{"type":37,"value":333},{"type":32,"tag":63,"props":1153,"children":1154},{"style":70},[1155],{"type":37,"value":1156}," BETWEEN",{"type":32,"tag":63,"props":1158,"children":1159},{"style":145},[1160],{"type":37,"value":1161}," '2026-05-01'",{"type":32,"tag":63,"props":1163,"children":1164},{"style":70},[1165],{"type":37,"value":1166}," AND",{"type":32,"tag":63,"props":1168,"children":1169},{"style":145},[1170],{"type":37,"value":1171}," '2026-05-15'\n",{"type":32,"tag":63,"props":1173,"children":1174},{"class":65,"line":295},[1175,1179,1183,1187,1191],{"type":32,"tag":63,"props":1176,"children":1177},{"style":70},[1178],{"type":37,"value":491},{"type":32,"tag":63,"props":1180,"children":1181},{"style":106},[1182],{"type":37,"value":282},{"type":32,"tag":63,"props":1184,"children":1185},{"style":76},[1186],{"type":37,"value":287},{"type":32,"tag":63,"props":1188,"children":1189},{"style":106},[1190],{"type":37,"value":525},{"type":32,"tag":63,"props":1192,"children":1193},{"style":76},[1194],{"type":37,"value":530},{"type":32,"tag":33,"props":1196,"children":1197},{},[1198],{"type":37,"value":1199},"This joins against the materialized view instead of the base table — rows scanned drop from millions to thousands. But it still scans the daily event table. The next layer introduces pre-aggregated retention.",{"type":32,"tag":40,"props":1201,"children":1203},{"id":1202},"pre-aggregated-retention-table-final-layer",[1204],{"type":37,"value":1205},"Pre-Aggregated Retention Table: Final Layer",{"type":32,"tag":33,"props":1207,"children":1208},{},[1209],{"type":37,"value":1210},"Cohort analysis typically examines fixed intervals — \"Day 0, Day 1, Day 7, Day 30\" — so you don't need to recalculate every day. Using dbt, apply this logic:",{"type":32,"tag":1212,"props":1213,"children":1214},"ol",{},[1215,1229,1234],{"type":32,"tag":1216,"props":1217,"children":1218},"li",{},[1219,1221,1227],{"type":37,"value":1220},"Each day, fetch new cohorts from the ",{"type":32,"tag":59,"props":1222,"children":1224},{"className":1223},[],[1225],{"type":37,"value":1226},"user_cohorts",{"type":37,"value":1228}," view",{"type":32,"tag":1216,"props":1230,"children":1231},{},[1232],{"type":37,"value":1233},"For each cohort, calculate past 30 days of retention (after the first 30 days complete, the result doesn't change)",{"type":32,"tag":1216,"props":1235,"children":1236},{},[1237,1239,1245,1247],{"type":37,"value":1238},"Write result to ",{"type":32,"tag":59,"props":1240,"children":1242},{"className":1241},[],[1243],{"type":37,"value":1244},"cohort_retention_summary",{"type":37,"value":1246}," table ",{"type":32,"tag":1248,"props":1249,"children":1250},"strong",{},[1251],{"type":37,"value":1252},"incrementally",{"type":32,"tag":33,"props":1254,"children":1255},{},[1256],{"type":37,"value":1257},"dbt model:",{"type":32,"tag":52,"props":1259,"children":1261},{"className":54,"code":1260,"language":56,"meta":16,"style":16},"{{\n  config(\n    materialized='incremental',\n    unique_key=['cohort_date','day_n'],\n    partition_by={'field':'cohort_date','data_type':'date'},\n    cluster_by=['day_n']\n  )\n}}\n\nWITH cohorts_to_update AS (\n  SELECT DISTINCT cohort_date \n  FROM {{ ref('user_cohorts') }}\n  WHERE cohort_date >= CURRENT_DATE() - 31\n  {% if is_incremental() %}\n    AND cohort_date > (SELECT MAX(cohort_date) FROM {{ this }})\n  {% endif %}\n),\nretention_calc AS (\n  SELECT \n    c.cohort_date,\n    DATE_DIFF(DATE(e.event_timestamp), c.cohort_date, DAY) AS day_n,\n    COUNT(DISTINCT e.user_id) AS retained_users,\n    MAX(c.first_day_events) AS cohort_size\n  FROM {{ ref('user_cohorts') }} c\n  JOIN {{ source('raw','events') }} e \n    ON c.user_id = e.user_id\n  WHERE c.cohort_date IN (SELECT cohort_date FROM cohorts_to_update)\n    AND DATE(e.event_timestamp) >= c.cohort_date\n    AND DATE_DIFF(DATE(e.event_timestamp), c.cohort_date, DAY) \u003C= 30\n  GROUP BY 1,2\n)\nSELECT \n  cohort_date,\n  day_n,\n  retained_users,\n  cohort_size,\n  SAFE_DIVIDE(retained_users, cohort_size) AS retention_rate\nFROM retention_calc;\n",[1262],{"type":32,"tag":59,"props":1263,"children":1264},{"__ignoreMap":16},[1265,1273,1281,1303,1320,1375,1392,1400,1408,1417,1437,1450,1472,1504,1522,1567,1575,1582,1598,1610,1631,1696,1738,1777,1798,1831,1869,1915,1963,2034,2054,2062,2074,2083,2092,2101,2110,2128],{"type":32,"tag":63,"props":1266,"children":1267},{"class":65,"line":66},[1268],{"type":32,"tag":63,"props":1269,"children":1270},{"style":76},[1271],{"type":37,"value":1272},"{{\n",{"type":32,"tag":63,"props":1274,"children":1275},{"class":65,"line":92},[1276],{"type":32,"tag":63,"props":1277,"children":1278},{"style":76},[1279],{"type":37,"value":1280},"  config(\n",{"type":32,"tag":63,"props":1282,"children":1283},{"class":65,"line":136},[1284,1289,1294,1299],{"type":32,"tag":63,"props":1285,"children":1286},{"style":76},[1287],{"type":37,"value":1288},"    materialized",{"type":32,"tag":63,"props":1290,"children":1291},{"style":70},[1292],{"type":37,"value":1293},"=",{"type":32,"tag":63,"props":1295,"children":1296},{"style":145},[1297],{"type":37,"value":1298},"'incremental'",{"type":32,"tag":63,"props":1300,"children":1301},{"style":76},[1302],{"type":37,"value":338},{"type":32,"tag":63,"props":1304,"children":1305},{"class":65,"line":151},[1306,1311,1315],{"type":32,"tag":63,"props":1307,"children":1308},{"style":76},[1309],{"type":37,"value":1310},"    unique_key",{"type":32,"tag":63,"props":1312,"children":1313},{"style":70},[1314],{"type":37,"value":1293},{"type":32,"tag":63,"props":1316,"children":1317},{"style":76},[1318],{"type":37,"value":1319},"['cohort_date','day_n'],\n",{"type":32,"tag":63,"props":1321,"children":1322},{"class":65,"line":165},[1323,1328,1332,1337,1342,1347,1352,1356,1361,1365,1370],{"type":32,"tag":63,"props":1324,"children":1325},{"style":76},[1326],{"type":37,"value":1327},"    partition_by",{"type":32,"tag":63,"props":1329,"children":1330},{"style":70},[1331],{"type":37,"value":1293},{"type":32,"tag":63,"props":1333,"children":1334},{"style":76},[1335],{"type":37,"value":1336},"{",{"type":32,"tag":63,"props":1338,"children":1339},{"style":145},[1340],{"type":37,"value":1341},"'field'",{"type":32,"tag":63,"props":1343,"children":1344},{"style":76},[1345],{"type":37,"value":1346},":",{"type":32,"tag":63,"props":1348,"children":1349},{"style":145},[1350],{"type":37,"value":1351},"'cohort_date'",{"type":32,"tag":63,"props":1353,"children":1354},{"style":76},[1355],{"type":37,"value":287},{"type":32,"tag":63,"props":1357,"children":1358},{"style":145},[1359],{"type":37,"value":1360},"'data_type'",{"type":32,"tag":63,"props":1362,"children":1363},{"style":76},[1364],{"type":37,"value":1346},{"type":32,"tag":63,"props":1366,"children":1367},{"style":145},[1368],{"type":37,"value":1369},"'date'",{"type":32,"tag":63,"props":1371,"children":1372},{"style":76},[1373],{"type":37,"value":1374},"},\n",{"type":32,"tag":63,"props":1376,"children":1377},{"class":65,"line":174},[1378,1383,1387],{"type":32,"tag":63,"props":1379,"children":1380},{"style":76},[1381],{"type":37,"value":1382},"    cluster_by",{"type":32,"tag":63,"props":1384,"children":1385},{"style":70},[1386],{"type":37,"value":1293},{"type":32,"tag":63,"props":1388,"children":1389},{"style":76},[1390],{"type":37,"value":1391},"['day_n']\n",{"type":32,"tag":63,"props":1393,"children":1394},{"class":65,"line":191},[1395],{"type":32,"tag":63,"props":1396,"children":1397},{"style":76},[1398],{"type":37,"value":1399},"  )\n",{"type":32,"tag":63,"props":1401,"children":1402},{"class":65,"line":26},[1403],{"type":32,"tag":63,"props":1404,"children":1405},{"style":76},[1406],{"type":37,"value":1407},"}}\n",{"type":32,"tag":63,"props":1409,"children":1410},{"class":65,"line":272},[1411],{"type":32,"tag":63,"props":1412,"children":1414},{"emptyLinePlaceholder":1413},true,[1415],{"type":37,"value":1416},"\n",{"type":32,"tag":63,"props":1418,"children":1419},{"class":65,"line":295},[1420,1424,1429,1433],{"type":32,"tag":63,"props":1421,"children":1422},{"style":70},[1423],{"type":37,"value":73},{"type":32,"tag":63,"props":1425,"children":1426},{"style":76},[1427],{"type":37,"value":1428}," cohorts_to_update ",{"type":32,"tag":63,"props":1430,"children":1431},{"style":70},[1432],{"type":37,"value":84},{"type":32,"tag":63,"props":1434,"children":1435},{"style":76},[1436],{"type":37,"value":89},{"type":32,"tag":63,"props":1438,"children":1439},{"class":65,"line":304},[1440,1445],{"type":32,"tag":63,"props":1441,"children":1442},{"style":70},[1443],{"type":37,"value":1444},"  SELECT DISTINCT",{"type":32,"tag":63,"props":1446,"children":1447},{"style":76},[1448],{"type":37,"value":1449}," cohort_date \n",{"type":32,"tag":63,"props":1451,"children":1452},{"class":65,"line":318},[1453,1457,1462,1467],{"type":32,"tag":63,"props":1454,"children":1455},{"style":70},[1456],{"type":37,"value":142},{"type":32,"tag":63,"props":1458,"children":1459},{"style":76},[1460],{"type":37,"value":1461}," {{ ref(",{"type":32,"tag":63,"props":1463,"children":1464},{"style":145},[1465],{"type":37,"value":1466},"'user_cohorts'",{"type":32,"tag":63,"props":1468,"children":1469},{"style":76},[1470],{"type":37,"value":1471},") }}\n",{"type":32,"tag":63,"props":1473,"children":1474},{"class":65,"line":341},[1475,1480,1485,1489,1494,1499],{"type":32,"tag":63,"props":1476,"children":1477},{"style":70},[1478],{"type":37,"value":1479},"  WHERE",{"type":32,"tag":63,"props":1481,"children":1482},{"style":76},[1483],{"type":37,"value":1484}," cohort_date ",{"type":32,"tag":63,"props":1486,"children":1487},{"style":70},[1488],{"type":37,"value":1118},{"type":32,"tag":63,"props":1490,"children":1491},{"style":76},[1492],{"type":37,"value":1493}," CURRENT_DATE() ",{"type":32,"tag":63,"props":1495,"children":1496},{"style":70},[1497],{"type":37,"value":1498},"-",{"type":32,"tag":63,"props":1500,"children":1501},{"style":106},[1502],{"type":37,"value":1503}," 31\n",{"type":32,"tag":63,"props":1505,"children":1506},{"class":65,"line":403},[1507,1512,1517],{"type":32,"tag":63,"props":1508,"children":1509},{"style":76},[1510],{"type":37,"value":1511},"  {% ",{"type":32,"tag":63,"props":1513,"children":1514},{"style":70},[1515],{"type":37,"value":1516},"if",{"type":32,"tag":63,"props":1518,"children":1519},{"style":76},[1520],{"type":37,"value":1521}," is_incremental() %}\n",{"type":32,"tag":63,"props":1523,"children":1524},{"class":65,"line":447},[1525,1530,1534,1539,1544,1548,1553,1558,1562],{"type":32,"tag":63,"props":1526,"children":1527},{"style":70},[1528],{"type":37,"value":1529},"    AND",{"type":32,"tag":63,"props":1531,"children":1532},{"style":76},[1533],{"type":37,"value":1484},{"type":32,"tag":63,"props":1535,"children":1536},{"style":70},[1537],{"type":37,"value":1538},">",{"type":32,"tag":63,"props":1540,"children":1541},{"style":76},[1542],{"type":37,"value":1543}," (",{"type":32,"tag":63,"props":1545,"children":1546},{"style":70},[1547],{"type":37,"value":310},{"type":32,"tag":63,"props":1549,"children":1550},{"style":106},[1551],{"type":37,"value":1552}," MAX",{"type":32,"tag":63,"props":1554,"children":1555},{"style":76},[1556],{"type":37,"value":1557},"(cohort_date) ",{"type":32,"tag":63,"props":1559,"children":1560},{"style":70},[1561],{"type":37,"value":453},{"type":32,"tag":63,"props":1563,"children":1564},{"style":76},[1565],{"type":37,"value":1566}," {{ this }})\n",{"type":32,"tag":63,"props":1568,"children":1569},{"class":65,"line":461},[1570],{"type":32,"tag":63,"props":1571,"children":1572},{"style":76},[1573],{"type":37,"value":1574},"  {% endif %}\n",{"type":32,"tag":63,"props":1576,"children":1577},{"class":65,"line":485},[1578],{"type":32,"tag":63,"props":1579,"children":1580},{"style":76},[1581],{"type":37,"value":171},{"type":32,"tag":63,"props":1583,"children":1584},{"class":65,"line":506},[1585,1590,1594],{"type":32,"tag":63,"props":1586,"children":1587},{"style":76},[1588],{"type":37,"value":1589},"retention_calc ",{"type":32,"tag":63,"props":1591,"children":1592},{"style":70},[1593],{"type":37,"value":84},{"type":32,"tag":63,"props":1595,"children":1596},{"style":76},[1597],{"type":37,"value":89},{"type":32,"tag":63,"props":1599,"children":1601},{"class":65,"line":1600},19,[1602,1606],{"type":32,"tag":63,"props":1603,"children":1604},{"style":70},[1605],{"type":37,"value":98},{"type":32,"tag":63,"props":1607,"children":1608},{"style":76},[1609],{"type":37,"value":315},{"type":32,"tag":63,"props":1611,"children":1613},{"class":65,"line":1612},20,[1614,1619,1623,1627],{"type":32,"tag":63,"props":1615,"children":1616},{"style":106},[1617],{"type":37,"value":1618},"    c",{"type":32,"tag":63,"props":1620,"children":1621},{"style":76},[1622],{"type":37,"value":206},{"type":32,"tag":63,"props":1624,"children":1625},{"style":106},[1626],{"type":37,"value":333},{"type":32,"tag":63,"props":1628,"children":1629},{"style":76},[1630],{"type":37,"value":338},{"type":32,"tag":63,"props":1632,"children":1634},{"class":65,"line":1633},21,[1635,1640,1644,1648,1652,1656,1660,1664,1668,1672,1676,1680,1684,1688,1692],{"type":32,"tag":63,"props":1636,"children":1637},{"style":76},[1638],{"type":37,"value":1639},"    DATE_DIFF(",{"type":32,"tag":63,"props":1641,"children":1642},{"style":70},[1643],{"type":37,"value":119},{"type":32,"tag":63,"props":1645,"children":1646},{"style":76},[1647],{"type":37,"value":114},{"type":32,"tag":63,"props":1649,"children":1650},{"style":106},[1651],{"type":37,"value":229},{"type":32,"tag":63,"props":1653,"children":1654},{"style":76},[1655],{"type":37,"value":206},{"type":32,"tag":63,"props":1657,"children":1658},{"style":106},[1659],{"type":37,"value":238},{"type":32,"tag":63,"props":1661,"children":1662},{"style":76},[1663],{"type":37,"value":934},{"type":32,"tag":63,"props":1665,"children":1666},{"style":106},[1667],{"type":37,"value":939},{"type":32,"tag":63,"props":1669,"children":1670},{"style":76},[1671],{"type":37,"value":206},{"type":32,"tag":63,"props":1673,"children":1674},{"style":106},[1675],{"type":37,"value":333},{"type":32,"tag":63,"props":1677,"children":1678},{"style":76},[1679],{"type":37,"value":216},{"type":32,"tag":63,"props":1681,"children":1682},{"style":70},[1683],{"type":37,"value":387},{"type":32,"tag":63,"props":1685,"children":1686},{"style":76},[1687],{"type":37,"value":243},{"type":32,"tag":63,"props":1689,"children":1690},{"style":70},[1691],{"type":37,"value":84},{"type":32,"tag":63,"props":1693,"children":1694},{"style":76},[1695],{"type":37,"value":400},{"type":32,"tag":63,"props":1697,"children":1699},{"class":65,"line":1698},22,[1700,1705,1709,1713,1717,1721,1725,1729,1733],{"type":32,"tag":63,"props":1701,"children":1702},{"style":106},[1703],{"type":37,"value":1704},"    COUNT",{"type":32,"tag":63,"props":1706,"children":1707},{"style":76},[1708],{"type":37,"value":114},{"type":32,"tag":63,"props":1710,"children":1711},{"style":70},[1712],{"type":37,"value":418},{"type":32,"tag":63,"props":1714,"children":1715},{"style":106},[1716],{"type":37,"value":201},{"type":32,"tag":63,"props":1718,"children":1719},{"style":76},[1720],{"type":37,"value":206},{"type":32,"tag":63,"props":1722,"children":1723},{"style":106},[1724],{"type":37,"value":211},{"type":32,"tag":63,"props":1726,"children":1727},{"style":76},[1728],{"type":37,"value":243},{"type":32,"tag":63,"props":1730,"children":1731},{"style":70},[1732],{"type":37,"value":84},{"type":32,"tag":63,"props":1734,"children":1735},{"style":76},[1736],{"type":37,"value":1737}," retained_users,\n",{"type":32,"tag":63,"props":1739,"children":1741},{"class":65,"line":1740},23,[1742,1747,1751,1755,1759,1764,1768,1772],{"type":32,"tag":63,"props":1743,"children":1744},{"style":106},[1745],{"type":37,"value":1746},"    MAX",{"type":32,"tag":63,"props":1748,"children":1749},{"style":76},[1750],{"type":37,"value":114},{"type":32,"tag":63,"props":1752,"children":1753},{"style":106},[1754],{"type":37,"value":939},{"type":32,"tag":63,"props":1756,"children":1757},{"style":76},[1758],{"type":37,"value":206},{"type":32,"tag":63,"props":1760,"children":1761},{"style":106},[1762],{"type":37,"value":1763},"first_day_events",{"type":32,"tag":63,"props":1765,"children":1766},{"style":76},[1767],{"type":37,"value":243},{"type":32,"tag":63,"props":1769,"children":1770},{"style":70},[1771],{"type":37,"value":84},{"type":32,"tag":63,"props":1773,"children":1774},{"style":76},[1775],{"type":37,"value":1776}," cohort_size\n",{"type":32,"tag":63,"props":1778,"children":1780},{"class":65,"line":1779},24,[1781,1785,1789,1793],{"type":32,"tag":63,"props":1782,"children":1783},{"style":70},[1784],{"type":37,"value":142},{"type":32,"tag":63,"props":1786,"children":1787},{"style":76},[1788],{"type":37,"value":1461},{"type":32,"tag":63,"props":1790,"children":1791},{"style":145},[1792],{"type":37,"value":1466},{"type":32,"tag":63,"props":1794,"children":1795},{"style":76},[1796],{"type":37,"value":1797},") }} c\n",{"type":32,"tag":63,"props":1799,"children":1801},{"class":65,"line":1800},25,[1802,1807,1812,1817,1821,1826],{"type":32,"tag":63,"props":1803,"children":1804},{"style":70},[1805],{"type":37,"value":1806},"  JOIN",{"type":32,"tag":63,"props":1808,"children":1809},{"style":76},[1810],{"type":37,"value":1811}," {{ source(",{"type":32,"tag":63,"props":1813,"children":1814},{"style":145},[1815],{"type":37,"value":1816},"'raw'",{"type":32,"tag":63,"props":1818,"children":1819},{"style":76},[1820],{"type":37,"value":287},{"type":32,"tag":63,"props":1822,"children":1823},{"style":145},[1824],{"type":37,"value":1825},"'events'",{"type":32,"tag":63,"props":1827,"children":1828},{"style":76},[1829],{"type":37,"value":1830},") }} e \n",{"type":32,"tag":63,"props":1832,"children":1834},{"class":65,"line":1833},26,[1835,1840,1844,1848,1852,1856,1860,1864],{"type":32,"tag":63,"props":1836,"children":1837},{"style":70},[1838],{"type":37,"value":1839},"    ON",{"type":32,"tag":63,"props":1841,"children":1842},{"style":106},[1843],{"type":37,"value":1052},{"type":32,"tag":63,"props":1845,"children":1846},{"style":76},[1847],{"type":37,"value":206},{"type":32,"tag":63,"props":1849,"children":1850},{"style":106},[1851],{"type":37,"value":211},{"type":32,"tag":63,"props":1853,"children":1854},{"style":70},[1855],{"type":37,"value":1065},{"type":32,"tag":63,"props":1857,"children":1858},{"style":106},[1859],{"type":37,"value":201},{"type":32,"tag":63,"props":1861,"children":1862},{"style":76},[1863],{"type":37,"value":206},{"type":32,"tag":63,"props":1865,"children":1866},{"style":106},[1867],{"type":37,"value":1868},"user_id\n",{"type":32,"tag":63,"props":1870,"children":1872},{"class":65,"line":1871},27,[1873,1877,1881,1885,1889,1894,1898,1902,1906,1910],{"type":32,"tag":63,"props":1874,"children":1875},{"style":70},[1876],{"type":37,"value":1479},{"type":32,"tag":63,"props":1878,"children":1879},{"style":106},[1880],{"type":37,"value":1052},{"type":32,"tag":63,"props":1882,"children":1883},{"style":76},[1884],{"type":37,"value":206},{"type":32,"tag":63,"props":1886,"children":1887},{"style":106},[1888],{"type":37,"value":333},{"type":32,"tag":63,"props":1890,"children":1891},{"style":70},[1892],{"type":37,"value":1893}," IN",{"type":32,"tag":63,"props":1895,"children":1896},{"style":76},[1897],{"type":37,"value":1543},{"type":32,"tag":63,"props":1899,"children":1900},{"style":70},[1901],{"type":37,"value":310},{"type":32,"tag":63,"props":1903,"children":1904},{"style":76},[1905],{"type":37,"value":1484},{"type":32,"tag":63,"props":1907,"children":1908},{"style":70},[1909],{"type":37,"value":453},{"type":32,"tag":63,"props":1911,"children":1912},{"style":76},[1913],{"type":37,"value":1914}," cohorts_to_update)\n",{"type":32,"tag":63,"props":1916,"children":1918},{"class":65,"line":1917},28,[1919,1923,1927,1931,1935,1939,1943,1947,1951,1955,1959],{"type":32,"tag":63,"props":1920,"children":1921},{"style":70},[1922],{"type":37,"value":1529},{"type":32,"tag":63,"props":1924,"children":1925},{"style":70},[1926],{"type":37,"value":619},{"type":32,"tag":63,"props":1928,"children":1929},{"style":76},[1930],{"type":37,"value":114},{"type":32,"tag":63,"props":1932,"children":1933},{"style":106},[1934],{"type":37,"value":229},{"type":32,"tag":63,"props":1936,"children":1937},{"style":76},[1938],{"type":37,"value":206},{"type":32,"tag":63,"props":1940,"children":1941},{"style":106},[1942],{"type":37,"value":238},{"type":32,"tag":63,"props":1944,"children":1945},{"style":76},[1946],{"type":37,"value":243},{"type":32,"tag":63,"props":1948,"children":1949},{"style":70},[1950],{"type":37,"value":1118},{"type":32,"tag":63,"props":1952,"children":1953},{"style":106},[1954],{"type":37,"value":1052},{"type":32,"tag":63,"props":1956,"children":1957},{"style":76},[1958],{"type":37,"value":206},{"type":32,"tag":63,"props":1960,"children":1961},{"style":106},[1962],{"type":37,"value":1131},{"type":32,"tag":63,"props":1964,"children":1966},{"class":65,"line":1965},29,[1967,1971,1976,1980,1984,1988,1992,1996,2000,2004,2008,2012,2016,2020,2024,2029],{"type":32,"tag":63,"props":1968,"children":1969},{"style":70},[1970],{"type":37,"value":1529},{"type":32,"tag":63,"props":1972,"children":1973},{"style":76},[1974],{"type":37,"value":1975}," DATE_DIFF(",{"type":32,"tag":63,"props":1977,"children":1978},{"style":70},[1979],{"type":37,"value":119},{"type":32,"tag":63,"props":1981,"children":1982},{"style":76},[1983],{"type":37,"value":114},{"type":32,"tag":63,"props":1985,"children":1986},{"style":106},[1987],{"type":37,"value":229},{"type":32,"tag":63,"props":1989,"children":1990},{"style":76},[1991],{"type":37,"value":206},{"type":32,"tag":63,"props":1993,"children":1994},{"style":106},[1995],{"type":37,"value":238},{"type":32,"tag":63,"props":1997,"children":1998},{"style":76},[1999],{"type":37,"value":934},{"type":32,"tag":63,"props":2001,"children":2002},{"style":106},[2003],{"type":37,"value":939},{"type":32,"tag":63,"props":2005,"children":2006},{"style":76},[2007],{"type":37,"value":206},{"type":32,"tag":63,"props":2009,"children":2010},{"style":106},[2011],{"type":37,"value":333},{"type":32,"tag":63,"props":2013,"children":2014},{"style":76},[2015],{"type":37,"value":216},{"type":32,"tag":63,"props":2017,"children":2018},{"style":70},[2019],{"type":37,"value":387},{"type":32,"tag":63,"props":2021,"children":2022},{"style":76},[2023],{"type":37,"value":243},{"type":32,"tag":63,"props":2025,"children":2026},{"style":70},[2027],{"type":37,"value":2028},"\u003C=",{"type":32,"tag":63,"props":2030,"children":2031},{"style":106},[2032],{"type":37,"value":2033}," 30\n",{"type":32,"tag":63,"props":2035,"children":2037},{"class":65,"line":2036},30,[2038,2042,2046,2050],{"type":32,"tag":63,"props":2039,"children":2040},{"style":70},[2041],{"type":37,"value":157},{"type":32,"tag":63,"props":2043,"children":2044},{"style":106},[2045],{"type":37,"value":282},{"type":32,"tag":63,"props":2047,"children":2048},{"style":76},[2049],{"type":37,"value":287},{"type":32,"tag":63,"props":2051,"children":2052},{"style":106},[2053],{"type":37,"value":292},{"type":32,"tag":63,"props":2055,"children":2057},{"class":65,"line":2056},31,[2058],{"type":32,"tag":63,"props":2059,"children":2060},{"style":76},[2061],{"type":37,"value":301},{"type":32,"tag":63,"props":2063,"children":2065},{"class":65,"line":2064},32,[2066,2070],{"type":32,"tag":63,"props":2067,"children":2068},{"style":70},[2069],{"type":37,"value":310},{"type":32,"tag":63,"props":2071,"children":2072},{"style":76},[2073],{"type":37,"value":315},{"type":32,"tag":63,"props":2075,"children":2077},{"class":65,"line":2076},33,[2078],{"type":32,"tag":63,"props":2079,"children":2080},{"style":76},[2081],{"type":37,"value":2082},"  cohort_date,\n",{"type":32,"tag":63,"props":2084,"children":2086},{"class":65,"line":2085},34,[2087],{"type":32,"tag":63,"props":2088,"children":2089},{"style":76},[2090],{"type":37,"value":2091},"  day_n,\n",{"type":32,"tag":63,"props":2093,"children":2095},{"class":65,"line":2094},35,[2096],{"type":32,"tag":63,"props":2097,"children":2098},{"style":76},[2099],{"type":37,"value":2100},"  retained_users,\n",{"type":32,"tag":63,"props":2102,"children":2104},{"class":65,"line":2103},36,[2105],{"type":32,"tag":63,"props":2106,"children":2107},{"style":76},[2108],{"type":37,"value":2109},"  cohort_size,\n",{"type":32,"tag":63,"props":2111,"children":2113},{"class":65,"line":2112},37,[2114,2119,2123],{"type":32,"tag":63,"props":2115,"children":2116},{"style":76},[2117],{"type":37,"value":2118},"  SAFE_DIVIDE(retained_users, cohort_size) ",{"type":32,"tag":63,"props":2120,"children":2121},{"style":70},[2122],{"type":37,"value":84},{"type":32,"tag":63,"props":2124,"children":2125},{"style":76},[2126],{"type":37,"value":2127}," retention_rate\n",{"type":32,"tag":63,"props":2129,"children":2131},{"class":65,"line":2130},38,[2132,2136],{"type":32,"tag":63,"props":2133,"children":2134},{"style":70},[2135],{"type":37,"value":453},{"type":32,"tag":63,"props":2137,"children":2138},{"style":76},[2139],{"type":37,"value":2140}," retention_calc;\n",{"type":32,"tag":33,"props":2142,"children":2143},{},[2144,2146,2155],{"type":37,"value":2145},"This model updates only the last 31 days of cohorts each day. For cohorts older than 31 days, retention is stable — no recalculation needed. Slot usage drops 95%. In ",{"type":32,"tag":2147,"props":2148,"children":2152},"a",{"href":2149,"rel":2150},"https:\u002F\u002Fwww.roibase.com.tr\u002Fen\u002Fretention-engineering-cdp",[2151],"nofollow",[2153],{"type":37,"value":2154},"CDP & Retention Engineering",{"type":37,"value":2156}," workflows, this table connects directly to dashboards — BI tools (Looker, Metabase) return results in 100ms.",{"type":32,"tag":40,"props":2158,"children":2160},{"id":2159},"query-cost-and-partition-expiration-strategy",[2161],{"type":37,"value":2162},"Query Cost and Partition Expiration Strategy",{"type":32,"tag":33,"props":2164,"children":2165},{},[2166],{"type":37,"value":2167},"In BigQuery, storage is cheap ($0.02\u002FGB\u002Fmonth), compute is expensive ($5\u002FTB scanned). Since retention analysis is retrospective, old partitions get scanned frequently. Two optimizations:",{"type":32,"tag":1212,"props":2169,"children":2170},{},[2171,2188],{"type":32,"tag":1216,"props":2172,"children":2173},{},[2174,2179,2181,2186],{"type":32,"tag":1248,"props":2175,"children":2176},{},[2177],{"type":37,"value":2178},"Partition expiration:",{"type":37,"value":2180}," Automatically delete partitions older than 90 days from ",{"type":32,"tag":59,"props":2182,"children":2184},{"className":2183},[],[2185],{"type":37,"value":541},{"type":37,"value":2187}," — cohort calculation finishes before raw events are no longer needed.",{"type":32,"tag":1216,"props":2189,"children":2190},{},[2191,2196,2198,2204],{"type":32,"tag":1248,"props":2192,"children":2193},{},[2194],{"type":37,"value":2195},"Periodically refresh clustering statistics:",{"type":37,"value":2197}," ",{"type":32,"tag":59,"props":2199,"children":2201},{"className":2200},[],[2202],{"type":37,"value":2203},"ANALYZE TABLE ... UPDATE STATISTICS",{"type":37,"value":2205}," — query optimizer chooses better execution plans.",{"type":32,"tag":33,"props":2207,"children":2208},{},[2209],{"type":37,"value":2210},"Example cost comparison (100M events\u002Fday, 1M users):",{"type":32,"tag":2212,"props":2213,"children":2214},"table",{},[2215,2239],{"type":32,"tag":2216,"props":2217,"children":2218},"thead",{},[2219],{"type":32,"tag":2220,"props":2221,"children":2222},"tr",{},[2223,2229,2234],{"type":32,"tag":2224,"props":2225,"children":2226},"th",{},[2227],{"type":37,"value":2228},"Method",{"type":32,"tag":2224,"props":2230,"children":2231},{},[2232],{"type":37,"value":2233},"Data scanned\u002Fday",{"type":32,"tag":2224,"props":2235,"children":2236},{},[2237],{"type":37,"value":2238},"Monthly compute cost",{"type":32,"tag":2240,"props":2241,"children":2242},"tbody",{},[2243,2262,2280],{"type":32,"tag":2220,"props":2244,"children":2245},{},[2246,2252,2257],{"type":32,"tag":2247,"props":2248,"children":2249},"td",{},[2250],{"type":37,"value":2251},"Naive query (full scan)",{"type":32,"tag":2247,"props":2253,"children":2254},{},[2255],{"type":37,"value":2256},"12TB",{"type":32,"tag":2247,"props":2258,"children":2259},{},[2260],{"type":37,"value":2261},"$600",{"type":32,"tag":2220,"props":2263,"children":2264},{},[2265,2270,2275],{"type":32,"tag":2247,"props":2266,"children":2267},{},[2268],{"type":37,"value":2269},"Partitioned + materialized view",{"type":32,"tag":2247,"props":2271,"children":2272},{},[2273],{"type":37,"value":2274},"800GB",{"type":32,"tag":2247,"props":2276,"children":2277},{},[2278],{"type":37,"value":2279},"$40",{"type":32,"tag":2220,"props":2281,"children":2282},{},[2283,2288,2293],{"type":32,"tag":2247,"props":2284,"children":2285},{},[2286],{"type":37,"value":2287},"Pre-aggregated table (incremental)",{"type":32,"tag":2247,"props":2289,"children":2290},{},[2291],{"type":37,"value":2292},"50GB",{"type":32,"tag":2247,"props":2294,"children":2295},{},[2296],{"type":37,"value":2297},"$2.50",{"type":32,"tag":33,"props":2299,"children":2300},{},[2301],{"type":37,"value":2302},"Adding the pre-aggregate layer reduces compute costs 240x. This difference is critical in production — especially if retention analysis refreshes hourly.",{"type":32,"tag":40,"props":2304,"children":2306},{"id":2305},"real-time-cohort-analysis-tradeoff",[2307],{"type":37,"value":2308},"Real-Time Cohort Analysis Tradeoff",{"type":32,"tag":33,"props":2310,"children":2311},{},[2312],{"type":37,"value":2313},"Materialized views and pre-aggregate structures introduce latency: data lags 1–5 minutes. If real-time cohort analysis is required (e.g., for the first 24 hours), use a hybrid approach:",{"type":32,"tag":2315,"props":2316,"children":2317},"ul",{},[2318,2323],{"type":32,"tag":1216,"props":2319,"children":2320},{},[2321],{"type":37,"value":2322},"For last 24 hours: streaming inserts + real-time query (cache disabled)",{"type":32,"tag":1216,"props":2324,"children":2325},{},[2326],{"type":37,"value":2327},"For older data: pre-aggregate table",{"type":32,"tag":33,"props":2329,"children":2330},{},[2331],{"type":37,"value":2332},"The BI query unions both sources:",{"type":32,"tag":52,"props":2334,"children":2336},{"className":54,"code":2335,"language":56,"meta":16,"style":16},"SELECT * FROM cohort_retention_summary WHERE cohort_date \u003C CURRENT_DATE()\nUNION ALL\nSELECT * FROM realtime_cohort_view WHERE cohort_date = CURRENT_DATE();\n",[2337],{"type":32,"tag":59,"props":2338,"children":2339},{"__ignoreMap":16},[2340,2378,2386],{"type":32,"tag":63,"props":2341,"children":2342},{"class":65,"line":66},[2343,2347,2351,2355,2360,2364,2368,2373],{"type":32,"tag":63,"props":2344,"children":2345},{"style":70},[2346],{"type":37,"value":310},{"type":32,"tag":63,"props":2348,"children":2349},{"style":70},[2350],{"type":37,"value":659},{"type":32,"tag":63,"props":2352,"children":2353},{"style":70},[2354],{"type":37,"value":664},{"type":32,"tag":63,"props":2356,"children":2357},{"style":76},[2358],{"type":37,"value":2359}," cohort_retention_summary ",{"type":32,"tag":63,"props":2361,"children":2362},{"style":70},[2363],{"type":37,"value":1139},{"type":32,"tag":63,"props":2365,"children":2366},{"style":76},[2367],{"type":37,"value":1484},{"type":32,"tag":63,"props":2369,"children":2370},{"style":70},[2371],{"type":37,"value":2372},"\u003C",{"type":32,"tag":63,"props":2374,"children":2375},{"style":76},[2376],{"type":37,"value":2377}," CURRENT_DATE()\n",{"type":32,"tag":63,"props":2379,"children":2380},{"class":65,"line":92},[2381],{"type":32,"tag":63,"props":2382,"children":2383},{"style":70},[2384],{"type":37,"value":2385},"UNION ALL\n",{"type":32,"tag":63,"props":2387,"children":2388},{"class":65,"line":136},[2389,2393,2397,2401,2406,2410,2414,2418],{"type":32,"tag":63,"props":2390,"children":2391},{"style":70},[2392],{"type":37,"value":310},{"type":32,"tag":63,"props":2394,"children":2395},{"style":70},[2396],{"type":37,"value":659},{"type":32,"tag":63,"props":2398,"children":2399},{"style":70},[2400],{"type":37,"value":664},{"type":32,"tag":63,"props":2402,"children":2403},{"style":76},[2404],{"type":37,"value":2405}," realtime_cohort_view ",{"type":32,"tag":63,"props":2407,"children":2408},{"style":70},[2409],{"type":37,"value":1139},{"type":32,"tag":63,"props":2411,"children":2412},{"style":76},[2413],{"type":37,"value":1484},{"type":32,"tag":63,"props":2415,"children":2416},{"style":70},[2417],{"type":37,"value":1293},{"type":32,"tag":63,"props":2419,"children":2420},{"style":76},[2421],{"type":37,"value":2422}," CURRENT_DATE();\n",{"type":32,"tag":33,"props":2424,"children":2425},{},[2426],{"type":37,"value":2427},"Real-time views are expensive, but running only for the current cohort keeps total compute impact manageable.",{"type":32,"tag":40,"props":2429,"children":2431},{"id":2430},"cohort-segmentation-and-cardinality-explosion",[2432],{"type":37,"value":2433},"Cohort Segmentation and Cardinality Explosion",{"type":32,"tag":33,"props":2435,"children":2436},{},[2437],{"type":37,"value":2438},"Slicing retention by user segments (platform, country, acquisition channel) can trigger cardinality issues. For example, 5 segments × 30 days × 365 cohorts = 54,750 unique rows. In this case:",{"type":32,"tag":1212,"props":2440,"children":2441},{},[2442,2452,2462],{"type":32,"tag":1216,"props":2443,"children":2444},{},[2445,2450],{"type":32,"tag":1248,"props":2446,"children":2447},{},[2448],{"type":37,"value":2449},"Limit segment count:",{"type":37,"value":2451}," Analyze the 3–5 most important segments; create separate tables for others.",{"type":32,"tag":1216,"props":2453,"children":2454},{},[2455,2460],{"type":32,"tag":1248,"props":2456,"children":2457},{},[2458],{"type":37,"value":2459},"Dynamic segmentation:",{"type":37,"value":2461}," Instead of pre-aggregating segments, use join-time filtering — preserves query flexibility but increases slot usage.",{"type":32,"tag":1216,"props":2463,"children":2464},{},[2465,2470],{"type":32,"tag":1248,"props":2466,"children":2467},{},[2468],{"type":37,"value":2469},"Rollup table:",{"type":37,"value":2471}," Create a separate table for weekly cohorts (weekly_cohort_retention) — cardinality drops 85%.",{"type":32,"tag":33,"props":2473,"children":2474},{},[2475,2477,2484],{"type":37,"value":2476},"In Roibase's ",{"type":32,"tag":2147,"props":2478,"children":2481},{"href":2479,"rel":2480},"https:\u002F\u002Fwww.roibase.com.tr\u002Fen\u002Fverianalizi",[2151],[2482],{"type":37,"value":2483},"Data Analytics & Insight Engineering",{"type":37,"value":2485}," process, we tie segment strategy to acquisition source attribution — cohort analysis links directly to channel performance.",{"type":32,"tag":40,"props":2487,"children":2489},{"id":2488},"monitoring-and-regression-detection",[2490],{"type":37,"value":2491},"Monitoring and Regression Detection",{"type":32,"tag":33,"props":2493,"children":2494},{},[2495],{"type":37,"value":2496},"Monitor your production cohort pipeline with these metrics:",{"type":32,"tag":2315,"props":2498,"children":2499},{},[2500,2510,2520],{"type":32,"tag":1216,"props":2501,"children":2502},{},[2503,2508],{"type":32,"tag":1248,"props":2504,"children":2505},{},[2506],{"type":37,"value":2507},"Query slot time:",{"type":37,"value":2509}," BigQuery slot consumption for daily refresh — sudden spikes indicate cardinality explosion or lost partition pruning.",{"type":32,"tag":1216,"props":2511,"children":2512},{},[2513,2518],{"type":32,"tag":1248,"props":2514,"children":2515},{},[2516],{"type":37,"value":2517},"Row count delta:",{"type":37,"value":2519}," Rows added per refresh — unexpectedly high values signal duplicate events.",{"type":32,"tag":1216,"props":2521,"children":2522},{},[2523,2528],{"type":32,"tag":1248,"props":2524,"children":2525},{},[2526],{"type":37,"value":2527},"Retention rate stddev:",{"type":37,"value":2529}," Day 1 retention shifts >10% suddenly? Data quality red flag.",{"type":32,"tag":33,"props":2531,"children":2532},{},[2533],{"type":37,"value":2534},"Add these checks as dbt tests:",{"type":32,"tag":52,"props":2536,"children":2540},{"className":2537,"code":2538,"language":2539,"meta":16,"style":16},"language-yaml shiki shiki-themes github-dark","tests:\n  - dbt_utils.expression_is_true:\n      expression: \"retention_rate BETWEEN 0 AND 1\"\n  - dbt_utils.recency:\n      datepart: day\n      field: cohort_date\n      interval: 1\n","yaml",[2541],{"type":32,"tag":59,"props":2542,"children":2543},{"__ignoreMap":16},[2544,2558,2575,2593,2609,2626,2642],{"type":32,"tag":63,"props":2545,"children":2546},{"class":65,"line":66},[2547,2553],{"type":32,"tag":63,"props":2548,"children":2550},{"style":2549},"--shiki-default:#85E89D",[2551],{"type":37,"value":2552},"tests",{"type":32,"tag":63,"props":2554,"children":2555},{"style":76},[2556],{"type":37,"value":2557},":\n",{"type":32,"tag":63,"props":2559,"children":2560},{"class":65,"line":92},[2561,2566,2571],{"type":32,"tag":63,"props":2562,"children":2563},{"style":76},[2564],{"type":37,"value":2565},"  - ",{"type":32,"tag":63,"props":2567,"children":2568},{"style":2549},[2569],{"type":37,"value":2570},"dbt_utils.expression_is_true",{"type":32,"tag":63,"props":2572,"children":2573},{"style":76},[2574],{"type":37,"value":2557},{"type":32,"tag":63,"props":2576,"children":2577},{"class":65,"line":136},[2578,2583,2588],{"type":32,"tag":63,"props":2579,"children":2580},{"style":2549},[2581],{"type":37,"value":2582},"      expression",{"type":32,"tag":63,"props":2584,"children":2585},{"style":76},[2586],{"type":37,"value":2587},": ",{"type":32,"tag":63,"props":2589,"children":2590},{"style":145},[2591],{"type":37,"value":2592},"\"retention_rate BETWEEN 0 AND 1\"\n",{"type":32,"tag":63,"props":2594,"children":2595},{"class":65,"line":151},[2596,2600,2605],{"type":32,"tag":63,"props":2597,"children":2598},{"style":76},[2599],{"type":37,"value":2565},{"type":32,"tag":63,"props":2601,"children":2602},{"style":2549},[2603],{"type":37,"value":2604},"dbt_utils.recency",{"type":32,"tag":63,"props":2606,"children":2607},{"style":76},[2608],{"type":37,"value":2557},{"type":32,"tag":63,"props":2610,"children":2611},{"class":65,"line":165},[2612,2617,2621],{"type":32,"tag":63,"props":2613,"children":2614},{"style":2549},[2615],{"type":37,"value":2616},"      datepart",{"type":32,"tag":63,"props":2618,"children":2619},{"style":76},[2620],{"type":37,"value":2587},{"type":32,"tag":63,"props":2622,"children":2623},{"style":145},[2624],{"type":37,"value":2625},"day\n",{"type":32,"tag":63,"props":2627,"children":2628},{"class":65,"line":174},[2629,2634,2638],{"type":32,"tag":63,"props":2630,"children":2631},{"style":2549},[2632],{"type":37,"value":2633},"      field",{"type":32,"tag":63,"props":2635,"children":2636},{"style":76},[2637],{"type":37,"value":2587},{"type":32,"tag":63,"props":2639,"children":2640},{"style":145},[2641],{"type":37,"value":1131},{"type":32,"tag":63,"props":2643,"children":2644},{"class":65,"line":191},[2645,2650,2654],{"type":32,"tag":63,"props":2646,"children":2647},{"style":2549},[2648],{"type":37,"value":2649},"      interval",{"type":32,"tag":63,"props":2651,"children":2652},{"style":76},[2653],{"type":37,"value":2587},{"type":32,"tag":63,"props":2655,"children":2656},{"style":106},[2657],{"type":37,"value":2658},"1\n",{"type":32,"tag":33,"props":2660,"children":2661},{},[2662],{"type":37,"value":2663},"Test failures trigger Slack\u002FPagerDuty alerts — no manual monitoring required.",{"type":32,"tag":33,"props":2665,"children":2666},{},[2667],{"type":37,"value":2668},"Cohort table architecture elevates retention analysis from \"ad-hoc query\" to \"production data product.\" Materialized views with incremental refresh, partitioning for query pruning, pre-aggregation for slot optimization — each layer reduces cost 10x. Running retention analysis across millions of users and billions of events now compresses into a 100ms dashboard query. Deciding which retention patterns to monitor remains your responsibility — but processing that data at this speed is now an engineering non-issue.",{"type":32,"tag":2670,"props":2671,"children":2672},"style",{},[2673],{"type":37,"value":2674},"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":16,"searchDepth":136,"depth":136,"links":2676},[2677,2678,2679,2680,2681,2682,2683,2684],{"id":42,"depth":92,"text":45},{"id":546,"depth":92,"text":549},{"id":677,"depth":92,"text":680},{"id":1202,"depth":92,"text":1205},{"id":2159,"depth":92,"text":2162},{"id":2305,"depth":92,"text":2308},{"id":2430,"depth":92,"text":2433},{"id":2488,"depth":92,"text":2491},"markdown","content:en:data:cohort-table-architecture-scaling-retention-analysis-production.md","content","en\u002Fdata\u002Fcohort-table-architecture-scaling-retention-analysis-production.md","en\u002Fdata\u002Fcohort-table-architecture-scaling-retention-analysis-production","md",1780898611528]