← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Full-Text Search

Performance PHP 5.0+ Intermediate
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints list mysql-explain and laravel-scout as tools. mysql-explain can reveal full table scans but requires the developer to actively run EXPLAIN on suspect queries — it won't proactively flag LIKE '%term%' patterns at write time. laravel-scout guides toward search abstraction but doesn't auto-detect missing FULLTEXT indexes. The code_pattern is identifiable only if someone is auditing queries or profiling under load, making this effectively a review/runtime discovery rather than an automatic catch.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix acknowledges two tiers: adding a MySQL FULLTEXT index with MATCH AGAINST is a moderate change (schema migration plus query rewrites), and migrating to Meilisearch or Elasticsearch is a more significant effort involving new infrastructure, indexing pipelines, and query-layer changes. Even the simpler fix touches schema, queries, and potentially model/repository layers across a component, placing this solidly at e5.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The choice applies to web and API contexts broadly. Using LIKE '%term%' as a de-facto search strategy means every search-related feature, query optimization review, and scaling discussion is haunted by the absent index. It slows down multiple work streams (performance tuning, feature additions involving search) but doesn't fully define the system's shape — a b5 fits because it's a recurring tax across search-related work without being fully load-bearing across the whole codebase.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception is explicit: developers assume LIKE '%keyword%' is equivalent to full-text search for most use cases. This is a deeply intuitive but completely wrong belief — LIKE with a leading wildcard looks syntactically similar to a search operation but silently performs a full table scan, contrary to how indexed lookups behave. The behavior contradicts reasonable developer expectations about SQL index usage, making it a serious cognitive trap just short of catastrophic.

About DEBT scoring →

Also Known As

FTS full-text index FULLTEXT search MySQL

TL;DR

Efficient natural-language search across text fields using inverted indexes — far faster than LIKE '%query%' for large datasets.

Explanation

SQL LIKE '%query%' cannot use a B-tree index and requires a full table scan. Full-text search uses inverted indexes — a mapping from words to the documents containing them — enabling relevance-ranked search in milliseconds. MySQL FULLTEXT indexes (InnoDB, Boolean and natural language modes) and PostgreSQL's tsvector/tsquery support basic full-text search. Elasticsearch and OpenSearch provide production-grade full-text search with fuzzy matching, faceting, autocomplete, and multi-field relevance tuning. In PHP, integration via the elasticsearch-php client or Laravel Scout abstracts the provider.

Common Misconception

LIKE '%keyword%' is equivalent to full-text search for most use cases. LIKE with a leading wildcard cannot use indexes and scans every row. Full-text search uses inverted indexes, supports relevance ranking, stemming, and stopwords — it is orders of magnitude faster on large datasets.

Why It Matters

LIKE '%keyword%' queries cannot use indexes and scan every row — full-text search indexes pre-process text into inverted indexes enabling sub-millisecond keyword lookups across millions of rows.

Common Mistakes

  • Using LIKE '%term%' for search — always a full table scan, unusable at scale.
  • Not using MySQL FULLTEXT or PostgreSQL tsvector indexes for text search fields.
  • Expecting full-text search to handle fuzzy matching — use a dedicated search engine (Elasticsearch, Meilisearch) for that.
  • Not stemming or normalizing search terms — 'running' and 'run' match different documents without stemming.

Code Examples

✗ Vulnerable
-- Full table scan on every search:
SELECT * FROM articles WHERE content LIKE '%php security%'; -- Scans all rows

-- MySQL FULLTEXT index:
ALTER TABLE articles ADD FULLTEXT INDEX ft_content (title, content);
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('php security' IN BOOLEAN MODE);
✓ Fixed
-- MySQL FULLTEXT — faster than LIKE '%keyword%'
-- Create FULLTEXT index
ALTER TABLE articles ADD FULLTEXT INDEX ft_body(title, body);

-- Natural language search
SELECT *, MATCH(title,body) AGAINST('php generators' IN NATURAL LANGUAGE MODE) AS score
FROM articles
WHERE MATCH(title,body) AGAINST('php generators' IN NATURAL LANGUAGE MODE)
ORDER BY score DESC;

-- PostgreSQL tsvector (more powerful)
ALTER TABLE articles ADD COLUMN search_vector tsvector
    GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || body)) STORED;
CREATE INDEX idx_articles_fts ON articles USING GIN(search_vector);

SELECT * FROM articles
WHERE search_vector @@ plainto_tsquery('english', 'php generators')
ORDER BY ts_rank(search_vector, plainto_tsquery('english', 'php generators')) DESC;

Added 15 Mar 2026
Edited 22 Mar 2026
Views 91
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 2 pings S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 1 ping S 3 pings M
SEMrush 1 Ahrefs 1 Google 1
PetalBot 1
Amazonbot 10 Perplexity 8 Scrapy 8 Ahrefs 7 ChatGPT 7 Bing 6 PetalBot 6 SEMrush 5 Google 4 Unknown AI 2 Applebot 2 Meta AI 1 Majestic 1 Twitter/X 1
crawler 64 crawler_json 4
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Use MySQL FULLTEXT index with MATCH AGAINST for simple search; migrate to Meilisearch or Elasticsearch when you need typo tolerance, faceting, or search-as-you-type
📦 Applies To
PHP 5.0+ web api laravel
🔗 Prerequisites
🔍 Detection Hints
LIKE '%search_term%' full table scan; no FULLTEXT index; no search engine for high-traffic search feature
Auto-detectable: ✓ Yes mysql-explain laravel-scout
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: High Context: File Tests: Update


✓ schema.org compliant