[{"data":1,"prerenderedAt":1963},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fru\u002Fdata\u002Farkhitektura-tablitsy-kogort-masshtabirovanie-analiza-sokhraneniya-v-production":13},{"i18nKey":4,"paths":5},"data-007-2026-07",{"de":6,"en":7,"es":8,"fr":9,"it":10,"ru":11,"tr":12},"\u002Fde\u002Fdata\u002Fcohort-table-architecture-production-retention-scaling","\u002Fen\u002Fdata\u002Fcohort-table-architecture-scaling-retention-analysis-production","\u002Fes\u002Fdata\u002Farquitectura-tabla-cohorte-escalando-analisis-retencion","\u002Ffr\u002Fdata\u002Farchitecture-table-cohort-analyse-retention","\u002Fit\u002Fdata\u002Farchitettura-tabella-cohort-scalabilita-retention-analysis-production","\u002Fru\u002Fdata\u002Farkhitektura-tablitsy-kogort-masshtabirovanie-analiza-sokhraneniya-v-production","\u002Ftr\u002Fdata\u002Fcohort-tablo-mimarisi-retention-analizinin-productionda-olceklenmesi",{"_path":11,"_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":1957,"_id":1958,"_source":1959,"_file":1960,"_stem":1961,"_extension":1962},"data",false,"","Архитектура таблицы когорт: масштабирование анализа сохранения в production","Как масштабировать анализ когорт в production-среде с помощью материализованных представлений, партиционирования и оптимизации стоимости запросов? Конкретная архитектура таблиц в BigQuery и dbt.","2026-07-12",[21,22,23,24,25],"analiz-kogort","bigquery","materializovannye-predstavleniya","optimizaciya-zaprosov","retention",9,"Roibase",{"type":29,"children":30,"toc":1947},"root",[31,39,46,51,56,61,67,89,107,122,148,333,339,344,365,378,1437,1442,1449,1454,1459,1495,1508,1514,1519,1529,1539,1551,1556,1562,1567,1605,1764,1769,1868,1874,1879,1936,1941],{"type":32,"tag":33,"props":34,"children":35},"element","p",{},[36],{"type":37,"value":38},"text","Анализ сохранения — одна из самых критических метрик в маркетинговых данных. Чтобы понять, какая группа пользователей остаётся активной и какая кампания создаёт долгосрочную ценность, нужны таблицы когорт. Проблема в том, что классические запросы когорт на десятках миллионов строк событийных данных запускаются каждый раз заново, и стоимость запроса становится астрономической. Построить архитектуру когорт в production — такую, которая обновляется каждое утро, отвечает аналитику за 3 секунды, но при этом минимизирует затраты через правильную стратегию партиционирования — это отдельная инженерная задача. В этой статье мы пошагово разберём конкретную архитектуру таблиц когорт в BigQuery и dbt, стратегию материализованных представлений и оптимизацию стоимости запросов.",{"type":32,"tag":40,"props":41,"children":43},"h2",{"id":42},"почему-когорт-таблица-должна-быть-отдельной",[44],{"type":37,"value":45},"Почему когорт-таблица должна быть отдельной",{"type":32,"tag":33,"props":47,"children":48},{},[49],{"type":37,"value":50},"Расчёт retention нельзя выполнять каждый раз с нуля на сырых данных событий. Если компания электронной коммерции генерирует 50 миллионов событий в день, то на вопрос \"Какой процент пользователей, зарегистрировавшихся в январе 2026, вернулись на 30-й день?\" BigQuery должна будет просканировать 1.5 миллиарда строк. Такой запрос занимает 10-15 секунд и обрабатывает 200-300 ГБ. Если аналитик в день делает 20 таких запросов по разным сегментам, месячная стоимость легко превышает $500.",{"type":32,"tag":33,"props":52,"children":53},{},[54],{"type":37,"value":55},"Таблица когорт решает эту проблему: вы заранее агрегируете событийные данные по группам, предварительно вычисляете метрики каждой когорты на каждый день и сохраняете результаты. Когда аналитик делает запрос, BigQuery сканирует только таблицу когорт, а не сырые данные событий. 1000 когорт × 90 дней × 5 метрик = 450 000 строк. Запрос такой таблицы выполняется за 200 мс и обрабатывает всего 5 МБ.",{"type":32,"tag":33,"props":57,"children":58},{},[59],{"type":37,"value":60},"Но такой подход создаёт новую проблему: как обновляется таблица когорт? Каждый день, когда приходят новые события, вы пересчитываете всю историю заново или используете инкрементальное обновление? Какая стратегия партиционирования оптимизирует одновременно производительность запросов и стоимость обновления? Ответы на эти вопросы кроются в дизайне материализованных представлений и инкрементальных dbt-моделей.",{"type":32,"tag":40,"props":62,"children":64},{"id":63},"стратегия-партиционирования-cohort_date-или-observation_date",[65],{"type":37,"value":66},"Стратегия партиционирования: cohort_date или observation_date?",{"type":32,"tag":33,"props":68,"children":69},{},[70,72,79,81,87],{"type":37,"value":71},"Выбор ключа партиционирования для таблицы когорт критичен. Есть два кандидата: дата образования когорты (",{"type":32,"tag":73,"props":74,"children":76},"code",{"className":75},[],[77],{"type":37,"value":78},"cohort_date",{"type":37,"value":80},") и дата наблюдения (",{"type":32,"tag":73,"props":82,"children":84},{"className":83},[],[85],{"type":37,"value":86},"observation_date",{"type":37,"value":88},").",{"type":32,"tag":33,"props":90,"children":91},{},[92,105],{"type":32,"tag":93,"props":94,"children":95},"strong",{},[96,98,103],{"type":37,"value":97},"Партиционирование по ",{"type":32,"tag":73,"props":99,"children":101},{"className":100},[],[102],{"type":37,"value":78},{"type":37,"value":104},":",{"type":37,"value":106}," разбиение по дате первой активности пользователя. Когорта января 2026 — один раздел, февраля — другой. Преимущество: при появлении новой когорты вы пишете только в её раздел, старые разделы не трогаете. Недостаток: для получения 90-дневного retention одной когорты BigQuery должна просканировать 90 разных разделов. Производительность падает.",{"type":32,"tag":33,"props":108,"children":109},{},[110,120],{"type":32,"tag":93,"props":111,"children":112},{},[113,114,119],{"type":37,"value":97},{"type":32,"tag":73,"props":115,"children":117},{"className":116},[],[118],{"type":37,"value":86},{"type":37,"value":104},{"type":37,"value":121}," разбиение по дате наблюдения. Каждый день — отдельный раздел, содержащий метрики всех когорт на этот день. Преимущество: запросы вроде \"тренд retention за последние 7 дней\" сканируют только 7 разделов. Недостаток: каждый день нужно обновлять все когорты, что дорого обходится инкрементальной обработке.",{"type":32,"tag":33,"props":123,"children":124},{},[125,127,132,134,139,141,146],{"type":37,"value":126},"Правильный ответ — ",{"type":32,"tag":93,"props":128,"children":129},{},[130],{"type":37,"value":131},"гибридная архитектура с двумя таблицами:",{"type":37,"value":133}," таблица снимков (",{"type":32,"tag":73,"props":135,"children":137},{"className":136},[],[138],{"type":37,"value":86},{"type":37,"value":140}," партиционирована) и таблица агрегированных данных (",{"type":32,"tag":73,"props":142,"children":144},{"className":143},[],[145],{"type":37,"value":78},{"type":37,"value":147}," партиционирована). Таблица снимков обновляется каждый день и питает dashboard-ы аналитиков. Таблица агрегированных данных обновляется еженедельно для глубокого сравнения когорт. Эта архитектура соответствует best practice BigQuery: разделение узких и широких таблиц.",{"type":32,"tag":149,"props":150,"children":154},"pre",{"className":151,"code":152,"language":153,"meta":16,"style":16},"language-sql shiki shiki-themes github-dark","-- Схема таблицы снимков (партиционирована по observation_date)\nCREATE TABLE `analytics.cohort_retention_snapshot`\nPARTITION BY observation_date\nCLUSTER BY cohort_date, channel, device_category\nAS\nSELECT\n  observation_date,\n  cohort_date,\n  channel,\n  device_category,\n  cohort_size,\n  day_n,\n  active_users,\n  retention_rate\nFROM ...\n","sql",[155],{"type":32,"tag":73,"props":156,"children":157},{"__ignoreMap":16},[158,170,191,211,230,239,248,257,266,274,283,292,301,310,319],{"type":32,"tag":159,"props":160,"children":163},"span",{"class":161,"line":162},"line",1,[164],{"type":32,"tag":159,"props":165,"children":167},{"style":166},"--shiki-default:#6A737D",[168],{"type":37,"value":169},"-- Схема таблицы снимков (партиционирована по observation_date)\n",{"type":32,"tag":159,"props":171,"children":173},{"class":161,"line":172},2,[174,180,185],{"type":32,"tag":159,"props":175,"children":177},{"style":176},"--shiki-default:#F97583",[178],{"type":37,"value":179},"CREATE",{"type":32,"tag":159,"props":181,"children":182},{"style":176},[183],{"type":37,"value":184}," TABLE",{"type":32,"tag":159,"props":186,"children":188},{"style":187},"--shiki-default:#9ECBFF",[189],{"type":37,"value":190}," `analytics.cohort_retention_snapshot`\n",{"type":32,"tag":159,"props":192,"children":194},{"class":161,"line":193},3,[195,200,205],{"type":32,"tag":159,"props":196,"children":197},{"style":176},[198],{"type":37,"value":199},"PARTITION",{"type":32,"tag":159,"props":201,"children":202},{"style":176},[203],{"type":37,"value":204}," BY",{"type":32,"tag":159,"props":206,"children":208},{"style":207},"--shiki-default:#E1E4E8",[209],{"type":37,"value":210}," observation_date\n",{"type":32,"tag":159,"props":212,"children":214},{"class":161,"line":213},4,[215,220,225],{"type":32,"tag":159,"props":216,"children":217},{"style":207},[218],{"type":37,"value":219},"CLUSTER ",{"type":32,"tag":159,"props":221,"children":222},{"style":176},[223],{"type":37,"value":224},"BY",{"type":32,"tag":159,"props":226,"children":227},{"style":207},[228],{"type":37,"value":229}," cohort_date, channel, device_category\n",{"type":32,"tag":159,"props":231,"children":233},{"class":161,"line":232},5,[234],{"type":32,"tag":159,"props":235,"children":236},{"style":176},[237],{"type":37,"value":238},"AS\n",{"type":32,"tag":159,"props":240,"children":242},{"class":161,"line":241},6,[243],{"type":32,"tag":159,"props":244,"children":245},{"style":176},[246],{"type":37,"value":247},"SELECT\n",{"type":32,"tag":159,"props":249,"children":251},{"class":161,"line":250},7,[252],{"type":32,"tag":159,"props":253,"children":254},{"style":207},[255],{"type":37,"value":256},"  observation_date,\n",{"type":32,"tag":159,"props":258,"children":260},{"class":161,"line":259},8,[261],{"type":32,"tag":159,"props":262,"children":263},{"style":207},[264],{"type":37,"value":265},"  cohort_date,\n",{"type":32,"tag":159,"props":267,"children":268},{"class":161,"line":26},[269],{"type":32,"tag":159,"props":270,"children":271},{"style":207},[272],{"type":37,"value":273},"  channel,\n",{"type":32,"tag":159,"props":275,"children":277},{"class":161,"line":276},10,[278],{"type":32,"tag":159,"props":279,"children":280},{"style":207},[281],{"type":37,"value":282},"  device_category,\n",{"type":32,"tag":159,"props":284,"children":286},{"class":161,"line":285},11,[287],{"type":32,"tag":159,"props":288,"children":289},{"style":207},[290],{"type":37,"value":291},"  cohort_size,\n",{"type":32,"tag":159,"props":293,"children":295},{"class":161,"line":294},12,[296],{"type":32,"tag":159,"props":297,"children":298},{"style":207},[299],{"type":37,"value":300},"  day_n,\n",{"type":32,"tag":159,"props":302,"children":304},{"class":161,"line":303},13,[305],{"type":32,"tag":159,"props":306,"children":307},{"style":207},[308],{"type":37,"value":309},"  active_users,\n",{"type":32,"tag":159,"props":311,"children":313},{"class":161,"line":312},14,[314],{"type":32,"tag":159,"props":315,"children":316},{"style":207},[317],{"type":37,"value":318},"  retention_rate\n",{"type":32,"tag":159,"props":320,"children":322},{"class":161,"line":321},15,[323,328],{"type":32,"tag":159,"props":324,"children":325},{"style":176},[326],{"type":37,"value":327},"FROM",{"type":32,"tag":159,"props":329,"children":330},{"style":207},[331],{"type":37,"value":332}," ...\n",{"type":32,"tag":40,"props":334,"children":336},{"id":335},"материализованные-представления-vs-инкрементальные-модели-dbt",[337],{"type":37,"value":338},"Материализованные представления vs инкрементальные модели dbt",{"type":32,"tag":33,"props":340,"children":341},{},[342],{"type":37,"value":343},"В BigQuery материализованное представление (MV) автоматически делает инкрементальное обновление — при поступлении новых событий перезапускает базовый запрос и кэширует результат. Но у MV есть три ограничения: максимум 5 join'ов, отсутствие window function, отсутствие ручного управления партициями.",{"type":32,"tag":33,"props":345,"children":346},{},[347,349,355,357,363],{"type":37,"value":348},"Расчёт когорт обычно требует 3+ join'ов (таблицы пользователей, событий, подписок) и window function вроде ",{"type":32,"tag":73,"props":350,"children":352},{"className":351},[],[353],{"type":37,"value":354},"LAG()",{"type":37,"value":356},", ",{"type":32,"tag":73,"props":358,"children":360},{"className":359},[],[361],{"type":37,"value":362},"FIRST_VALUE()",{"type":37,"value":364},". В таком случае MV не подходит. Альтернатива — инкрементальная модель dbt.",{"type":32,"tag":33,"props":366,"children":367},{},[368,370,376],{"type":37,"value":369},"Инкрементальная модель dbt позволяет определить пользовательскую стратегию merge. Каждый день вы обновляете только разделы последних 7 дней (",{"type":32,"tag":73,"props":371,"children":373},{"className":372},[],[374],{"type":37,"value":375},"WHERE observation_date >= CURRENT_DATE() - 7",{"type":37,"value":377},"). Это снижает стоимость запроса на 85%. Пример dbt-модели:",{"type":32,"tag":149,"props":379,"children":381},{"className":151,"code":380,"language":153,"meta":16,"style":16},"{{ config(\n    materialized='incremental',\n    partition_by={\n      \"field\": \"observation_date\",\n      \"data_type\": \"date\"\n    },\n    cluster_by=['cohort_date', 'channel'],\n    incremental_strategy='insert_overwrite'\n) }}\n\nWITH daily_cohorts AS (\n  SELECT\n    DATE(first_seen_at) AS cohort_date,\n    user_id,\n    acquisition_channel AS channel\n  FROM {{ ref('users') }}\n  WHERE first_seen_at IS NOT NULL\n),\n\ndaily_activity AS (\n  SELECT\n    DATE(event_timestamp) AS activity_date,\n    user_id,\n    COUNT(*) AS event_count\n  FROM {{ ref('events') }}\n  WHERE event_name IN ('page_view', 'purchase')\n  {% if is_incremental() %}\n    AND DATE(event_timestamp) >= CURRENT_DATE() - 7\n  {% endif %}\n  GROUP BY 1, 2\n)\n\nSELECT\n  a.activity_date AS observation_date,\n  c.cohort_date,\n  c.channel,\n  DATE_DIFF(a.activity_date, c.cohort_date, DAY) AS day_n,\n  COUNT(DISTINCT c.user_id) AS cohort_size,\n  COUNT(DISTINCT a.user_id) AS active_users,\n  SAFE_DIVIDE(COUNT(DISTINCT a.user_id), COUNT(DISTINCT c.user_id)) AS retention_rate\nFROM daily_cohorts c\nLEFT JOIN daily_activity a\n  ON c.user_id = a.user_id\nWHERE a.activity_date >= c.cohort_date\n{% if is_incremental() %}\n  AND a.activity_date >= CURRENT_DATE() - 7\n{% endif %}\nGROUP BY 1, 2, 3, 4\n",[382],{"type":32,"tag":73,"props":383,"children":384},{"__ignoreMap":16},[385,393,416,433,455,472,480,497,514,522,531,554,562,584,592,609,632,651,660,668,685,693,715,723,757,778,820,839,877,886,909,917,925,933,962,983,1004,1065,1110,1152,1229,1242,1256,1295,1334,1351,1388,1397],{"type":32,"tag":159,"props":386,"children":387},{"class":161,"line":162},[388],{"type":32,"tag":159,"props":389,"children":390},{"style":207},[391],{"type":37,"value":392},"{{ config(\n",{"type":32,"tag":159,"props":394,"children":395},{"class":161,"line":172},[396,401,406,411],{"type":32,"tag":159,"props":397,"children":398},{"style":207},[399],{"type":37,"value":400},"    materialized",{"type":32,"tag":159,"props":402,"children":403},{"style":176},[404],{"type":37,"value":405},"=",{"type":32,"tag":159,"props":407,"children":408},{"style":187},[409],{"type":37,"value":410},"'incremental'",{"type":32,"tag":159,"props":412,"children":413},{"style":207},[414],{"type":37,"value":415},",\n",{"type":32,"tag":159,"props":417,"children":418},{"class":161,"line":193},[419,424,428],{"type":32,"tag":159,"props":420,"children":421},{"style":207},[422],{"type":37,"value":423},"    partition_by",{"type":32,"tag":159,"props":425,"children":426},{"style":176},[427],{"type":37,"value":405},{"type":32,"tag":159,"props":429,"children":430},{"style":207},[431],{"type":37,"value":432},"{\n",{"type":32,"tag":159,"props":434,"children":435},{"class":161,"line":213},[436,441,446,451],{"type":32,"tag":159,"props":437,"children":438},{"style":187},[439],{"type":37,"value":440},"      \"field\"",{"type":32,"tag":159,"props":442,"children":443},{"style":207},[444],{"type":37,"value":445},": ",{"type":32,"tag":159,"props":447,"children":448},{"style":187},[449],{"type":37,"value":450},"\"observation_date\"",{"type":32,"tag":159,"props":452,"children":453},{"style":207},[454],{"type":37,"value":415},{"type":32,"tag":159,"props":456,"children":457},{"class":161,"line":232},[458,463,467],{"type":32,"tag":159,"props":459,"children":460},{"style":187},[461],{"type":37,"value":462},"      \"data_type\"",{"type":32,"tag":159,"props":464,"children":465},{"style":207},[466],{"type":37,"value":445},{"type":32,"tag":159,"props":468,"children":469},{"style":187},[470],{"type":37,"value":471},"\"date\"\n",{"type":32,"tag":159,"props":473,"children":474},{"class":161,"line":241},[475],{"type":32,"tag":159,"props":476,"children":477},{"style":207},[478],{"type":37,"value":479},"    },\n",{"type":32,"tag":159,"props":481,"children":482},{"class":161,"line":250},[483,488,492],{"type":32,"tag":159,"props":484,"children":485},{"style":207},[486],{"type":37,"value":487},"    cluster_by",{"type":32,"tag":159,"props":489,"children":490},{"style":176},[491],{"type":37,"value":405},{"type":32,"tag":159,"props":493,"children":494},{"style":207},[495],{"type":37,"value":496},"['cohort_date', 'channel'],\n",{"type":32,"tag":159,"props":498,"children":499},{"class":161,"line":259},[500,505,509],{"type":32,"tag":159,"props":501,"children":502},{"style":207},[503],{"type":37,"value":504},"    incremental_strategy",{"type":32,"tag":159,"props":506,"children":507},{"style":176},[508],{"type":37,"value":405},{"type":32,"tag":159,"props":510,"children":511},{"style":187},[512],{"type":37,"value":513},"'insert_overwrite'\n",{"type":32,"tag":159,"props":515,"children":516},{"class":161,"line":26},[517],{"type":32,"tag":159,"props":518,"children":519},{"style":207},[520],{"type":37,"value":521},") }}\n",{"type":32,"tag":159,"props":523,"children":524},{"class":161,"line":276},[525],{"type":32,"tag":159,"props":526,"children":528},{"emptyLinePlaceholder":527},true,[529],{"type":37,"value":530},"\n",{"type":32,"tag":159,"props":532,"children":533},{"class":161,"line":285},[534,539,544,549],{"type":32,"tag":159,"props":535,"children":536},{"style":176},[537],{"type":37,"value":538},"WITH",{"type":32,"tag":159,"props":540,"children":541},{"style":207},[542],{"type":37,"value":543}," daily_cohorts ",{"type":32,"tag":159,"props":545,"children":546},{"style":176},[547],{"type":37,"value":548},"AS",{"type":32,"tag":159,"props":550,"children":551},{"style":207},[552],{"type":37,"value":553}," (\n",{"type":32,"tag":159,"props":555,"children":556},{"class":161,"line":294},[557],{"type":32,"tag":159,"props":558,"children":559},{"style":176},[560],{"type":37,"value":561},"  SELECT\n",{"type":32,"tag":159,"props":563,"children":564},{"class":161,"line":303},[565,570,575,579],{"type":32,"tag":159,"props":566,"children":567},{"style":176},[568],{"type":37,"value":569},"    DATE",{"type":32,"tag":159,"props":571,"children":572},{"style":207},[573],{"type":37,"value":574},"(first_seen_at) ",{"type":32,"tag":159,"props":576,"children":577},{"style":176},[578],{"type":37,"value":548},{"type":32,"tag":159,"props":580,"children":581},{"style":207},[582],{"type":37,"value":583}," cohort_date,\n",{"type":32,"tag":159,"props":585,"children":586},{"class":161,"line":312},[587],{"type":32,"tag":159,"props":588,"children":589},{"style":207},[590],{"type":37,"value":591},"    user_id,\n",{"type":32,"tag":159,"props":593,"children":594},{"class":161,"line":321},[595,600,604],{"type":32,"tag":159,"props":596,"children":597},{"style":207},[598],{"type":37,"value":599},"    acquisition_channel ",{"type":32,"tag":159,"props":601,"children":602},{"style":176},[603],{"type":37,"value":548},{"type":32,"tag":159,"props":605,"children":606},{"style":207},[607],{"type":37,"value":608}," channel\n",{"type":32,"tag":159,"props":610,"children":612},{"class":161,"line":611},16,[613,618,623,628],{"type":32,"tag":159,"props":614,"children":615},{"style":176},[616],{"type":37,"value":617},"  FROM",{"type":32,"tag":159,"props":619,"children":620},{"style":207},[621],{"type":37,"value":622}," {{ ref(",{"type":32,"tag":159,"props":624,"children":625},{"style":187},[626],{"type":37,"value":627},"'users'",{"type":32,"tag":159,"props":629,"children":630},{"style":207},[631],{"type":37,"value":521},{"type":32,"tag":159,"props":633,"children":635},{"class":161,"line":634},17,[636,641,646],{"type":32,"tag":159,"props":637,"children":638},{"style":176},[639],{"type":37,"value":640},"  WHERE",{"type":32,"tag":159,"props":642,"children":643},{"style":207},[644],{"type":37,"value":645}," first_seen_at ",{"type":32,"tag":159,"props":647,"children":648},{"style":176},[649],{"type":37,"value":650},"IS NOT NULL\n",{"type":32,"tag":159,"props":652,"children":654},{"class":161,"line":653},18,[655],{"type":32,"tag":159,"props":656,"children":657},{"style":207},[658],{"type":37,"value":659},"),\n",{"type":32,"tag":159,"props":661,"children":663},{"class":161,"line":662},19,[664],{"type":32,"tag":159,"props":665,"children":666},{"emptyLinePlaceholder":527},[667],{"type":37,"value":530},{"type":32,"tag":159,"props":669,"children":671},{"class":161,"line":670},20,[672,677,681],{"type":32,"tag":159,"props":673,"children":674},{"style":207},[675],{"type":37,"value":676},"daily_activity ",{"type":32,"tag":159,"props":678,"children":679},{"style":176},[680],{"type":37,"value":548},{"type":32,"tag":159,"props":682,"children":683},{"style":207},[684],{"type":37,"value":553},{"type":32,"tag":159,"props":686,"children":688},{"class":161,"line":687},21,[689],{"type":32,"tag":159,"props":690,"children":691},{"style":176},[692],{"type":37,"value":561},{"type":32,"tag":159,"props":694,"children":696},{"class":161,"line":695},22,[697,701,706,710],{"type":32,"tag":159,"props":698,"children":699},{"style":176},[700],{"type":37,"value":569},{"type":32,"tag":159,"props":702,"children":703},{"style":207},[704],{"type":37,"value":705},"(event_timestamp) ",{"type":32,"tag":159,"props":707,"children":708},{"style":176},[709],{"type":37,"value":548},{"type":32,"tag":159,"props":711,"children":712},{"style":207},[713],{"type":37,"value":714}," activity_date,\n",{"type":32,"tag":159,"props":716,"children":718},{"class":161,"line":717},23,[719],{"type":32,"tag":159,"props":720,"children":721},{"style":207},[722],{"type":37,"value":591},{"type":32,"tag":159,"props":724,"children":726},{"class":161,"line":725},24,[727,733,738,743,748,752],{"type":32,"tag":159,"props":728,"children":730},{"style":729},"--shiki-default:#79B8FF",[731],{"type":37,"value":732},"    COUNT",{"type":32,"tag":159,"props":734,"children":735},{"style":207},[736],{"type":37,"value":737},"(",{"type":32,"tag":159,"props":739,"children":740},{"style":176},[741],{"type":37,"value":742},"*",{"type":32,"tag":159,"props":744,"children":745},{"style":207},[746],{"type":37,"value":747},") ",{"type":32,"tag":159,"props":749,"children":750},{"style":176},[751],{"type":37,"value":548},{"type":32,"tag":159,"props":753,"children":754},{"style":207},[755],{"type":37,"value":756}," event_count\n",{"type":32,"tag":159,"props":758,"children":760},{"class":161,"line":759},25,[761,765,769,774],{"type":32,"tag":159,"props":762,"children":763},{"style":176},[764],{"type":37,"value":617},{"type":32,"tag":159,"props":766,"children":767},{"style":207},[768],{"type":37,"value":622},{"type":32,"tag":159,"props":770,"children":771},{"style":187},[772],{"type":37,"value":773},"'events'",{"type":32,"tag":159,"props":775,"children":776},{"style":207},[777],{"type":37,"value":521},{"type":32,"tag":159,"props":779,"children":781},{"class":161,"line":780},26,[782,786,791,796,801,806,810,815],{"type":32,"tag":159,"props":783,"children":784},{"style":176},[785],{"type":37,"value":640},{"type":32,"tag":159,"props":787,"children":788},{"style":207},[789],{"type":37,"value":790}," event_name ",{"type":32,"tag":159,"props":792,"children":793},{"style":176},[794],{"type":37,"value":795},"IN",{"type":32,"tag":159,"props":797,"children":798},{"style":207},[799],{"type":37,"value":800}," (",{"type":32,"tag":159,"props":802,"children":803},{"style":187},[804],{"type":37,"value":805},"'page_view'",{"type":32,"tag":159,"props":807,"children":808},{"style":207},[809],{"type":37,"value":356},{"type":32,"tag":159,"props":811,"children":812},{"style":187},[813],{"type":37,"value":814},"'purchase'",{"type":32,"tag":159,"props":816,"children":817},{"style":207},[818],{"type":37,"value":819},")\n",{"type":32,"tag":159,"props":821,"children":823},{"class":161,"line":822},27,[824,829,834],{"type":32,"tag":159,"props":825,"children":826},{"style":207},[827],{"type":37,"value":828},"  {% ",{"type":32,"tag":159,"props":830,"children":831},{"style":176},[832],{"type":37,"value":833},"if",{"type":32,"tag":159,"props":835,"children":836},{"style":207},[837],{"type":37,"value":838}," is_incremental() %}\n",{"type":32,"tag":159,"props":840,"children":842},{"class":161,"line":841},28,[843,848,853,857,862,867,872],{"type":32,"tag":159,"props":844,"children":845},{"style":176},[846],{"type":37,"value":847},"    AND",{"type":32,"tag":159,"props":849,"children":850},{"style":176},[851],{"type":37,"value":852}," DATE",{"type":32,"tag":159,"props":854,"children":855},{"style":207},[856],{"type":37,"value":705},{"type":32,"tag":159,"props":858,"children":859},{"style":176},[860],{"type":37,"value":861},">=",{"type":32,"tag":159,"props":863,"children":864},{"style":207},[865],{"type":37,"value":866}," CURRENT_DATE() ",{"type":32,"tag":159,"props":868,"children":869},{"style":176},[870],{"type":37,"value":871},"-",{"type":32,"tag":159,"props":873,"children":874},{"style":729},[875],{"type":37,"value":876}," 7\n",{"type":32,"tag":159,"props":878,"children":880},{"class":161,"line":879},29,[881],{"type":32,"tag":159,"props":882,"children":883},{"style":207},[884],{"type":37,"value":885},"  {% endif %}\n",{"type":32,"tag":159,"props":887,"children":889},{"class":161,"line":888},30,[890,895,900,904],{"type":32,"tag":159,"props":891,"children":892},{"style":176},[893],{"type":37,"value":894},"  GROUP BY",{"type":32,"tag":159,"props":896,"children":897},{"style":729},[898],{"type":37,"value":899}," 1",{"type":32,"tag":159,"props":901,"children":902},{"style":207},[903],{"type":37,"value":356},{"type":32,"tag":159,"props":905,"children":906},{"style":729},[907],{"type":37,"value":908},"2\n",{"type":32,"tag":159,"props":910,"children":912},{"class":161,"line":911},31,[913],{"type":32,"tag":159,"props":914,"children":915},{"style":207},[916],{"type":37,"value":819},{"type":32,"tag":159,"props":918,"children":920},{"class":161,"line":919},32,[921],{"type":32,"tag":159,"props":922,"children":923},{"emptyLinePlaceholder":527},[924],{"type":37,"value":530},{"type":32,"tag":159,"props":926,"children":928},{"class":161,"line":927},33,[929],{"type":32,"tag":159,"props":930,"children":931},{"style":176},[932],{"type":37,"value":247},{"type":32,"tag":159,"props":934,"children":936},{"class":161,"line":935},34,[937,942,947,952,957],{"type":32,"tag":159,"props":938,"children":939},{"style":729},[940],{"type":37,"value":941},"  a",{"type":32,"tag":159,"props":943,"children":944},{"style":207},[945],{"type":37,"value":946},".",{"type":32,"tag":159,"props":948,"children":949},{"style":729},[950],{"type":37,"value":951},"activity_date",{"type":32,"tag":159,"props":953,"children":954},{"style":176},[955],{"type":37,"value":956}," AS",{"type":32,"tag":159,"props":958,"children":959},{"style":207},[960],{"type":37,"value":961}," observation_date,\n",{"type":32,"tag":159,"props":963,"children":965},{"class":161,"line":964},35,[966,971,975,979],{"type":32,"tag":159,"props":967,"children":968},{"style":729},[969],{"type":37,"value":970},"  c",{"type":32,"tag":159,"props":972,"children":973},{"style":207},[974],{"type":37,"value":946},{"type":32,"tag":159,"props":976,"children":977},{"style":729},[978],{"type":37,"value":78},{"type":32,"tag":159,"props":980,"children":981},{"style":207},[982],{"type":37,"value":415},{"type":32,"tag":159,"props":984,"children":986},{"class":161,"line":985},36,[987,991,995,1000],{"type":32,"tag":159,"props":988,"children":989},{"style":729},[990],{"type":37,"value":970},{"type":32,"tag":159,"props":992,"children":993},{"style":207},[994],{"type":37,"value":946},{"type":32,"tag":159,"props":996,"children":997},{"style":729},[998],{"type":37,"value":999},"channel",{"type":32,"tag":159,"props":1001,"children":1002},{"style":207},[1003],{"type":37,"value":415},{"type":32,"tag":159,"props":1005,"children":1007},{"class":161,"line":1006},37,[1008,1013,1018,1022,1026,1030,1035,1039,1043,1047,1052,1056,1060],{"type":32,"tag":159,"props":1009,"children":1010},{"style":207},[1011],{"type":37,"value":1012},"  DATE_DIFF(",{"type":32,"tag":159,"props":1014,"children":1015},{"style":729},[1016],{"type":37,"value":1017},"a",{"type":32,"tag":159,"props":1019,"children":1020},{"style":207},[1021],{"type":37,"value":946},{"type":32,"tag":159,"props":1023,"children":1024},{"style":729},[1025],{"type":37,"value":951},{"type":32,"tag":159,"props":1027,"children":1028},{"style":207},[1029],{"type":37,"value":356},{"type":32,"tag":159,"props":1031,"children":1032},{"style":729},[1033],{"type":37,"value":1034},"c",{"type":32,"tag":159,"props":1036,"children":1037},{"style":207},[1038],{"type":37,"value":946},{"type":32,"tag":159,"props":1040,"children":1041},{"style":729},[1042],{"type":37,"value":78},{"type":32,"tag":159,"props":1044,"children":1045},{"style":207},[1046],{"type":37,"value":356},{"type":32,"tag":159,"props":1048,"children":1049},{"style":176},[1050],{"type":37,"value":1051},"DAY",{"type":32,"tag":159,"props":1053,"children":1054},{"style":207},[1055],{"type":37,"value":747},{"type":32,"tag":159,"props":1057,"children":1058},{"style":176},[1059],{"type":37,"value":548},{"type":32,"tag":159,"props":1061,"children":1062},{"style":207},[1063],{"type":37,"value":1064}," day_n,\n",{"type":32,"tag":159,"props":1066,"children":1068},{"class":161,"line":1067},38,[1069,1074,1078,1083,1088,1092,1097,1101,1105],{"type":32,"tag":159,"props":1070,"children":1071},{"style":729},[1072],{"type":37,"value":1073},"  COUNT",{"type":32,"tag":159,"props":1075,"children":1076},{"style":207},[1077],{"type":37,"value":737},{"type":32,"tag":159,"props":1079,"children":1080},{"style":176},[1081],{"type":37,"value":1082},"DISTINCT",{"type":32,"tag":159,"props":1084,"children":1085},{"style":729},[1086],{"type":37,"value":1087}," c",{"type":32,"tag":159,"props":1089,"children":1090},{"style":207},[1091],{"type":37,"value":946},{"type":32,"tag":159,"props":1093,"children":1094},{"style":729},[1095],{"type":37,"value":1096},"user_id",{"type":32,"tag":159,"props":1098,"children":1099},{"style":207},[1100],{"type":37,"value":747},{"type":32,"tag":159,"props":1102,"children":1103},{"style":176},[1104],{"type":37,"value":548},{"type":32,"tag":159,"props":1106,"children":1107},{"style":207},[1108],{"type":37,"value":1109}," cohort_size,\n",{"type":32,"tag":159,"props":1111,"children":1113},{"class":161,"line":1112},39,[1114,1118,1122,1126,1131,1135,1139,1143,1147],{"type":32,"tag":159,"props":1115,"children":1116},{"style":729},[1117],{"type":37,"value":1073},{"type":32,"tag":159,"props":1119,"children":1120},{"style":207},[1121],{"type":37,"value":737},{"type":32,"tag":159,"props":1123,"children":1124},{"style":176},[1125],{"type":37,"value":1082},{"type":32,"tag":159,"props":1127,"children":1128},{"style":729},[1129],{"type":37,"value":1130}," a",{"type":32,"tag":159,"props":1132,"children":1133},{"style":207},[1134],{"type":37,"value":946},{"type":32,"tag":159,"props":1136,"children":1137},{"style":729},[1138],{"type":37,"value":1096},{"type":32,"tag":159,"props":1140,"children":1141},{"style":207},[1142],{"type":37,"value":747},{"type":32,"tag":159,"props":1144,"children":1145},{"style":176},[1146],{"type":37,"value":548},{"type":32,"tag":159,"props":1148,"children":1149},{"style":207},[1150],{"type":37,"value":1151}," active_users,\n",{"type":32,"tag":159,"props":1153,"children":1155},{"class":161,"line":1154},40,[1156,1161,1166,1170,1174,1178,1182,1186,1191,1195,1199,1203,1207,1211,1215,1220,1224],{"type":32,"tag":159,"props":1157,"children":1158},{"style":207},[1159],{"type":37,"value":1160},"  SAFE_DIVIDE(",{"type":32,"tag":159,"props":1162,"children":1163},{"style":729},[1164],{"type":37,"value":1165},"COUNT",{"type":32,"tag":159,"props":1167,"children":1168},{"style":207},[1169],{"type":37,"value":737},{"type":32,"tag":159,"props":1171,"children":1172},{"style":176},[1173],{"type":37,"value":1082},{"type":32,"tag":159,"props":1175,"children":1176},{"style":729},[1177],{"type":37,"value":1130},{"type":32,"tag":159,"props":1179,"children":1180},{"style":207},[1181],{"type":37,"value":946},{"type":32,"tag":159,"props":1183,"children":1184},{"style":729},[1185],{"type":37,"value":1096},{"type":32,"tag":159,"props":1187,"children":1188},{"style":207},[1189],{"type":37,"value":1190},"), ",{"type":32,"tag":159,"props":1192,"children":1193},{"style":729},[1194],{"type":37,"value":1165},{"type":32,"tag":159,"props":1196,"children":1197},{"style":207},[1198],{"type":37,"value":737},{"type":32,"tag":159,"props":1200,"children":1201},{"style":176},[1202],{"type":37,"value":1082},{"type":32,"tag":159,"props":1204,"children":1205},{"style":729},[1206],{"type":37,"value":1087},{"type":32,"tag":159,"props":1208,"children":1209},{"style":207},[1210],{"type":37,"value":946},{"type":32,"tag":159,"props":1212,"children":1213},{"style":729},[1214],{"type":37,"value":1096},{"type":32,"tag":159,"props":1216,"children":1217},{"style":207},[1218],{"type":37,"value":1219},")) ",{"type":32,"tag":159,"props":1221,"children":1222},{"style":176},[1223],{"type":37,"value":548},{"type":32,"tag":159,"props":1225,"children":1226},{"style":207},[1227],{"type":37,"value":1228}," retention_rate\n",{"type":32,"tag":159,"props":1230,"children":1232},{"class":161,"line":1231},41,[1233,1237],{"type":32,"tag":159,"props":1234,"children":1235},{"style":176},[1236],{"type":37,"value":327},{"type":32,"tag":159,"props":1238,"children":1239},{"style":207},[1240],{"type":37,"value":1241}," daily_cohorts c\n",{"type":32,"tag":159,"props":1243,"children":1245},{"class":161,"line":1244},42,[1246,1251],{"type":32,"tag":159,"props":1247,"children":1248},{"style":176},[1249],{"type":37,"value":1250},"LEFT JOIN",{"type":32,"tag":159,"props":1252,"children":1253},{"style":207},[1254],{"type":37,"value":1255}," daily_activity a\n",{"type":32,"tag":159,"props":1257,"children":1259},{"class":161,"line":1258},43,[1260,1265,1269,1273,1277,1282,1286,1290],{"type":32,"tag":159,"props":1261,"children":1262},{"style":176},[1263],{"type":37,"value":1264},"  ON",{"type":32,"tag":159,"props":1266,"children":1267},{"style":729},[1268],{"type":37,"value":1087},{"type":32,"tag":159,"props":1270,"children":1271},{"style":207},[1272],{"type":37,"value":946},{"type":32,"tag":159,"props":1274,"children":1275},{"style":729},[1276],{"type":37,"value":1096},{"type":32,"tag":159,"props":1278,"children":1279},{"style":176},[1280],{"type":37,"value":1281}," =",{"type":32,"tag":159,"props":1283,"children":1284},{"style":729},[1285],{"type":37,"value":1130},{"type":32,"tag":159,"props":1287,"children":1288},{"style":207},[1289],{"type":37,"value":946},{"type":32,"tag":159,"props":1291,"children":1292},{"style":729},[1293],{"type":37,"value":1294},"user_id\n",{"type":32,"tag":159,"props":1296,"children":1298},{"class":161,"line":1297},44,[1299,1304,1308,1312,1316,1321,1325,1329],{"type":32,"tag":159,"props":1300,"children":1301},{"style":176},[1302],{"type":37,"value":1303},"WHERE",{"type":32,"tag":159,"props":1305,"children":1306},{"style":729},[1307],{"type":37,"value":1130},{"type":32,"tag":159,"props":1309,"children":1310},{"style":207},[1311],{"type":37,"value":946},{"type":32,"tag":159,"props":1313,"children":1314},{"style":729},[1315],{"type":37,"value":951},{"type":32,"tag":159,"props":1317,"children":1318},{"style":176},[1319],{"type":37,"value":1320}," >=",{"type":32,"tag":159,"props":1322,"children":1323},{"style":729},[1324],{"type":37,"value":1087},{"type":32,"tag":159,"props":1326,"children":1327},{"style":207},[1328],{"type":37,"value":946},{"type":32,"tag":159,"props":1330,"children":1331},{"style":729},[1332],{"type":37,"value":1333},"cohort_date\n",{"type":32,"tag":159,"props":1335,"children":1337},{"class":161,"line":1336},45,[1338,1343,1347],{"type":32,"tag":159,"props":1339,"children":1340},{"style":207},[1341],{"type":37,"value":1342},"{% ",{"type":32,"tag":159,"props":1344,"children":1345},{"style":176},[1346],{"type":37,"value":833},{"type":32,"tag":159,"props":1348,"children":1349},{"style":207},[1350],{"type":37,"value":838},{"type":32,"tag":159,"props":1352,"children":1354},{"class":161,"line":1353},46,[1355,1360,1364,1368,1372,1376,1380,1384],{"type":32,"tag":159,"props":1356,"children":1357},{"style":176},[1358],{"type":37,"value":1359},"  AND",{"type":32,"tag":159,"props":1361,"children":1362},{"style":729},[1363],{"type":37,"value":1130},{"type":32,"tag":159,"props":1365,"children":1366},{"style":207},[1367],{"type":37,"value":946},{"type":32,"tag":159,"props":1369,"children":1370},{"style":729},[1371],{"type":37,"value":951},{"type":32,"tag":159,"props":1373,"children":1374},{"style":176},[1375],{"type":37,"value":1320},{"type":32,"tag":159,"props":1377,"children":1378},{"style":207},[1379],{"type":37,"value":866},{"type":32,"tag":159,"props":1381,"children":1382},{"style":176},[1383],{"type":37,"value":871},{"type":32,"tag":159,"props":1385,"children":1386},{"style":729},[1387],{"type":37,"value":876},{"type":32,"tag":159,"props":1389,"children":1391},{"class":161,"line":1390},47,[1392],{"type":32,"tag":159,"props":1393,"children":1394},{"style":207},[1395],{"type":37,"value":1396},"{% endif %}\n",{"type":32,"tag":159,"props":1398,"children":1400},{"class":161,"line":1399},48,[1401,1406,1410,1414,1419,1423,1428,1432],{"type":32,"tag":159,"props":1402,"children":1403},{"style":176},[1404],{"type":37,"value":1405},"GROUP BY",{"type":32,"tag":159,"props":1407,"children":1408},{"style":729},[1409],{"type":37,"value":899},{"type":32,"tag":159,"props":1411,"children":1412},{"style":207},[1413],{"type":37,"value":356},{"type":32,"tag":159,"props":1415,"children":1416},{"style":729},[1417],{"type":37,"value":1418},"2",{"type":32,"tag":159,"props":1420,"children":1421},{"style":207},[1422],{"type":37,"value":356},{"type":32,"tag":159,"props":1424,"children":1425},{"style":729},[1426],{"type":37,"value":1427},"3",{"type":32,"tag":159,"props":1429,"children":1430},{"style":207},[1431],{"type":37,"value":356},{"type":32,"tag":159,"props":1433,"children":1434},{"style":729},[1435],{"type":37,"value":1436},"4\n",{"type":32,"tag":33,"props":1438,"children":1439},{},[1440],{"type":37,"value":1441},"Когда такая модель запускается ежедневно, она перезаписывает только разделы последних 7 дней. Обрабатываемый объём падает с 20 ГБ в день до 2 ГБ. Годовая экономия на стоимости запросов — $2400.",{"type":32,"tag":1443,"props":1444,"children":1446},"h3",{"id":1445},"выбор-ключа-кластеризации",[1447],{"type":37,"value":1448},"Выбор ключа кластеризации",{"type":32,"tag":33,"props":1450,"children":1451},{},[1452],{"type":37,"value":1453},"Партиционирования недостаточно, нужна ещё кластеризация. Таблица когорт фильтруется по трём измерениям: cohort_date (время), channel (источник), device_category (устройство). В BigQuery порядок ключа кластеризации важен — поле с наибольшей кардинальностью должно быть первым.",{"type":32,"tag":33,"props":1455,"children":1456},{},[1457],{"type":37,"value":1458},"Анализ кардинальности:",{"type":32,"tag":1460,"props":1461,"children":1462},"ul",{},[1463,1474,1484],{"type":32,"tag":1464,"props":1465,"children":1466},"li",{},[1467,1472],{"type":32,"tag":73,"props":1468,"children":1470},{"className":1469},[],[1471],{"type":37,"value":78},{"type":37,"value":1473},": 365 значений (1 год)",{"type":32,"tag":1464,"props":1475,"children":1476},{},[1477,1482],{"type":32,"tag":73,"props":1478,"children":1480},{"className":1479},[],[1481],{"type":37,"value":999},{"type":37,"value":1483},": 15-20 значений (organic, paid_search, social, email...)",{"type":32,"tag":1464,"props":1485,"children":1486},{},[1487,1493],{"type":32,"tag":73,"props":1488,"children":1490},{"className":1489},[],[1491],{"type":37,"value":1492},"device_category",{"type":37,"value":1494},": 3-4 значения (desktop, mobile, tablet)",{"type":32,"tag":33,"props":1496,"children":1497},{},[1498,1500,1506],{"type":37,"value":1499},"Правильный порядок: ",{"type":32,"tag":73,"props":1501,"children":1503},{"className":1502},[],[1504],{"type":37,"value":1505},"CLUSTER BY cohort_date, channel, device_category",{"type":37,"value":1507},". Такой порядок ускорит запросы вроде \"какой процент пользователей из Instagram на мобильных в Q4 2025 вернулись на 30-й день?\" в 10 раз.",{"type":32,"tag":40,"props":1509,"children":1511},{"id":1510},"оптимизация-стоимости-запросов-глубина-предварительной-агрегации",[1512],{"type":37,"value":1513},"Оптимизация стоимости запросов: глубина предварительной агрегации",{"type":32,"tag":33,"props":1515,"children":1516},{},[1517],{"type":37,"value":1518},"Уровень гранулярности таблицы когорт определяет баланс между стоимостью и производительностью. Храните ли вы отдельную строку для каждой комбинации когорта × канал × устройство × день, или только общие итоги?",{"type":32,"tag":33,"props":1520,"children":1521},{},[1522,1527],{"type":32,"tag":93,"props":1523,"children":1524},{},[1525],{"type":37,"value":1526},"Вариант 1: гранулярная таблица",{"type":37,"value":1528}," — каждая комбинация когорта × канал × устройство × день_n отдельной строкой. Общее количество строк: 365 когорт × 20 каналов × 4 устройства × 90 дней = 2.6 миллиона строк. Преимущество: аналитик может делать pivot по любому сегменту. Недостаток: высокая стоимость хранения ($50\u002FТБ → ~$0.15 в месяц).",{"type":32,"tag":33,"props":1530,"children":1531},{},[1532,1537],{"type":32,"tag":93,"props":1533,"children":1534},{},[1535],{"type":37,"value":1536},"Вариант 2: агрегированная таблица",{"type":37,"value":1538}," — только когорта × день_n, без разделения по каналам и устройствам. Общее количество строк: 365 × 90 = 32 850 строк. Преимущество: минимальная стоимость хранения и запросов. Недостаток: невозможно сделать разбор по каналам.",{"type":32,"tag":33,"props":1540,"children":1541},{},[1542,1544,1549],{"type":37,"value":1543},"Правильный подход — ",{"type":32,"tag":93,"props":1545,"children":1546},{},[1547],{"type":37,"value":1548},"двухуровневая архитектура:",{"type":37,"value":1550}," core metrics — гранулярная (с разделением по каналам и устройствам), extended metrics — агрегированная (только когорта × день_n). Это оптимизирует хранилище и даёт аналитическую гибкость. Core metrics питает dashboard-ы, extended metrics используется для ad-hoc анализа.",{"type":32,"tag":33,"props":1552,"children":1553},{},[1554],{"type":37,"value":1555},"Кроме того, определите политику истечения разделов в BigQuery: разделы старше 90 дней автоматически удаляются. Анализ retention редко требует данных старше 90 дней, и эта политика снижает годовую стоимость хранения на 60%.",{"type":32,"tag":40,"props":1557,"children":1559},{"id":1558},"решение-проблемы-разрешения-идентичности-на-уровне-когорты",[1560],{"type":37,"value":1561},"Решение проблемы разрешения идентичности на уровне когорты",{"type":32,"tag":33,"props":1563,"children":1564},{},[1565],{"type":37,"value":1566},"Самая тёмная сторона анализа когорт — столкновения user_id и разрешение идентичности. Если пользователь зарегистрировался на десктопе и совершил покупку на мобильном, создаются два разных user_id. Если таблица когорт не объединит эти идентичности, retention будет недооценён на 20%.",{"type":32,"tag":33,"props":1568,"children":1569},{},[1570,1572,1580,1582,1588,1590,1596,1598,1604],{"type":37,"value":1571},"Решение: перед созданием таблицы когорт объедините таблицу графика идентичности. В процессе ",{"type":32,"tag":1017,"props":1573,"children":1577},{"href":1574,"rel":1575},"https:\u002F\u002Fwww.roibase.com.tr\u002Fru\u002Ffirstparty",[1576],"nofollow",[1578],{"type":37,"value":1579},"First-Party Вори и архитектура измерений",{"type":37,"value":1581}," вы уже создали столбец ",{"type":32,"tag":73,"props":1583,"children":1585},{"className":1584},[],[1586],{"type":37,"value":1587},"canonical_user_id",{"type":37,"value":1589}," — используйте его здесь. В dbt-модели используйте view ",{"type":32,"tag":73,"props":1591,"children":1593},{"className":1592},[],[1594],{"type":37,"value":1595},"users_unified",{"type":37,"value":1597}," вместо таблицы ",{"type":32,"tag":73,"props":1599,"children":1601},{"className":1600},[],[1602],{"type":37,"value":1603},"users",{"type":37,"value":946},{"type":32,"tag":149,"props":1606,"children":1608},{"className":151,"code":1607,"language":153,"meta":16,"style":16},"WITH unified_users AS (\n  SELECT\n    canonical_user_id,\n    MIN(first_seen_at) AS cohort_date,\n    ARRAY_AGG(DISTINCT acquisition_channel IGNORE NULLS ORDER BY first_seen_at LIMIT 1)[OFFSET(0)] AS channel\n  FROM {{ ref('users_unified') }}\n  GROUP BY 1\n)\n",[1609],{"type":32,"tag":73,"props":1610,"children":1611},{"__ignoreMap":16},[1612,1632,1639,1647,1667,1725,1745,1757],{"type":32,"tag":159,"props":1613,"children":1614},{"class":161,"line":162},[1615,1619,1624,1628],{"type":32,"tag":159,"props":1616,"children":1617},{"style":176},[1618],{"type":37,"value":538},{"type":32,"tag":159,"props":1620,"children":1621},{"style":207},[1622],{"type":37,"value":1623}," unified_users ",{"type":32,"tag":159,"props":1625,"children":1626},{"style":176},[1627],{"type":37,"value":548},{"type":32,"tag":159,"props":1629,"children":1630},{"style":207},[1631],{"type":37,"value":553},{"type":32,"tag":159,"props":1633,"children":1634},{"class":161,"line":172},[1635],{"type":32,"tag":159,"props":1636,"children":1637},{"style":176},[1638],{"type":37,"value":561},{"type":32,"tag":159,"props":1640,"children":1641},{"class":161,"line":193},[1642],{"type":32,"tag":159,"props":1643,"children":1644},{"style":207},[1645],{"type":37,"value":1646},"    canonical_user_id,\n",{"type":32,"tag":159,"props":1648,"children":1649},{"class":161,"line":213},[1650,1655,1659,1663],{"type":32,"tag":159,"props":1651,"children":1652},{"style":729},[1653],{"type":37,"value":1654},"    MIN",{"type":32,"tag":159,"props":1656,"children":1657},{"style":207},[1658],{"type":37,"value":574},{"type":32,"tag":159,"props":1660,"children":1661},{"style":176},[1662],{"type":37,"value":548},{"type":32,"tag":159,"props":1664,"children":1665},{"style":207},[1666],{"type":37,"value":583},{"type":32,"tag":159,"props":1668,"children":1669},{"class":161,"line":232},[1670,1675,1679,1684,1689,1694,1699,1703,1708,1712,1717,1721],{"type":32,"tag":159,"props":1671,"children":1672},{"style":207},[1673],{"type":37,"value":1674},"    ARRAY_AGG(",{"type":32,"tag":159,"props":1676,"children":1677},{"style":176},[1678],{"type":37,"value":1082},{"type":32,"tag":159,"props":1680,"children":1681},{"style":207},[1682],{"type":37,"value":1683}," acquisition_channel ",{"type":32,"tag":159,"props":1685,"children":1686},{"style":176},[1687],{"type":37,"value":1688},"IGNORE",{"type":32,"tag":159,"props":1690,"children":1691},{"style":176},[1692],{"type":37,"value":1693}," NULLS",{"type":32,"tag":159,"props":1695,"children":1696},{"style":176},[1697],{"type":37,"value":1698}," ORDER BY",{"type":32,"tag":159,"props":1700,"children":1701},{"style":207},[1702],{"type":37,"value":645},{"type":32,"tag":159,"props":1704,"children":1705},{"style":176},[1706],{"type":37,"value":1707},"LIMIT",{"type":32,"tag":159,"props":1709,"children":1710},{"style":729},[1711],{"type":37,"value":899},{"type":32,"tag":159,"props":1713,"children":1714},{"style":207},[1715],{"type":37,"value":1716},")[OFFSET(0)] ",{"type":32,"tag":159,"props":1718,"children":1719},{"style":176},[1720],{"type":37,"value":548},{"type":32,"tag":159,"props":1722,"children":1723},{"style":207},[1724],{"type":37,"value":608},{"type":32,"tag":159,"props":1726,"children":1727},{"class":161,"line":241},[1728,1732,1736,1741],{"type":32,"tag":159,"props":1729,"children":1730},{"style":176},[1731],{"type":37,"value":617},{"type":32,"tag":159,"props":1733,"children":1734},{"style":207},[1735],{"type":37,"value":622},{"type":32,"tag":159,"props":1737,"children":1738},{"style":187},[1739],{"type":37,"value":1740},"'users_unified'",{"type":32,"tag":159,"props":1742,"children":1743},{"style":207},[1744],{"type":37,"value":521},{"type":32,"tag":159,"props":1746,"children":1747},{"class":161,"line":250},[1748,1752],{"type":32,"tag":159,"props":1749,"children":1750},{"style":176},[1751],{"type":37,"value":894},{"type":32,"tag":159,"props":1753,"children":1754},{"style":729},[1755],{"type":37,"value":1756}," 1\n",{"type":32,"tag":159,"props":1758,"children":1759},{"class":161,"line":259},[1760],{"type":32,"tag":159,"props":1761,"children":1762},{"style":207},[1763],{"type":37,"value":819},{"type":32,"tag":33,"props":1765,"children":1766},{},[1767],{"type":37,"value":1768},"Такой подход правильно вычисляет cross-device retention. В production это даёт разницу 15-25% в метриках retention. Когда таблица разрешения идентичности обновляется, таблица когорт также должна переписываться — определите зависимость в DAG dbt:",{"type":32,"tag":149,"props":1770,"children":1774},{"className":1771,"code":1772,"language":1773,"meta":16,"style":16},"language-yaml shiki shiki-themes github-dark","models:\n  - name: cohort_retention_snapshot\n    config:\n      materialized: incremental\n    depends_on:\n      - ref('users_unified')\n","yaml",[1775],{"type":32,"tag":73,"props":1776,"children":1777},{"__ignoreMap":16},[1778,1792,1814,1826,1843,1855],{"type":32,"tag":159,"props":1779,"children":1780},{"class":161,"line":162},[1781,1787],{"type":32,"tag":159,"props":1782,"children":1784},{"style":1783},"--shiki-default:#85E89D",[1785],{"type":37,"value":1786},"models",{"type":32,"tag":159,"props":1788,"children":1789},{"style":207},[1790],{"type":37,"value":1791},":\n",{"type":32,"tag":159,"props":1793,"children":1794},{"class":161,"line":172},[1795,1800,1805,1809],{"type":32,"tag":159,"props":1796,"children":1797},{"style":207},[1798],{"type":37,"value":1799},"  - ",{"type":32,"tag":159,"props":1801,"children":1802},{"style":1783},[1803],{"type":37,"value":1804},"name",{"type":32,"tag":159,"props":1806,"children":1807},{"style":207},[1808],{"type":37,"value":445},{"type":32,"tag":159,"props":1810,"children":1811},{"style":187},[1812],{"type":37,"value":1813},"cohort_retention_snapshot\n",{"type":32,"tag":159,"props":1815,"children":1816},{"class":161,"line":193},[1817,1822],{"type":32,"tag":159,"props":1818,"children":1819},{"style":1783},[1820],{"type":37,"value":1821},"    config",{"type":32,"tag":159,"props":1823,"children":1824},{"style":207},[1825],{"type":37,"value":1791},{"type":32,"tag":159,"props":1827,"children":1828},{"class":161,"line":213},[1829,1834,1838],{"type":32,"tag":159,"props":1830,"children":1831},{"style":1783},[1832],{"type":37,"value":1833},"      materialized",{"type":32,"tag":159,"props":1835,"children":1836},{"style":207},[1837],{"type":37,"value":445},{"type":32,"tag":159,"props":1839,"children":1840},{"style":187},[1841],{"type":37,"value":1842},"incremental\n",{"type":32,"tag":159,"props":1844,"children":1845},{"class":161,"line":232},[1846,1851],{"type":32,"tag":159,"props":1847,"children":1848},{"style":1783},[1849],{"type":37,"value":1850},"    depends_on",{"type":32,"tag":159,"props":1852,"children":1853},{"style":207},[1854],{"type":37,"value":1791},{"type":32,"tag":159,"props":1856,"children":1857},{"class":161,"line":241},[1858,1863],{"type":32,"tag":159,"props":1859,"children":1860},{"style":207},[1861],{"type":37,"value":1862},"      - ",{"type":32,"tag":159,"props":1864,"children":1865},{"style":187},[1866],{"type":37,"value":1867},"ref('users_unified')\n",{"type":32,"tag":40,"props":1869,"children":1871},{"id":1870},"production-чеклист-мониторинг-и-алертинг",[1872],{"type":37,"value":1873},"Production-чеклист: мониторинг и алертинг",{"type":32,"tag":33,"props":1875,"children":1876},{},[1877],{"type":37,"value":1878},"Когда таблица когорт запущена в production, непрерывно отслеживайте 3 метрики:",{"type":32,"tag":1880,"props":1881,"children":1882},"ol",{},[1883,1901,1919],{"type":32,"tag":1464,"props":1884,"children":1885},{},[1886,1891,1893,1899],{"type":32,"tag":93,"props":1887,"children":1888},{},[1889],{"type":37,"value":1890},"Freshness:",{"type":37,"value":1892}," когда последний раздел обновлён? Определите тест ",{"type":32,"tag":73,"props":1894,"children":1896},{"className":1895},[],[1897],{"type":37,"value":1898},"freshness",{"type":37,"value":1900}," в dbt-core, отправьте alert в Slack если раздел старше 24 часов.",{"type":32,"tag":1464,"props":1902,"children":1903},{},[1904,1909,1911,1917],{"type":32,"tag":93,"props":1905,"children":1906},{},[1907],{"type":37,"value":1908},"Drift количества строк:",{"type":37,"value":1910}," если cohort_size сегодня отличается от вчерашнего на 30%, в pipeline данных есть проблема. Используйте запрос BigQuery с ",{"type":32,"tag":73,"props":1912,"children":1914},{"className":1913},[],[1915],{"type":37,"value":1916},"STDDEV()",{"type":37,"value":1918}," для контроля.",{"type":32,"tag":1464,"props":1920,"children":1921},{},[1922,1927,1929,1935],{"type":32,"tag":93,"props":1923,"children":1924},{},[1925],{"type":37,"value":1926},"Spike стоимости запросов:",{"type":37,"value":1928}," если средняя стоимость запроса к таблице когорт выросла с $0.01 до $0.10, partition pruning не работает. Проверьте таблицу ",{"type":32,"tag":73,"props":1930,"children":1932},{"className":1931},[],[1933],{"type":37,"value":1934},"INFORMATION_SCHEMA.JOBS",{"type":37,"value":946},{"type":32,"tag":33,"props":1937,"children":1938},{},[1939],{"type":37,"value":1940},"Создайте Google Cloud Monitoring dashboard для этих",{"type":32,"tag":1942,"props":1943,"children":1944},"style",{},[1945],{"type":37,"value":1946},"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":193,"depth":193,"links":1948},[1949,1950,1951,1954,1955,1956],{"id":42,"depth":172,"text":45},{"id":63,"depth":172,"text":66},{"id":335,"depth":172,"text":338,"children":1952},[1953],{"id":1445,"depth":193,"text":1448},{"id":1510,"depth":172,"text":1513},{"id":1558,"depth":172,"text":1561},{"id":1870,"depth":172,"text":1873},"markdown","content:ru:data:arkhitektura-tablitsy-kogort-masshtabirovanie-analiza-sokhraneniya-v-production.md","content","ru\u002Fdata\u002Farkhitektura-tablitsy-kogort-masshtabirovanie-analiza-sokhraneniya-v-production.md","ru\u002Fdata\u002Farkhitektura-tablitsy-kogort-masshtabirovanie-analiza-sokhraneniya-v-production","md",1785103526733]