6523 lines
159 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Build Power. Not Rent It. Own your digital infrastructure.">
<meta name="author" content="Bunker Operations">
<link rel="canonical" href="https://bnkserve.org/v2/database/indexes/">
<link rel="prev" href="../seeding/">
<link rel="next" href="../models/">
<link rel="icon" href="../../../assets/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.1">
<title>Indexes - Changemaker Lite</title>
<link rel="stylesheet" href="../../../assets/stylesheets/main.484c7ddc.min.css">
<link rel="stylesheet" href="../../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="../../../stylesheets/extra.css">
<link rel="stylesheet" href="../../../stylesheets/home.css">
<link rel="stylesheet" href="../../../assets/css/video-player.css">
<script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<meta property="og:type" content="website" />
<meta property="og:title" content="Indexes - Changemaker Lite" />
<meta property="og:description" content="Build Power. Not Rent It. Own your digital infrastructure." />
<meta property="og:image" content="https://bnkserve.org/assets/images/social/v2/database/indexes.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://bnkserve.org/v2/database/indexes/" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:title" content="Indexes - Changemaker Lite" />
<meta property="twitter:description" content="Build Power. Not Rent It. Own your digital infrastructure." />
<meta property="twitter:image" content="https://bnkserve.org/assets/images/social/v2/database/indexes.png" />
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="amber">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#index-strategy-performance" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../../.." title="Changemaker Lite" class="md-header__button md-logo" aria-label="Changemaker Lite" data-md-component="logo">
<img src="../../../assets/logo.png" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Changemaker Lite
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Indexes
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="amber" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg>
</label>
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="deep-purple" data-md-color-accent="amber" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://gitea.bnkops.com/admin/changemaker.lite" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
changemaker.lite
</div>
</a>
</div>
</nav>
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../../" class="md-tabs__link">
V2 Documentation
</a>
</li>
<li class="md-tabs__item">
<a href="../../../phil/" class="md-tabs__link">
Philosophy
</a>
</li>
<li class="md-tabs__item">
<a href="../../../v1/" class="md-tabs__link">
V1 Documentation (Legacy)
</a>
</li>
<li class="md-tabs__item">
<a href="../../../blog/" class="md-tabs__link">
Blog
</a>
</li>
</ul>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../.." title="Changemaker Lite" class="md-nav__button md-logo" aria-label="Changemaker Lite" data-md-component="logo">
<img src="../../../assets/logo.png" alt="logo">
</a>
Changemaker Lite
</label>
<div class="md-nav__source">
<a href="https://gitea.bnkops.com/admin/changemaker.lite" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
changemaker.lite
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
<div class="md-nav__link md-nav__container">
<a href="../../" class="md-nav__link ">
<span class="md-ellipsis">
V2 Documentation
</span>
</a>
<label class="md-nav__link " for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
V2 Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_2" >
<div class="md-nav__link md-nav__container">
<a href="../../getting-started/" class="md-nav__link ">
<span class="md-ellipsis">
Getting Started
</span>
</a>
<label class="md-nav__link " for="__nav_2_2" id="__nav_2_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../getting-started/quick-start/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_3" >
<div class="md-nav__link md-nav__container">
<a href="../../architecture/" class="md-nav__link ">
<span class="md-ellipsis">
Architecture
</span>
</a>
<label class="md-nav__link " for="__nav_2_3" id="__nav_2_3_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_3">
<span class="md-nav__icon md-icon"></span>
Architecture
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../architecture/dual-api/" class="md-nav__link">
<span class="md-ellipsis">
Dual API System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../architecture/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication & Security
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_4" >
<div class="md-nav__link md-nav__container">
<a href="../../backend/" class="md-nav__link ">
<span class="md-ellipsis">
Backend
</span>
</a>
<label class="md-nav__link " for="__nav_2_4" id="__nav_2_4_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_4">
<span class="md-nav__icon md-icon"></span>
Backend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/modules/" class="md-nav__link">
<span class="md-ellipsis">
Modules
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/services/" class="md-nav__link">
<span class="md-ellipsis">
Services
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/middleware/" class="md-nav__link">
<span class="md-ellipsis">
Middleware
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/utilities/" class="md-nav__link">
<span class="md-ellipsis">
Utilities
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_5" >
<div class="md-nav__link md-nav__container">
<a href="../../frontend/" class="md-nav__link ">
<span class="md-ellipsis">
Frontend
</span>
</a>
<label class="md-nav__link " for="__nav_2_5" id="__nav_2_5_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_5">
<span class="md-nav__icon md-icon"></span>
Frontend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../frontend/components/" class="md-nav__link">
<span class="md-ellipsis">
Components
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../frontend/layouts/" class="md-nav__link">
<span class="md-ellipsis">
Layouts
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../frontend/pages/" class="md-nav__link">
<span class="md-ellipsis">
Pages
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_6" checked>
<div class="md-nav__link md-nav__container">
<a href="../" class="md-nav__link ">
<span class="md-ellipsis">
Database
</span>
</a>
<label class="md-nav__link " for="__nav_2_6" id="__nav_2_6_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_6_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2_6">
<span class="md-nav__icon md-icon"></span>
Database
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../schema/" class="md-nav__link">
<span class="md-ellipsis">
Schema Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../migrations/" class="md-nav__link">
<span class="md-ellipsis">
Migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../seeding/" class="md-nav__link">
<span class="md-ellipsis">
Seeding
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Indexes
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Indexes
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#overview" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-catalog" class="md-nav__link">
<span class="md-ellipsis">
Index Catalog
</span>
</a>
<nav class="md-nav" aria-label="Index Catalog">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#auth-users" class="md-nav__link">
<span class="md-ellipsis">
Auth &amp; Users
</span>
</a>
<nav class="md-nav" aria-label="Auth &amp; Users">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#user" class="md-nav__link">
<span class="md-ellipsis">
User
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#refreshtoken" class="md-nav__link">
<span class="md-ellipsis">
RefreshToken
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#influence" class="md-nav__link">
<span class="md-ellipsis">
Influence
</span>
</a>
<nav class="md-nav" aria-label="Influence">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#campaign" class="md-nav__link">
<span class="md-ellipsis">
Campaign
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#representative" class="md-nav__link">
<span class="md-ellipsis">
Representative
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#campaignemail" class="md-nav__link">
<span class="md-ellipsis">
CampaignEmail
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#representativeresponse" class="md-nav__link">
<span class="md-ellipsis">
RepresentativeResponse
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#responseupvote" class="md-nav__link">
<span class="md-ellipsis">
ResponseUpvote
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#customrecipient" class="md-nav__link">
<span class="md-ellipsis">
CustomRecipient
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#postalcodecache" class="md-nav__link">
<span class="md-ellipsis">
PostalCodeCache
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#call" class="md-nav__link">
<span class="md-ellipsis">
Call
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#map-locations" class="md-nav__link">
<span class="md-ellipsis">
Map — Locations
</span>
</a>
<nav class="md-nav" aria-label="Map — Locations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#location" class="md-nav__link">
<span class="md-ellipsis">
Location
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#address" class="md-nav__link">
<span class="md-ellipsis">
Address
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#locationhistory" class="md-nav__link">
<span class="md-ellipsis">
LocationHistory
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#map-shifts-cuts" class="md-nav__link">
<span class="md-ellipsis">
Map — Shifts &amp; Cuts
</span>
</a>
<nav class="md-nav" aria-label="Map — Shifts &amp; Cuts">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#shift" class="md-nav__link">
<span class="md-ellipsis">
Shift
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#shiftsignup" class="md-nav__link">
<span class="md-ellipsis">
ShiftSignup
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#canvassing" class="md-nav__link">
<span class="md-ellipsis">
Canvassing
</span>
</a>
<nav class="md-nav" aria-label="Canvassing">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#canvasssession" class="md-nav__link">
<span class="md-ellipsis">
CanvassSession
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#canvassvisit" class="md-nav__link">
<span class="md-ellipsis">
CanvassVisit
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#trackingsession" class="md-nav__link">
<span class="md-ellipsis">
TrackingSession
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#trackpoint" class="md-nav__link">
<span class="md-ellipsis">
TrackPoint
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#email-templates" class="md-nav__link">
<span class="md-ellipsis">
Email Templates
</span>
</a>
<nav class="md-nav" aria-label="Email Templates">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#emailtemplate" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#emailtemplatevariable" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplateVariable
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#emailtemplateversion" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplateVersion
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#emailtemplatetestlog" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplateTestLog
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#landing-pages" class="md-nav__link">
<span class="md-ellipsis">
Landing Pages
</span>
</a>
<nav class="md-nav" aria-label="Landing Pages">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#landingpage" class="md-nav__link">
<span class="md-ellipsis">
LandingPage
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#media-drizzle-orm" class="md-nav__link">
<span class="md-ellipsis">
Media (Drizzle ORM)
</span>
</a>
<nav class="md-nav" aria-label="Media (Drizzle ORM)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#videos" class="md-nav__link">
<span class="md-ellipsis">
videos
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#jobs" class="md-nav__link">
<span class="md-ellipsis">
jobs
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#query-optimization-patterns" class="md-nav__link">
<span class="md-ellipsis">
Query Optimization Patterns
</span>
</a>
<nav class="md-nav" aria-label="Query Optimization Patterns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-use-indexes-for-where-clauses" class="md-nav__link">
<span class="md-ellipsis">
1. Use Indexes for WHERE Clauses
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-use-composite-indexes-for-multi-column-filters" class="md-nav__link">
<span class="md-ellipsis">
2. Use Composite Indexes for Multi-Column Filters
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-use-foreign-key-indexes-for-joins" class="md-nav__link">
<span class="md-ellipsis">
3. Use Foreign Key Indexes for JOINs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-use-unique-indexes-for-deduplication" class="md-nav__link">
<span class="md-ellipsis">
4. Use Unique Indexes for Deduplication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-use-temporal-indexes-for-date-filtering" class="md-nav__link">
<span class="md-ellipsis">
5. Use Temporal Indexes for Date Filtering
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#index-selectivity" class="md-nav__link">
<span class="md-ellipsis">
Index Selectivity
</span>
</a>
<nav class="md-nav" aria-label="Index Selectivity">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#high-selectivity-good" class="md-nav__link">
<span class="md-ellipsis">
High Selectivity (Good)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#medium-selectivity-okay" class="md-nav__link">
<span class="md-ellipsis">
Medium Selectivity (Okay)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#low-selectivity-poor-for-filtering-good-for-covering-index" class="md-nav__link">
<span class="md-ellipsis">
Low Selectivity (Poor for filtering, good for covering index)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#index-maintenance" class="md-nav__link">
<span class="md-ellipsis">
Index Maintenance
</span>
</a>
<nav class="md-nav" aria-label="Index Maintenance">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#prisma-indexes-automatic" class="md-nav__link">
<span class="md-ellipsis">
Prisma Indexes (Automatic)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#drizzle-indexes-manual-in-schema" class="md-nav__link">
<span class="md-ellipsis">
Drizzle Indexes (Manual in Schema)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-size-monitoring" class="md-nav__link">
<span class="md-ellipsis">
Index Size Monitoring
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unused-index-detection" class="md-nav__link">
<span class="md-ellipsis">
Unused Index Detection
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#performance-considerations" class="md-nav__link">
<span class="md-ellipsis">
Performance Considerations
</span>
</a>
<nav class="md-nav" aria-label="Performance Considerations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#index-trade-offs" class="md-nav__link">
<span class="md-ellipsis">
Index Trade-offs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#query-planning" class="md-nav__link">
<span class="md-ellipsis">
Query Planning
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-bloat" class="md-nav__link">
<span class="md-ellipsis">
Index Bloat
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#common-performance-issues" class="md-nav__link">
<span class="md-ellipsis">
Common Performance Issues
</span>
</a>
<nav class="md-nav" aria-label="Common Performance Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#issue-slow-campaign-email-stats-query" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow campaign email stats query
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#issue-slow-location-bounding-box-queries" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow location bounding box queries
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#issue-slow-active-session-cleanup" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow active session cleanup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#issue-slow-template-version-history" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow template version history
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related-documentation" class="md-nav__link">
<span class="md-ellipsis">
Related Documentation
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_7" >
<div class="md-nav__link md-nav__container">
<a href="../../features/" class="md-nav__link ">
<span class="md-ellipsis">
Features
</span>
</a>
<label class="md-nav__link " for="__nav_2_7" id="__nav_2_7_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_7">
<span class="md-nav__icon md-icon"></span>
Features
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/influence/" class="md-nav__link">
<span class="md-ellipsis">
Influence
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/map/" class="md-nav__link">
<span class="md-ellipsis">
Map
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/landing-pages/" class="md-nav__link">
<span class="md-ellipsis">
Landing Pages
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/email-templates/" class="md-nav__link">
<span class="md-ellipsis">
Email Templates
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/media/" class="md-nav__link">
<span class="md-ellipsis">
Media
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/newsletter/" class="md-nav__link">
<span class="md-ellipsis">
Newsletter
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/observability/" class="md-nav__link">
<span class="md-ellipsis">
Observability
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/tunnel/" class="md-nav__link">
<span class="md-ellipsis">
Tunnel
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_8" >
<div class="md-nav__link md-nav__container">
<a href="../../deployment/" class="md-nav__link ">
<span class="md-ellipsis">
Deployment
</span>
</a>
<label class="md-nav__link " for="__nav_2_8" id="__nav_2_8_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_8">
<span class="md-nav__icon md-icon"></span>
Deployment
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../deployment/docker-compose/" class="md-nav__link">
<span class="md-ellipsis">
Docker Compose
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/environment-variables/" class="md-nav__link">
<span class="md-ellipsis">
Environment Variables
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/nginx/" class="md-nav__link">
<span class="md-ellipsis">
Nginx Configuration
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/ssl-tls/" class="md-nav__link">
<span class="md-ellipsis">
SSL/TLS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/tunneling/" class="md-nav__link">
<span class="md-ellipsis">
Tunneling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/monitoring-stack/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Stack
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/healthchecks/" class="md-nav__link">
<span class="md-ellipsis">
Health Checks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/scaling/" class="md-nav__link">
<span class="md-ellipsis">
Scaling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/backup-restore/" class="md-nav__link">
<span class="md-ellipsis">
Backup & Restore
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_9" >
<div class="md-nav__link md-nav__container">
<a href="../../development/" class="md-nav__link ">
<span class="md-ellipsis">
Development
</span>
</a>
<label class="md-nav__link " for="__nav_2_9" id="__nav_2_9_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_9">
<span class="md-nav__icon md-icon"></span>
Development
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../development/local-setup/" class="md-nav__link">
<span class="md-ellipsis">
Local Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/docker-workflow/" class="md-nav__link">
<span class="md-ellipsis">
Docker Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/git-workflow/" class="md-nav__link">
<span class="md-ellipsis">
Git Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/npm-commands/" class="md-nav__link">
<span class="md-ellipsis">
NPM Commands
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/migrations/" class="md-nav__link">
<span class="md-ellipsis">
Migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/typescript/" class="md-nav__link">
<span class="md-ellipsis">
TypeScript
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/debugging/" class="md-nav__link">
<span class="md-ellipsis">
Debugging
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/code-style/" class="md-nav__link">
<span class="md-ellipsis">
Code Style
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_10" >
<div class="md-nav__link md-nav__container">
<a href="../../api-reference/" class="md-nav__link ">
<span class="md-ellipsis">
API Reference
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_10">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_11" >
<div class="md-nav__link md-nav__container">
<a href="../../user-guides/" class="md-nav__link ">
<span class="md-ellipsis">
User Guides
</span>
</a>
<label class="md-nav__link " for="__nav_2_11" id="__nav_2_11_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_11">
<span class="md-nav__icon md-icon"></span>
User Guides
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guides/admin-guide/" class="md-nav__link">
<span class="md-ellipsis">
Admin Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/campaign-manager-guide/" class="md-nav__link">
<span class="md-ellipsis">
Campaign Manager Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/map-organizer-guide/" class="md-nav__link">
<span class="md-ellipsis">
Map Organizer Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/content-editor-guide/" class="md-nav__link">
<span class="md-ellipsis">
Content Editor Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/volunteer-guide/" class="md-nav__link">
<span class="md-ellipsis">
Volunteer Guide
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_12" >
<div class="md-nav__link md-nav__container">
<a href="../../troubleshooting/" class="md-nav__link ">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
<label class="md-nav__link " for="__nav_2_12" id="__nav_2_12_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_12_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_12">
<span class="md-nav__icon md-icon"></span>
Troubleshooting
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../troubleshooting/faq/" class="md-nav__link">
<span class="md-ellipsis">
FAQ
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/common-errors/" class="md-nav__link">
<span class="md-ellipsis">
Common Errors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/auth-issues/" class="md-nav__link">
<span class="md-ellipsis">
Auth Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/database-issues/" class="md-nav__link">
<span class="md-ellipsis">
Database Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/docker-issues/" class="md-nav__link">
<span class="md-ellipsis">
Docker Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/email-issues/" class="md-nav__link">
<span class="md-ellipsis">
Email Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/geocoding-issues/" class="md-nav__link">
<span class="md-ellipsis">
Geocoding Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/monitoring-issues/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../troubleshooting/performance-optimization/" class="md-nav__link">
<span class="md-ellipsis">
Performance Optimization
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_13" >
<div class="md-nav__link md-nav__container">
<a href="../../migration/" class="md-nav__link ">
<span class="md-ellipsis">
Migration
</span>
</a>
<label class="md-nav__link " for="__nav_2_13" id="__nav_2_13_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_13_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_13">
<span class="md-nav__icon md-icon"></span>
Migration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../migration/feature-parity/" class="md-nav__link">
<span class="md-ellipsis">
Feature Parity
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../migration/breaking-changes/" class="md-nav__link">
<span class="md-ellipsis">
Breaking Changes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../migration/api-changes/" class="md-nav__link">
<span class="md-ellipsis">
API Changes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../migration/data-migration/" class="md-nav__link">
<span class="md-ellipsis">
Data Migration
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_14" >
<div class="md-nav__link md-nav__container">
<a href="../../contributing/" class="md-nav__link ">
<span class="md-ellipsis">
Contributing
</span>
</a>
<label class="md-nav__link " for="__nav_2_14" id="__nav_2_14_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_14_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_14">
<span class="md-nav__icon md-icon"></span>
Contributing
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../contributing/development-setup/" class="md-nav__link">
<span class="md-ellipsis">
Development Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../contributing/code-of-conduct/" class="md-nav__link">
<span class="md-ellipsis">
Code of Conduct
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../contributing/pull-requests/" class="md-nav__link">
<span class="md-ellipsis">
Pull Requests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../contributing/roadmap/" class="md-nav__link">
<span class="md-ellipsis">
Roadmap
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../phil/" class="md-nav__link">
<span class="md-ellipsis">
Philosophy
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../v1/" class="md-nav__link">
<span class="md-ellipsis">
V1 Documentation (Legacy)
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../blog/" class="md-nav__link">
<span class="md-ellipsis">
Blog
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#overview" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-catalog" class="md-nav__link">
<span class="md-ellipsis">
Index Catalog
</span>
</a>
<nav class="md-nav" aria-label="Index Catalog">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#auth-users" class="md-nav__link">
<span class="md-ellipsis">
Auth &amp; Users
</span>
</a>
<nav class="md-nav" aria-label="Auth &amp; Users">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#user" class="md-nav__link">
<span class="md-ellipsis">
User
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#refreshtoken" class="md-nav__link">
<span class="md-ellipsis">
RefreshToken
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#influence" class="md-nav__link">
<span class="md-ellipsis">
Influence
</span>
</a>
<nav class="md-nav" aria-label="Influence">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#campaign" class="md-nav__link">
<span class="md-ellipsis">
Campaign
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#representative" class="md-nav__link">
<span class="md-ellipsis">
Representative
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#campaignemail" class="md-nav__link">
<span class="md-ellipsis">
CampaignEmail
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#representativeresponse" class="md-nav__link">
<span class="md-ellipsis">
RepresentativeResponse
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#responseupvote" class="md-nav__link">
<span class="md-ellipsis">
ResponseUpvote
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#customrecipient" class="md-nav__link">
<span class="md-ellipsis">
CustomRecipient
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#postalcodecache" class="md-nav__link">
<span class="md-ellipsis">
PostalCodeCache
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#call" class="md-nav__link">
<span class="md-ellipsis">
Call
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#map-locations" class="md-nav__link">
<span class="md-ellipsis">
Map — Locations
</span>
</a>
<nav class="md-nav" aria-label="Map — Locations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#location" class="md-nav__link">
<span class="md-ellipsis">
Location
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#address" class="md-nav__link">
<span class="md-ellipsis">
Address
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#locationhistory" class="md-nav__link">
<span class="md-ellipsis">
LocationHistory
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#map-shifts-cuts" class="md-nav__link">
<span class="md-ellipsis">
Map — Shifts &amp; Cuts
</span>
</a>
<nav class="md-nav" aria-label="Map — Shifts &amp; Cuts">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#shift" class="md-nav__link">
<span class="md-ellipsis">
Shift
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#shiftsignup" class="md-nav__link">
<span class="md-ellipsis">
ShiftSignup
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#canvassing" class="md-nav__link">
<span class="md-ellipsis">
Canvassing
</span>
</a>
<nav class="md-nav" aria-label="Canvassing">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#canvasssession" class="md-nav__link">
<span class="md-ellipsis">
CanvassSession
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#canvassvisit" class="md-nav__link">
<span class="md-ellipsis">
CanvassVisit
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#trackingsession" class="md-nav__link">
<span class="md-ellipsis">
TrackingSession
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#trackpoint" class="md-nav__link">
<span class="md-ellipsis">
TrackPoint
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#email-templates" class="md-nav__link">
<span class="md-ellipsis">
Email Templates
</span>
</a>
<nav class="md-nav" aria-label="Email Templates">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#emailtemplate" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#emailtemplatevariable" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplateVariable
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#emailtemplateversion" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplateVersion
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#emailtemplatetestlog" class="md-nav__link">
<span class="md-ellipsis">
EmailTemplateTestLog
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#landing-pages" class="md-nav__link">
<span class="md-ellipsis">
Landing Pages
</span>
</a>
<nav class="md-nav" aria-label="Landing Pages">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#landingpage" class="md-nav__link">
<span class="md-ellipsis">
LandingPage
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#media-drizzle-orm" class="md-nav__link">
<span class="md-ellipsis">
Media (Drizzle ORM)
</span>
</a>
<nav class="md-nav" aria-label="Media (Drizzle ORM)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#videos" class="md-nav__link">
<span class="md-ellipsis">
videos
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#jobs" class="md-nav__link">
<span class="md-ellipsis">
jobs
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#query-optimization-patterns" class="md-nav__link">
<span class="md-ellipsis">
Query Optimization Patterns
</span>
</a>
<nav class="md-nav" aria-label="Query Optimization Patterns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-use-indexes-for-where-clauses" class="md-nav__link">
<span class="md-ellipsis">
1. Use Indexes for WHERE Clauses
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-use-composite-indexes-for-multi-column-filters" class="md-nav__link">
<span class="md-ellipsis">
2. Use Composite Indexes for Multi-Column Filters
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-use-foreign-key-indexes-for-joins" class="md-nav__link">
<span class="md-ellipsis">
3. Use Foreign Key Indexes for JOINs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-use-unique-indexes-for-deduplication" class="md-nav__link">
<span class="md-ellipsis">
4. Use Unique Indexes for Deduplication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-use-temporal-indexes-for-date-filtering" class="md-nav__link">
<span class="md-ellipsis">
5. Use Temporal Indexes for Date Filtering
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#index-selectivity" class="md-nav__link">
<span class="md-ellipsis">
Index Selectivity
</span>
</a>
<nav class="md-nav" aria-label="Index Selectivity">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#high-selectivity-good" class="md-nav__link">
<span class="md-ellipsis">
High Selectivity (Good)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#medium-selectivity-okay" class="md-nav__link">
<span class="md-ellipsis">
Medium Selectivity (Okay)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#low-selectivity-poor-for-filtering-good-for-covering-index" class="md-nav__link">
<span class="md-ellipsis">
Low Selectivity (Poor for filtering, good for covering index)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#index-maintenance" class="md-nav__link">
<span class="md-ellipsis">
Index Maintenance
</span>
</a>
<nav class="md-nav" aria-label="Index Maintenance">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#prisma-indexes-automatic" class="md-nav__link">
<span class="md-ellipsis">
Prisma Indexes (Automatic)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#drizzle-indexes-manual-in-schema" class="md-nav__link">
<span class="md-ellipsis">
Drizzle Indexes (Manual in Schema)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-size-monitoring" class="md-nav__link">
<span class="md-ellipsis">
Index Size Monitoring
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unused-index-detection" class="md-nav__link">
<span class="md-ellipsis">
Unused Index Detection
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#performance-considerations" class="md-nav__link">
<span class="md-ellipsis">
Performance Considerations
</span>
</a>
<nav class="md-nav" aria-label="Performance Considerations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#index-trade-offs" class="md-nav__link">
<span class="md-ellipsis">
Index Trade-offs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#query-planning" class="md-nav__link">
<span class="md-ellipsis">
Query Planning
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#index-bloat" class="md-nav__link">
<span class="md-ellipsis">
Index Bloat
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#common-performance-issues" class="md-nav__link">
<span class="md-ellipsis">
Common Performance Issues
</span>
</a>
<nav class="md-nav" aria-label="Common Performance Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#issue-slow-campaign-email-stats-query" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow campaign email stats query
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#issue-slow-location-bounding-box-queries" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow location bounding box queries
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#issue-slow-active-session-cleanup" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow active session cleanup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#issue-slow-template-version-history" class="md-nav__link">
<span class="md-ellipsis">
Issue: Slow template version history
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related-documentation" class="md-nav__link">
<span class="md-ellipsis">
Related Documentation
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<nav class="md-path" aria-label="Navigation" >
<ol class="md-path__list">
<li class="md-path__item">
<a href="../../.." class="md-path__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-path__item">
<a href="../../" class="md-path__link">
<span class="md-ellipsis">
V2 Documentation
</span>
</a>
</li>
<li class="md-path__item">
<a href="../" class="md-path__link">
<span class="md-ellipsis">
Database
</span>
</a>
</li>
</ol>
</nav>
<article class="md-content__inner md-typeset">
<a href="https://gitea.bnkops.com/admin/changemaker.lite/src/branch/main/mkdocs/docs/v2/database/indexes.md" title="Edit this page" class="md-content__button md-icon" rel="edit">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg>
</a>
<a href="https://gitea.bnkops.com/admin/changemaker.lite/src/branch/main/mkdocs/docs/v2/database/indexes.md" title="View source of this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg>
</a>
<h1 id="index-strategy-performance">Index Strategy &amp; Performance<a class="headerlink" href="#index-strategy-performance" title="Permanent link">&para;</a></h1>
<h2 id="overview">Overview<a class="headerlink" href="#overview" title="Permanent link">&para;</a></h2>
<p>Changemaker Lite V2 uses strategic indexing across 33 models to optimize query performance. This document catalogs all indexes, explains their purpose, and provides query optimization guidance.</p>
<p><strong>Total Indexes:</strong> 60+ (Prisma: 50+, Drizzle: 10+)</p>
<p><strong>Index Types:</strong>
- <strong>Unique indexes</strong> — Enforce uniqueness constraints (email, slug, token, etc.)
- <strong>Foreign key indexes</strong> — Optimize JOIN operations (userId, campaignId, locationId, etc.)
- <strong>Composite indexes</strong> — Multi-column indexes for complex queries
- <strong>Spatial indexes</strong> — Latitude/longitude for geographic queries</p>
<hr />
<h2 id="index-catalog">Index Catalog<a class="headerlink" href="#index-catalog" title="Permanent link">&para;</a></h2>
<h3 id="auth-users">Auth &amp; Users<a class="headerlink" href="#auth-users" title="Permanent link">&para;</a></h3>
<h4 id="user">User<a class="headerlink" href="#user" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>email</code> — Login lookups (<code>WHERE email = ?</code>)</li>
</ul>
<h4 id="refreshtoken">RefreshToken<a class="headerlink" href="#refreshtoken" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>token</code> — Refresh endpoint lookups (<code>WHERE token = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>userId</code> — User deletion cascades</li>
</ul>
<hr />
<h3 id="influence">Influence<a class="headerlink" href="#influence" title="Permanent link">&para;</a></h3>
<h4 id="campaign">Campaign<a class="headerlink" href="#campaign" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>slug</code> — Public campaign page lookups (<code>WHERE slug = ?</code>)</li>
</ul>
<h4 id="representative">Representative<a class="headerlink" href="#representative" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Non-unique:</strong> <code>postalCode</code> — Postal code lookups (<code>WHERE postalCode = ?</code>)</li>
</ul>
<h4 id="campaignemail">CampaignEmail<a class="headerlink" href="#campaignemail" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>campaignId</code> — Campaign email stats (<code>JOIN campaign_emails ON campaign_id = ?</code>)</li>
<li><strong>Non-unique:</strong> <code>campaignSlug</code> — Slug-based queries</li>
</ul>
<h4 id="representativeresponse">RepresentativeResponse<a class="headerlink" href="#representativeresponse" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>campaignId</code> — Campaign response wall (<code>JOIN representative_responses ON campaign_id = ?</code>)</li>
<li><strong>Non-unique:</strong> <code>campaignSlug</code> — Slug-based queries</li>
</ul>
<h4 id="responseupvote">ResponseUpvote<a class="headerlink" href="#responseupvote" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>[responseId, userId]</code> — Prevent duplicate upvotes from logged-in users</li>
<li><strong>Unique:</strong> <code>[responseId, upvotedIp]</code> — Prevent duplicate upvotes from same IP</li>
</ul>
<h4 id="customrecipient">CustomRecipient<a class="headerlink" href="#customrecipient" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>campaignId</code> — Campaign custom recipients (<code>JOIN custom_recipients ON campaign_id = ?</code>)</li>
</ul>
<h4 id="postalcodecache">PostalCodeCache<a class="headerlink" href="#postalcodecache" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>postalCode</code> — Postal code cache lookups (<code>WHERE postal_code = ?</code>)</li>
</ul>
<h4 id="call">Call<a class="headerlink" href="#call" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>campaignId</code> — Campaign call tracking (<code>JOIN calls ON campaign_id = ?</code>)</li>
</ul>
<hr />
<h3 id="map-locations">Map — Locations<a class="headerlink" href="#map-locations" title="Permanent link">&para;</a></h3>
<h4 id="location">Location<a class="headerlink" href="#location" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>locGuid</code> — NAR location GUID lookups</li>
<li><strong>Composite:</strong> <code>[latitude, longitude]</code><strong>Spatial queries</strong> (nearby locations, bounding box searches)</li>
<li><strong>Non-unique:</strong> <code>postalCode</code> — Postal code filtering</li>
</ul>
<p><strong>Query Optimization:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1">-- Uses composite index for bounding box queries</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">locations</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">latitude</span><span class="w"> </span><span class="k">BETWEEN</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="o">?</span>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">longitude</span><span class="w"> </span><span class="k">BETWEEN</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="o">?</span><span class="p">;</span>
</span></code></pre></div></p>
<h4 id="address">Address<a class="headerlink" href="#address" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>addrGuid</code> — NAR address GUID lookups</li>
<li><strong>Foreign Key:</strong> <code>locationId</code> — Location addresses (<code>JOIN addresses ON location_id = ?</code>)</li>
<li><strong>Composite:</strong> <code>[locationId, unitNumber]</code><strong>Unit lookups within building</strong></li>
</ul>
<p><strong>Query Optimization:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="c1">-- Uses composite index for unit-specific queries</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">addresses</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">location_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">unit_number</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">?</span><span class="p">;</span>
</span></code></pre></div></p>
<h4 id="locationhistory">LocationHistory<a class="headerlink" href="#locationhistory" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>locationId</code> — Location history (<code>JOIN location_history ON location_id = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>userId</code> — User edit history (<code>JOIN location_history ON user_id = ?</code>)</li>
<li><strong>Non-unique:</strong> <code>createdAt</code><strong>Temporal queries</strong> (recent edits, audit trails)</li>
</ul>
<hr />
<h3 id="map-shifts-cuts">Map — Shifts &amp; Cuts<a class="headerlink" href="#map-shifts-cuts" title="Permanent link">&para;</a></h3>
<h4 id="shift">Shift<a class="headerlink" href="#shift" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>cutId</code> — Cut shifts (<code>JOIN shifts ON cut_id = ?</code>)</li>
</ul>
<h4 id="shiftsignup">ShiftSignup<a class="headerlink" href="#shiftsignup" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>[shiftId, userEmail]</code><strong>Prevent duplicate shift signups</strong></li>
<li><strong>Foreign Key:</strong> <code>shiftId</code> — Shift signups (<code>JOIN shift_signups ON shift_id = ?</code>)</li>
</ul>
<hr />
<h3 id="canvassing">Canvassing<a class="headerlink" href="#canvassing" title="Permanent link">&para;</a></h3>
<h4 id="canvasssession">CanvassSession<a class="headerlink" href="#canvasssession" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>userId</code> — User canvass sessions (<code>JOIN canvass_sessions ON user_id = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>cutId</code> — Cut canvass sessions (<code>JOIN canvass_sessions ON cut_id = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>shiftId</code> — Shift canvass sessions (<code>JOIN canvass_sessions ON shift_id = ?</code>)</li>
</ul>
<h4 id="canvassvisit">CanvassVisit<a class="headerlink" href="#canvassvisit" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Foreign Key:</strong> <code>addressId</code> — Address visit history (<code>JOIN canvass_visits ON address_id = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>userId</code> — User visit history (<code>JOIN canvass_visits ON user_id = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>shiftId</code> — Shift visits (<code>JOIN canvass_visits ON shift_id = ?</code>)</li>
<li><strong>Foreign Key:</strong> <code>sessionId</code> — Session visits (<code>JOIN canvass_visits ON session_id = ?</code>)</li>
<li><strong>Non-unique:</strong> <code>visitedAt</code><strong>Temporal queries</strong> (recent visits, activity feeds)</li>
</ul>
<h4 id="trackingsession">TrackingSession<a class="headerlink" href="#trackingsession" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>canvassSessionId</code><strong>One-to-one relationship</strong> with CanvassSession</li>
<li><strong>Foreign Key:</strong> <code>userId</code> — User GPS sessions (<code>JOIN tracking_sessions ON user_id = ?</code>)</li>
<li><strong>Non-unique:</strong> <code>isActive</code> — Active session filtering (<code>WHERE is_active = true</code>)</li>
<li><strong>Composite:</strong> <code>[isActive, lastRecordedAt]</code><strong>Session cleanup queries</strong> (abandoned sessions)</li>
</ul>
<p><strong>Query Optimization:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="c1">-- Uses composite index for abandoned session cleanup</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">tracking_sessions</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">is_active</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">true</span>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">last_recorded_at</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">NOW</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nb">INTERVAL</span><span class="w"> </span><span class="s1">&#39;12 hours&#39;</span><span class="p">;</span>
</span></code></pre></div></p>
<h4 id="trackpoint">TrackPoint<a class="headerlink" href="#trackpoint" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Composite:</strong> <code>[trackingSessionId, recordedAt]</code><strong>Temporal GPS queries</strong> (session breadcrumb trail)</li>
<li><strong>Non-unique:</strong> <code>recordedAt</code> — Cross-session temporal queries</li>
</ul>
<hr />
<h3 id="email-templates">Email Templates<a class="headerlink" href="#email-templates" title="Permanent link">&para;</a></h3>
<h4 id="emailtemplate">EmailTemplate<a class="headerlink" href="#emailtemplate" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>key</code> — Template key lookups (<code>WHERE key = 'campaign-email'</code>)</li>
<li><strong>Non-unique:</strong> <code>category</code> — Category filtering (<code>WHERE category = 'INFLUENCE'</code>)</li>
<li><strong>Non-unique:</strong> <code>isActive</code> — Active template filtering (<code>WHERE is_active = true</code>)</li>
</ul>
<h4 id="emailtemplatevariable">EmailTemplateVariable<a class="headerlink" href="#emailtemplatevariable" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>[templateId, key]</code><strong>Unique variable keys per template</strong></li>
<li><strong>Foreign Key:</strong> <code>templateId</code> — Template variables (<code>JOIN email_template_variables ON template_id = ?</code>)</li>
</ul>
<h4 id="emailtemplateversion">EmailTemplateVersion<a class="headerlink" href="#emailtemplateversion" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>[templateId, versionNumber]</code><strong>Sequential version numbers per template</strong></li>
<li><strong>Composite:</strong> <code>[templateId, createdAt(sort: Desc)]</code><strong>Recent version history</strong></li>
</ul>
<p><strong>Query Optimization:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1">-- Uses composite index for recent version queries</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">email_template_versions</span>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">template_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">?</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">created_at</span><span class="w"> </span><span class="k">DESC</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="k">LIMIT</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
</span></code></pre></div></p>
<h4 id="emailtemplatetestlog">EmailTemplateTestLog<a class="headerlink" href="#emailtemplatetestlog" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Composite:</strong> <code>[templateId, sentAt(sort: Desc)]</code><strong>Recent test logs</strong></li>
</ul>
<hr />
<h3 id="landing-pages">Landing Pages<a class="headerlink" href="#landing-pages" title="Permanent link">&para;</a></h3>
<h4 id="landingpage">LandingPage<a class="headerlink" href="#landingpage" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>slug</code> — Public page lookups (<code>WHERE slug = 'about'</code>)</li>
</ul>
<hr />
<h3 id="media-drizzle-orm">Media (Drizzle ORM)<a class="headerlink" href="#media-drizzle-orm" title="Permanent link">&para;</a></h3>
<h4 id="videos">videos<a class="headerlink" href="#videos" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Unique:</strong> <code>path</code> — File path lookups (<code>WHERE path = '/media/local/videos/file.mp4'</code>)</li>
<li><strong>Non-unique:</strong> <code>orientation</code> — Orientation filtering (<code>WHERE orientation = 'landscape'</code>)</li>
<li><strong>Non-unique:</strong> <code>producer</code> — Producer filtering (<code>WHERE producer = 'Studio A'</code>)</li>
<li><strong>Non-unique:</strong> <code>isValid</code> — Valid video filtering (<code>WHERE is_valid = true</code>)</li>
<li><strong>Non-unique:</strong> <code>directoryType</code> — Directory type filtering (<code>WHERE directory_type = 'studios'</code>)</li>
<li><strong>Composite:</strong> <code>[durationSeconds, fileSize, width, height]</code><strong>Fingerprint matching</strong> (duplicate detection)</li>
<li><strong>Composite:</strong> <code>[directoryType, isValid, orientation]</code><strong>Common filtering pattern</strong></li>
</ul>
<p><strong>Query Optimization:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="c1">-- Uses composite index for common video library queries</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">videos</span>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">directory_type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;studios&#39;</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">is_valid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">true</span>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">orientation</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;landscape&#39;</span><span class="p">;</span>
</span></code></pre></div></p>
<h4 id="jobs">jobs<a class="headerlink" href="#jobs" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Composite:</strong> <code>[status, priority, createdAt]</code><strong>Job queue processing</strong></li>
<li><strong>Composite:</strong> <code>[resourceCategory, status]</code><strong>Resource-based filtering</strong></li>
<li><strong>Non-unique:</strong> <code>pipelineId</code> — Pipeline job filtering</li>
</ul>
<p><strong>Query Optimization:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="c1">-- Uses composite index for job queue queries</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">jobs</span>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;pending&#39;</span>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">priority</span><span class="w"> </span><span class="k">ASC</span><span class="p">,</span><span class="w"> </span><span class="n">created_at</span><span class="w"> </span><span class="k">ASC</span>
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="k">LIMIT</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
</span></code></pre></div></p>
<hr />
<h2 id="query-optimization-patterns">Query Optimization Patterns<a class="headerlink" href="#query-optimization-patterns" title="Permanent link">&para;</a></h2>
<h3 id="1-use-indexes-for-where-clauses">1. Use Indexes for WHERE Clauses<a class="headerlink" href="#1-use-indexes-for-where-clauses" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="c1">// ✅ Uses email unique index</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">findUnique</span><span class="p">({</span><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">email</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;user@example.com&#39;</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">});</span>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a>
</span><span id="__span-6-4"><a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="c1">// ❌ Full table scan (no index on name)</span>
</span><span id="__span-6-5"><a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;John&#39;</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">});</span>
</span></code></pre></div>
<h3 id="2-use-composite-indexes-for-multi-column-filters">2. Use Composite Indexes for Multi-Column Filters<a class="headerlink" href="#2-use-composite-indexes-for-multi-column-filters" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="c1">// ✅ Uses [latitude, longitude] composite index</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="nx">latitude</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">gte</span><span class="o">:</span><span class="w"> </span><span class="kt">53.5</span><span class="p">,</span><span class="w"> </span><span class="nx">lte</span><span class="o">:</span><span class="w"> </span><span class="kt">53.6</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="w"> </span><span class="nx">longitude</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">gte</span><span class="o">:</span><span class="w"> </span><span class="o">-</span><span class="mf">113.5</span><span class="p">,</span><span class="w"> </span><span class="nx">lte</span><span class="o">:</span><span class="w"> </span><span class="o">-</span><span class="mf">113.4</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-7-6"><a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-7-7"><a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="p">});</span>
</span><span id="__span-7-8"><a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a>
</span><span id="__span-7-9"><a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="c1">// ❌ Less efficient (only uses latitude index)</span>
</span><span id="__span-7-10"><a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span><span id="__span-7-11"><a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-7-12"><a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a><span class="w"> </span><span class="nx">latitude</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">gte</span><span class="o">:</span><span class="w"> </span><span class="kt">53.5</span><span class="p">,</span><span class="w"> </span><span class="nx">lte</span><span class="o">:</span><span class="w"> </span><span class="kt">53.6</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-7-13"><a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a><span class="w"> </span><span class="c1">// longitude filter applied after index scan</span>
</span><span id="__span-7-14"><a id="__codelineno-7-14" name="__codelineno-7-14" href="#__codelineno-7-14"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-7-15"><a id="__codelineno-7-15" name="__codelineno-7-15" href="#__codelineno-7-15"></a><span class="p">});</span>
</span></code></pre></div>
<h3 id="3-use-foreign-key-indexes-for-joins">3. Use Foreign Key Indexes for JOINs<a class="headerlink" href="#3-use-foreign-key-indexes-for-joins" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="c1">// ✅ Uses campaignId foreign key index</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">campaign</span><span class="p">.</span><span class="nx">findUnique</span><span class="p">({</span>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="kt">campaignId</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="w"> </span><span class="nx">include</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">emails</span><span class="o">:</span><span class="w"> </span><span class="kt">true</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="c1">// JOIN uses index</span>
</span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="p">});</span>
</span><span id="__span-8-6"><a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a>
</span><span id="__span-8-7"><a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="c1">// ❌ N+1 query (loads emails one-by-one)</span>
</span><span id="__span-8-8"><a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a><span class="kd">const</span><span class="w"> </span><span class="nx">campaign</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">campaign</span><span class="p">.</span><span class="nx">findUnique</span><span class="p">({</span><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="kt">campaignId</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">});</span>
</span><span id="__span-8-9"><a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="kd">const</span><span class="w"> </span><span class="nx">emails</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">campaignEmail</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">campaignId</span><span class="o">:</span><span class="w"> </span><span class="kt">campaign.id</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">});</span>
</span></code></pre></div>
<h3 id="4-use-unique-indexes-for-deduplication">4. Use Unique Indexes for Deduplication<a class="headerlink" href="#4-use-unique-indexes-for-deduplication" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="c1">// ✅ Uses [responseId, userId] unique index</span>
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">responseUpvote</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="nx">data</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">responseId</span><span class="p">,</span><span class="w"> </span><span class="nx">userId</span><span class="p">,</span><span class="w"> </span><span class="nx">upvotedIp</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="p">});</span>
</span><span id="__span-9-5"><a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="c1">// Throws error if user already upvoted (database-level check)</span>
</span><span id="__span-9-6"><a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a>
</span><span id="__span-9-7"><a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a><span class="c1">// ❌ Application-level check (race condition)</span>
</span><span id="__span-9-8"><a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a><span class="kd">const</span><span class="w"> </span><span class="nx">existing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">responseUpvote</span><span class="p">.</span><span class="nx">findFirst</span><span class="p">({</span>
</span><span id="__span-9-9"><a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">responseId</span><span class="p">,</span><span class="w"> </span><span class="nx">userId</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-9-10"><a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a><span class="p">});</span>
</span><span id="__span-9-11"><a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">existing</span><span class="p">)</span><span class="w"> </span><span class="k">throw</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="ne">Error</span><span class="p">(</span><span class="s1">&#39;Already upvoted&#39;</span><span class="p">);</span>
</span><span id="__span-9-12"><a id="__codelineno-9-12" name="__codelineno-9-12" href="#__codelineno-9-12"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">responseUpvote</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span><span class="w"> </span><span class="nx">data</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">responseId</span><span class="p">,</span><span class="w"> </span><span class="nx">userId</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">});</span>
</span></code></pre></div>
<h3 id="5-use-temporal-indexes-for-date-filtering">5. Use Temporal Indexes for Date Filtering<a class="headerlink" href="#5-use-temporal-indexes-for-date-filtering" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="c1">// ✅ Uses createdAt index</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">locationHistory</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="nx">createdAt</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">gte</span><span class="o">:</span><span class="w"> </span><span class="kt">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="s1">&#39;2025-01-01&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-10-6"><a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="nx">orderBy</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">createdAt</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;desc&#39;</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-10-7"><a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="w"> </span><span class="nx">take</span><span class="o">:</span><span class="w"> </span><span class="kt">100</span><span class="p">,</span>
</span><span id="__span-10-8"><a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="p">});</span>
</span><span id="__span-10-9"><a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a>
</span><span id="__span-10-10"><a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="c1">// ❌ Full table scan (no index on field)</span>
</span><span id="__span-10-11"><a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">locationHistory</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span><span id="__span-10-12"><a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-10-13"><a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a><span class="w"> </span><span class="nx">oldValue</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">contains</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Calgary&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="c1">// No index</span>
</span><span id="__span-10-14"><a id="__codelineno-10-14" name="__codelineno-10-14" href="#__codelineno-10-14"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-10-15"><a id="__codelineno-10-15" name="__codelineno-10-15" href="#__codelineno-10-15"></a><span class="p">});</span>
</span></code></pre></div>
<hr />
<h2 id="index-selectivity">Index Selectivity<a class="headerlink" href="#index-selectivity" title="Permanent link">&para;</a></h2>
<p><strong>Selectivity</strong> = Percentage of unique values in indexed column. Higher selectivity = better index performance.</p>
<h3 id="high-selectivity-good">High Selectivity (Good)<a class="headerlink" href="#high-selectivity-good" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>email</strong> (User) — 100% unique (1 user per email)</li>
<li><strong>token</strong> (RefreshToken) — 100% unique (1 token per record)</li>
<li><strong>slug</strong> (Campaign, LandingPage) — 100% unique (1 record per slug)</li>
<li><strong>[responseId, userId]</strong> (ResponseUpvote) — High uniqueness (1 upvote per user per response)</li>
</ul>
<h3 id="medium-selectivity-okay">Medium Selectivity (Okay)<a class="headerlink" href="#medium-selectivity-okay" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>postalCode</strong> (Location) — ~50% unique (multiple locations per postal code)</li>
<li><strong>campaignId</strong> (CampaignEmail) — ~10% unique (100s of emails per campaign)</li>
<li><strong>directoryType</strong> (videos) — ~11% unique (9 directory types)</li>
</ul>
<h3 id="low-selectivity-poor-for-filtering-good-for-covering-index">Low Selectivity (Poor for filtering, good for covering index)<a class="headerlink" href="#low-selectivity-poor-for-filtering-good-for-covering-index" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>isActive</strong> (TrackingSession) — ~50% unique (active vs inactive)</li>
<li><strong>status</strong> (Campaign) — ~25% unique (4 statuses: DRAFT, ACTIVE, PAUSED, ARCHIVED)</li>
<li><strong>role</strong> (User) — ~20% unique (5 roles)</li>
</ul>
<p><strong>Optimization:</strong>
- Use low-selectivity indexes as <strong>first column in composite index</strong> only
- Example: <code>[isActive, lastRecordedAt]</code> uses <code>isActive</code> to narrow search, then <code>lastRecordedAt</code> for ordering</p>
<hr />
<h2 id="index-maintenance">Index Maintenance<a class="headerlink" href="#index-maintenance" title="Permanent link">&para;</a></h2>
<h3 id="prisma-indexes-automatic">Prisma Indexes (Automatic)<a class="headerlink" href="#prisma-indexes-automatic" title="Permanent link">&para;</a></h3>
<p>Prisma migrations automatically create indexes defined in <code>schema.prisma</code>:
<div class="language-text highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>model Location {
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a> latitude Decimal
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a> longitude Decimal
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a>
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a> @@index([latitude, longitude]) // Composite index
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a>}
</span></code></pre></div></p>
<h3 id="drizzle-indexes-manual-in-schema">Drizzle Indexes (Manual in Schema)<a class="headerlink" href="#drizzle-indexes-manual-in-schema" title="Permanent link">&para;</a></h3>
<p>Drizzle indexes defined in <code>schema.ts</code>:
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">videos</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">pgTable</span><span class="p">(</span><span class="s1">&#39;videos&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="w"> </span><span class="nx">directoryType</span><span class="o">:</span><span class="w"> </span><span class="kt">text</span><span class="p">(</span><span class="s1">&#39;directory_type&#39;</span><span class="p">),</span>
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a><span class="w"> </span><span class="nx">isValid</span><span class="o">:</span><span class="w"> </span><span class="kt">boolean</span><span class="p">(</span><span class="s1">&#39;is_valid&#39;</span><span class="p">),</span>
</span><span id="__span-12-4"><a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="w"> </span><span class="nx">orientation</span><span class="o">:</span><span class="w"> </span><span class="kt">text</span><span class="p">(</span><span class="s1">&#39;orientation&#39;</span><span class="p">),</span>
</span><span id="__span-12-5"><a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a><span class="p">},</span><span class="w"> </span><span class="p">(</span><span class="nx">table</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">({</span>
</span><span id="__span-12-6"><a id="__codelineno-12-6" name="__codelineno-12-6" href="#__codelineno-12-6"></a><span class="w"> </span><span class="nx">directoryValidOrientationIdx</span><span class="o">:</span><span class="w"> </span><span class="kt">index</span><span class="p">(</span><span class="s1">&#39;idx_videos_directory_valid_orientation&#39;</span><span class="p">)</span>
</span><span id="__span-12-7"><a id="__codelineno-12-7" name="__codelineno-12-7" href="#__codelineno-12-7"></a><span class="w"> </span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="nx">table</span><span class="p">.</span><span class="nx">directoryType</span><span class="p">,</span><span class="w"> </span><span class="nx">table</span><span class="p">.</span><span class="nx">isValid</span><span class="p">,</span><span class="w"> </span><span class="nx">table</span><span class="p">.</span><span class="nx">orientation</span><span class="p">),</span>
</span><span id="__span-12-8"><a id="__codelineno-12-8" name="__codelineno-12-8" href="#__codelineno-12-8"></a><span class="p">}));</span>
</span></code></pre></div></p>
<h3 id="index-size-monitoring">Index Size Monitoring<a class="headerlink" href="#index-size-monitoring" title="Permanent link">&para;</a></h3>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="c1">-- Check index sizes</span>
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="k">SELECT</span>
</span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a><span class="w"> </span><span class="n">tablename</span><span class="p">,</span>
</span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="w"> </span><span class="n">indexname</span><span class="p">,</span>
</span><span id="__span-13-5"><a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a><span class="w"> </span><span class="n">pg_size_pretty</span><span class="p">(</span><span class="n">pg_relation_size</span><span class="p">(</span><span class="n">indexrelid</span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">index_size</span>
</span><span id="__span-13-6"><a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a><span class="k">FROM</span><span class="w"> </span><span class="n">pg_stat_user_indexes</span>
</span><span id="__span-13-7"><a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">schemaname</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;public&#39;</span>
</span><span id="__span-13-8"><a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">pg_relation_size</span><span class="p">(</span><span class="n">indexrelid</span><span class="p">)</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span>
</span></code></pre></div>
<h3 id="unused-index-detection">Unused Index Detection<a class="headerlink" href="#unused-index-detection" title="Permanent link">&para;</a></h3>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="c1">-- Find indexes with zero scans (unused)</span>
</span><span id="__span-14-2"><a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a><span class="k">SELECT</span>
</span><span id="__span-14-3"><a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="w"> </span><span class="n">schemaname</span><span class="p">,</span>
</span><span id="__span-14-4"><a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="w"> </span><span class="n">tablename</span><span class="p">,</span>
</span><span id="__span-14-5"><a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a><span class="w"> </span><span class="n">indexname</span><span class="p">,</span>
</span><span id="__span-14-6"><a id="__codelineno-14-6" name="__codelineno-14-6" href="#__codelineno-14-6"></a><span class="w"> </span><span class="n">idx_scan</span><span class="p">,</span>
</span><span id="__span-14-7"><a id="__codelineno-14-7" name="__codelineno-14-7" href="#__codelineno-14-7"></a><span class="w"> </span><span class="n">pg_size_pretty</span><span class="p">(</span><span class="n">pg_relation_size</span><span class="p">(</span><span class="n">indexrelid</span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">index_size</span>
</span><span id="__span-14-8"><a id="__codelineno-14-8" name="__codelineno-14-8" href="#__codelineno-14-8"></a><span class="k">FROM</span><span class="w"> </span><span class="n">pg_stat_user_indexes</span>
</span><span id="__span-14-9"><a id="__codelineno-14-9" name="__codelineno-14-9" href="#__codelineno-14-9"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">schemaname</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;public&#39;</span>
</span><span id="__span-14-10"><a id="__codelineno-14-10" name="__codelineno-14-10" href="#__codelineno-14-10"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">idx_scan</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span>
</span><span id="__span-14-11"><a id="__codelineno-14-11" name="__codelineno-14-11" href="#__codelineno-14-11"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">indexrelid</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-14-12"><a id="__codelineno-14-12" name="__codelineno-14-12" href="#__codelineno-14-12"></a><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="n">conindid</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">pg_constraint</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">contype</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="s1">&#39;p&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;u&#39;</span><span class="p">)</span>
</span><span id="__span-14-13"><a id="__codelineno-14-13" name="__codelineno-14-13" href="#__codelineno-14-13"></a><span class="w"> </span><span class="p">)</span>
</span><span id="__span-14-14"><a id="__codelineno-14-14" name="__codelineno-14-14" href="#__codelineno-14-14"></a><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">pg_relation_size</span><span class="p">(</span><span class="n">indexrelid</span><span class="p">)</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span>
</span></code></pre></div>
<hr />
<h2 id="performance-considerations">Performance Considerations<a class="headerlink" href="#performance-considerations" title="Permanent link">&para;</a></h2>
<h3 id="index-trade-offs">Index Trade-offs<a class="headerlink" href="#index-trade-offs" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Pros:</strong> Faster SELECT queries, enforces uniqueness, prevents N+1</li>
<li><strong>Cons:</strong> Slower INSERT/UPDATE/DELETE (index must be updated), increased storage</li>
</ul>
<p><strong>Rule of Thumb:</strong>
- Index all foreign keys (JOIN performance)
- Index all unique constraints (data integrity)
- Index columns used in WHERE clauses frequently
- Avoid indexing low-selectivity columns alone
- Avoid indexing large text fields (use full-text search instead)</p>
<h3 id="query-planning">Query Planning<a class="headerlink" href="#query-planning" title="Permanent link">&para;</a></h3>
<p>Use <code>EXPLAIN ANALYZE</code> to verify index usage:
<div class="language-sql highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="k">EXPLAIN</span><span class="w"> </span><span class="k">ANALYZE</span>
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">locations</span>
</span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">latitude</span><span class="w"> </span><span class="k">BETWEEN</span><span class="w"> </span><span class="mi">53</span><span class="p">.</span><span class="mi">5</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="mi">53</span><span class="p">.</span><span class="mi">6</span>
</span><span id="__span-15-4"><a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">longitude</span><span class="w"> </span><span class="k">BETWEEN</span><span class="w"> </span><span class="o">-</span><span class="mi">113</span><span class="p">.</span><span class="mi">5</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="o">-</span><span class="mi">113</span><span class="p">.</span><span class="mi">4</span><span class="p">;</span>
</span><span id="__span-15-5"><a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a>
</span><span id="__span-15-6"><a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a><span class="c1">-- Output should show &quot;Index Scan using locations_latitude_longitude_idx&quot;</span>
</span></code></pre></div></p>
<h3 id="index-bloat">Index Bloat<a class="headerlink" href="#index-bloat" title="Permanent link">&para;</a></h3>
<p>Over time, indexes can become bloated (unused space). Monitor with:
<div class="language-sql highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="k">SELECT</span>
</span><span id="__span-16-2"><a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a><span class="w"> </span><span class="n">schemaname</span><span class="p">,</span>
</span><span id="__span-16-3"><a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a><span class="w"> </span><span class="n">tablename</span><span class="p">,</span>
</span><span id="__span-16-4"><a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a><span class="w"> </span><span class="n">indexname</span><span class="p">,</span>
</span><span id="__span-16-5"><a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a><span class="w"> </span><span class="n">pg_size_pretty</span><span class="p">(</span><span class="n">pg_relation_size</span><span class="p">(</span><span class="n">indexrelid</span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">index_size</span><span class="p">,</span>
</span><span id="__span-16-6"><a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a><span class="w"> </span><span class="n">idx_scan</span><span class="p">,</span>
</span><span id="__span-16-7"><a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a><span class="w"> </span><span class="n">idx_tup_read</span><span class="p">,</span>
</span><span id="__span-16-8"><a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a><span class="w"> </span><span class="n">idx_tup_fetch</span>
</span><span id="__span-16-9"><a id="__codelineno-16-9" name="__codelineno-16-9" href="#__codelineno-16-9"></a><span class="k">FROM</span><span class="w"> </span><span class="n">pg_stat_user_indexes</span>
</span><span id="__span-16-10"><a id="__codelineno-16-10" name="__codelineno-16-10" href="#__codelineno-16-10"></a><span class="k">WHERE</span><span class="w"> </span><span class="n">schemaname</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;public&#39;</span>
</span><span id="__span-16-11"><a id="__codelineno-16-11" name="__codelineno-16-11" href="#__codelineno-16-11"></a><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">pg_relation_size</span><span class="p">(</span><span class="n">indexrelid</span><span class="p">)</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span>
</span></code></pre></div></p>
<p><strong>Fix bloat:</strong> <code>REINDEX INDEX index_name;</code> (requires table lock)</p>
<hr />
<h2 id="common-performance-issues">Common Performance Issues<a class="headerlink" href="#common-performance-issues" title="Permanent link">&para;</a></h2>
<h3 id="issue-slow-campaign-email-stats-query">Issue: Slow campaign email stats query<a class="headerlink" href="#issue-slow-campaign-email-stats-query" title="Permanent link">&para;</a></h3>
<p><strong>Query:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="k">SELECT</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">campaign_emails</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">campaign_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">?</span><span class="p">;</span>
</span></code></pre></div></p>
<p><strong>Solution:</strong> Already optimized (uses <code>campaignId</code> foreign key index)</p>
<h3 id="issue-slow-location-bounding-box-queries">Issue: Slow location bounding box queries<a class="headerlink" href="#issue-slow-location-bounding-box-queries" title="Permanent link">&para;</a></h3>
<p><strong>Query:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">locations</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">latitude</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">latitude</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">longitude</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">longitude</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="o">?</span><span class="p">;</span>
</span></code></pre></div></p>
<p><strong>Solution:</strong> Already optimized (uses <code>[latitude, longitude]</code> composite index)</p>
<h3 id="issue-slow-active-session-cleanup">Issue: Slow active session cleanup<a class="headerlink" href="#issue-slow-active-session-cleanup" title="Permanent link">&para;</a></h3>
<p><strong>Query:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">tracking_sessions</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">is_active</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">true</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">last_recorded_at</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="o">?</span><span class="p">;</span>
</span></code></pre></div></p>
<p><strong>Solution:</strong> Already optimized (uses <code>[isActive, lastRecordedAt]</code> composite index)</p>
<h3 id="issue-slow-template-version-history">Issue: Slow template version history<a class="headerlink" href="#issue-slow-template-version-history" title="Permanent link">&para;</a></h3>
<p><strong>Query:</strong>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">email_template_versions</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">template_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">created_at</span><span class="w"> </span><span class="k">DESC</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
</span></code></pre></div></p>
<p><strong>Solution:</strong> Already optimized (uses <code>[templateId, createdAt(sort: Desc)]</code> composite index)</p>
<hr />
<h2 id="related-documentation">Related Documentation<a class="headerlink" href="#related-documentation" title="Permanent link">&para;</a></h2>
<ul>
<li><a href="../">Database Overview</a> — Complete ER diagram</li>
<li><a href="../schema/">Schema Reference</a> — All model fields</li>
<li><a href="../migrations/">Migration Workflow</a> — Creating indexes in migrations</li>
<li><a href="../models/auth/#common-queries">Common Queries</a> — Query examples with index usage</li>
<li><a href="https://www.postgresql.org/docs/16/indexes.html">PostgreSQL Index Documentation</a></li>
</ul>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../seeding/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Seeding">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Seeding
</div>
</div>
</a>
<a href="../models/" class="md-footer__link md-footer__link--next" aria-label="Next: Database Models">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Database Models
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2024 The Bunker Operations <a href="#__consent">Change cookie settings</a>
</div>
</div>
<div class="md-social">
<a href="https://gitea.bnkops.com/admin" target="_blank" rel="noopener" title="Gitea Repository" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
</a>
<a href="https://listmonk.bnkops.com/subscription/form" target="_blank" rel="noopener" title="Newsletter" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M536.4-26.3c9.8-3.5 20.6-1 28 6.3s9.8 18.2 6.3 28l-178 496.9c-5 13.9-18.1 23.1-32.8 23.1-14.2 0-27-8.6-32.3-21.7l-64.2-158c-4.5-11-2.5-23.6 5.2-32.6l94.5-112.4c5.1-6.1 4.7-15-.9-20.6s-14.6-6-20.6-.9l-112.4 94.3c-9.1 7.6-21.6 9.6-32.6 5.2L38.1 216.8c-13.1-5.3-21.7-18.1-21.7-32.3 0-14.7 9.2-27.8 23.1-32.8z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../../..", "features": ["announce.dismiss", "content.action.edit", "content.action.view", "content.code.annotate", "content.code.copy", "content.tooltips", "navigation.expand", "navigation.footer", "navigation.indexes", "navigation.path", "navigation.prune", "navigation.sections", "navigation.tabs", "navigation.tabs.sticky", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../../assets/javascripts/bundle.79ae519e.min.js"></script>
<script src="../../../javascripts/home.js"></script>
<script src="../../../javascripts/github-widget.js"></script>
<script src="../../../javascripts/gitea-widget.js"></script>
<script src="../../../assets/js/env-config.js"></script>
<script src="../../../assets/js/video-player.js"></script>
</body>
</html>