{"post":{"slug":"trigram-indexes-explained-2026","title":"Trigram Indexes: Making LIKE Queries Fast","excerpt":"A leading-wildcard search cannot use a normal index, so it scans the table. Trigram indexing makes substring and fuzzy matching indexable by breaking text into three-character pieces.","category":"code","date":"January 26, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">A</span> B-tree index stores values in sorted order, which is what makes it fast: to find everything starting with a prefix, jump to that point and read forward.\n\nThat works for a trailing wildcard. It does not work when the pattern begins with a wildcard, because the search term could appear anywhere in the value and sorted order provides no help. The database scans every row.\n\n## What changed in 2026\n\n- **Trigram indexing became a standard tool.** Widely available and routinely used for search-as-you-type and fuzzy matching features.\n- **Fuzzy matching demand grew.** Typo-tolerant search became an expected product feature rather than a refinement.\n- **The dedicated-search-engine boundary clarified.** Trigram indexing handled moderate needs; full search engines remained for ranking and language-aware requirements.\n- **Index size scrutiny increased.** Teams learned that trigram indexes can be large relative to the data they index.\n\n## How trigrams work\n\nThe column's text is broken into every overlapping three-character sequence. The word `search` produces the trigrams `sea`, `ear`, `arc`, `rch`, plus padded ones at the boundaries.\n\nThose trigrams are indexed, with the rows containing each. When you search for a substring, the search term is broken into its own trigrams, and the index finds rows containing all of them. Those candidates are then checked properly against the actual pattern.\n\nBecause a substring anywhere in the text produces trigrams present in the index, position no longer matters — which is exactly what a leading wildcard needed.\n\nThe two-stage nature is worth knowing: the index produces candidates, and a recheck confirms them. So the index reduces the rows examined rather than answering the query outright, which is why its benefit depends on how selective the trigrams are.\n\n## Where it works and does not\n\n| Pattern | B-tree | Trigram |\n| --- | --- | --- |\n| `LIKE 'abc%'` | Yes | Yes, but B-tree is better |\n| `LIKE '%abc'` | No | Yes |\n| `LIKE '%abc%'` | No | Yes |\n| Case-insensitive match | With an expression index | Yes |\n| Similarity / typo matching | No | Yes |\n| Term shorter than 3 chars | N/A | Poorly |\n| Exact equality | Yes, better | Works, wasteful |\n\nThe short-term limitation is structural. A two-character search term produces essentially no useful trigrams, so the index cannot narrow the candidate set and the query degenerates toward a scan. Search-as-you-type features hit this on the first two keystrokes, which is why they typically wait for three characters before querying.\n\n## Fuzzy matching\n\nThe capability people adopt trigram indexing for and then find more useful than the substring search that motivated it.\n\nBecause text is represented as a set of trigrams, you can measure similarity between two strings by how many trigrams they share. That gives typo tolerance — `recieve` and `receive` share most of their trigrams — and near-match ranking.\n\nThat supports \"did you mean\" behaviour, deduplication of near-identical records, and matching user input against a canonical list. Implemented with an ordinary index rather than a separate search system, which is the appeal for moderate needs.\n\nThe tradeoff is that similarity is purely lexical. It knows nothing about meaning, so semantically related but lexically different terms do not match — that is what embeddings are for, per [how vector embeddings work](/blog/how-vector-embeddings-work-2026).\n\n## Costs\n\nTrigram indexes are large. Each row contributes many trigrams, and the index stores row lists for each, so index size can approach or exceed the size of the indexed text.\n\nWrites are correspondingly expensive, for the same reason as any index storing many entries per row — see [GIN indexes](/blog/gin-indexes-explained-2026), which is a common underlying structure here.\n\nThat makes trigram indexing a poor fit for very large text columns or write-heavy tables. It suits moderate-length values — names, titles, identifiers, descriptions — queried frequently and written less.\n\n## Common mistakes\n\n- **Using it for prefix-only search.** A B-tree is smaller and faster.\n- **Expecting good performance on short terms.** Fewer than three characters has nothing to match.\n- **Indexing very large text columns.** Index size and write cost become severe.\n- **Assuming semantic matching.** It is purely lexical.\n- **Not checking the plan.** The planner may decline the index on unselective patterns.\n- **Ignoring index size.** Can rival the table.\n\n## FAQ\n\n**Does this replace a search engine?**\nFor substring and fuzzy matching on moderate data, yes. For ranked relevance, language-aware stemming, and large corpora, a dedicated search system does considerably more.\n\n**How large will the index be?**\nPotentially comparable to the indexed data. Measure on a representative sample before adding it to a large table.\n\n**Can I combine it with other indexes?**\nYes, and it is common — a B-tree for exact and prefix matching, a trigram index for substring and fuzzy. The planner picks per query.\n\n**What about case sensitivity?**\nTrigram matching is typically case-insensitive by default, which is usually what search features want and worth confirming for your engine.\n\n## Where to go next\n\nFor the underlying index structure, read [GIN indexes](/blog/gin-indexes-explained-2026). For semantic rather than lexical matching, [how vector embeddings work](/blog/how-vector-embeddings-work-2026), and for index selection generally, [database indexing explained](/blog/database-indexing-explained-2026).","hue":310,"metaTitle":"Trigram Indexes: Making LIKE Queries Fast","metaDescription":"Why leading-wildcard searches cannot use a B-tree, how trigram indexing makes substring and fuzzy matching fast, and its limitations on short terms.","keywords":["trigram index","pg_trgm","like query performance","substring search index","fuzzy matching sql","similarity search","leading wildcard","database indexing 2026"],"tldr":["**A leading wildcard defeats a B-tree** — which is why substring search scans by default.","**Trigrams index three-character sequences** — so any substring can be matched via the trigrams it contains.","**Short search terms perform badly** — a term under three characters has no trigrams to match.","**It also enables fuzzy similarity search** — matching typos and near-misses, not just substrings.","**Skip:** trigram indexes for prefix-only search. A normal B-tree handles a trailing wildcard fine."],"readTime":"4 min read","wordCount":860},"related":[{"slug":"database-indexing-explained-2026","title":"Database indexing explained in 2026: what every developer must know","excerpt":"Bad indexes cause more production incidents than almost any other root cause. Here is the 2026 guide to choosing, building, and maintaining the right ones.","category":"code","date":"March 10, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":318},{"slug":"partial-indexes-explained-2026","title":"Partial Indexes: Indexing Only the Rows That Matter","excerpt":"Most queries against a large table only ever touch a small slice of it. A partial index covers just that slice, and is a fraction of the size and cost.","category":"code","date":"August 12, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":316},{"slug":"gin-indexes-explained-2026","title":"GIN Indexes: Indexing Values Inside a Column","excerpt":"A B-tree indexes a column's value. A GIN index indexes the things inside it — array elements, document keys, words in a text field — which is a different problem.","category":"code","date":"January 7, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":316}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"rent-vs-buy-calculator-guide-2026","title":"Rent vs buy in 2026: the calculator and the math nobody runs honestly","excerpt":"A blunt walkthrough of the rent-vs-buy math for 2026 — the variables most calculators skip, and how to plug your actual numbers in correctly.","category":"finance","date":"January 26, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":280},"older":{"slug":"what-1-percent-fees-cost-over-30-years-2026","title":"What 1% fees really cost you over 30 years (with the actual math)","excerpt":"A 1% management fee sounds tiny. Over 30 years on a $100k portfolio, it costs you $269,000. We did the math, ran the scenarios, and built a way to see exactly how much your specific fees are eating.","category":"finance","date":"January 26, 2026","author":"ByteLedger Team","readTime":"9 min read","hue":38}}