Full-Text Index
IntermediateFull-text indexes enable MATCH(col) AGAINST('term') searches with natural language and boolean modes; faster than LIKE '%term%' for text-heavy search on large datasets.
Overview
Full-text indexes in MySQL enable fast word-based search on TEXT and VARCHAR columns using MATCH() AGAINST(). Unlike LIKE '%term%' which causes a full table scan, full-text search uses an inverted index mapping each word to the rows containing it. InnoDB has supported full-text indexes since MySQL 5.6. There are two query modes: Natural Language mode (default — relevance-ranked results) and Boolean mode (supports +word, -word, "exact phrase", word* prefix operators). Full-text search is not a replacement for Elasticsearch on large datasets — MySQL full-text is suitable for moderate-scale text search on a single table without complex tokenisation requirements.
Creating and querying full-text indexes
Create a FULLTEXT index on one or more text columns. MATCH(columns) AGAINST('search terms') in Natural Language mode returns rows ranked by relevance. MySQL automatically excludes common stop words (a, the, is) and words shorter than innodb_ft_min_token_size (default 3 characters).
-- Create table with full-text index
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
body TEXT,
FULLTEXT idx_ft_title_body (title, body) -- multi-column full-text index
);
-- Add to existing table
ALTER TABLE articles ADD FULLTEXT INDEX idx_ft_body (body);
-- Natural Language mode (default) — ranked by relevance
SELECT id, title, MATCH(title, body) AGAINST ('kafka streaming') AS relevance
FROM articles
WHERE MATCH(title, body) AGAINST ('kafka streaming') -- WHERE uses index
ORDER BY relevance DESC
LIMIT 10;
-- EXPLAIN should show: Extra = "Using where; Ft_hints: sorted"
EXPLAIN SELECT * FROM articles
WHERE MATCH(title, body) AGAINST ('kafka streaming');
-- Minimum token length (default 3 — cannot search 2-char words)
SHOW VARIABLES LIKE 'innodb_ft_min_token_size'; -- default: 3
-- To allow 2-char words: set innodb_ft_min_token_size=2 in my.cnf + OPTIMIZE TABLEBoolean mode operators
Boolean mode gives fine-grained control over which terms must, may, or must not appear. Operators: + (must include), - (must exclude), "" (exact phrase), * (prefix wildcard), > (increase relevance), < (decrease relevance), () (subexpression grouping). Boolean mode results are not relevance-ranked by default — add ORDER BY MATCH() AGAINST() for ranked results.
-- Boolean mode — must contain "kafka", must not contain "zookeeper"
SELECT id, title
FROM articles
WHERE MATCH(title, body) AGAINST ('+kafka -zookeeper' IN BOOLEAN MODE);
-- Must contain both "kafka" AND "streams"
SELECT id, title
FROM articles
WHERE MATCH(title, body) AGAINST ('+kafka +streams' IN BOOLEAN MODE);
-- Exact phrase match
SELECT id, title
FROM articles
WHERE MATCH(title, body) AGAINST ('"event sourcing"' IN BOOLEAN MODE);
-- Prefix wildcard: matches "stream", "streaming", "streams"
SELECT id, title
FROM articles
WHERE MATCH(title, body) AGAINST ('stream*' IN BOOLEAN MODE);
-- Combined: must have "kafka", optional "streams" (higher rank if present)
SELECT id, title,
MATCH(title, body) AGAINST ('+kafka streams*' IN BOOLEAN MODE) AS score
FROM articles
WHERE MATCH(title, body) AGAINST ('+kafka streams*' IN BOOLEAN MODE)
ORDER BY score DESC;Limitations and when to use Elasticsearch instead
MySQL full-text search has limitations: no support for stemming (searching "run" finds "run" but not "running"), no multilingual tokenisation, no fuzzy matching, and index rebuild is slow on large tables. For production search at scale, Elasticsearch (or OpenSearch) is the standard. MySQL full-text is appropriate for: small-medium tables (< 10 M rows), simple word searches on a single table, and cases where an external search engine adds too much operational overhead.
-- Full-text limitations and workarounds
-- 1. Stop words: common words excluded from indexing
SHOW VARIABLES LIKE 'innodb_ft_enable_stopword'; -- default: ON
-- View current stop word list:
SELECT value FROM information_schema.INNODB_FT_DEFAULT_STOPWORD;
-- Disable stop words for specific table (my.cnf):
-- innodb_ft_user_stopword_table = 'my_db/my_stopwords'
-- 2. Minimum token size: words < 3 chars not indexed
-- Check: SELECT * FROM articles WHERE MATCH(body) AGAINST ('AI')
-- → returns 0 rows even if "AI" is in body (too short)
-- 3. Rebuild index after changing min_token_size
OPTIMIZE TABLE articles; -- rebuilds full-text index
-- 4. InnoDB auxiliary tables (used by full-text engine)
SELECT * FROM information_schema.INNODB_FT_INDEX_CACHE LIMIT 5;
-- When to use Elasticsearch instead of MySQL full-text:
-- ✓ Need fuzzy matching ("kafkka" → "kafka")
-- ✓ Need stemming ("searching" → "search")
-- ✓ Need multilingual tokenisation (Chinese, Japanese)
-- ✓ Searching across > 50M rows
-- ✓ Need faceted search / aggregations
-- ✓ Near-real-time search on rapidly changing dataKey Points to Remember
- 1FULLTEXT indexes use an inverted index — MATCH() AGAINST() uses the index; LIKE '%term%' does not
- 2Natural Language mode returns relevance-ranked results; Boolean mode supports +/- operators but is not ranked by default
- 3Words shorter than innodb_ft_min_token_size (default 3) and stop words are not indexed
- 4After changing min_token_size, run OPTIMIZE TABLE to rebuild the full-text index
- 5Boolean mode + (must) and - (must not) operators are the most common use case for structured text search
- 6For fuzzy matching, stemming, multilingual search, or > 50M rows: use Elasticsearch or OpenSearch instead
Interview Questions
Sign in to ask AriaWhy is LIKE '%term%' slow and how does a full-text index improve search performance?
What is the difference between Natural Language mode and Boolean mode in MySQL full-text search?
Why might MATCH(body) AGAINST('AI') return no results even if "AI" appears in the body column?
How would you implement case-insensitive, stemmed search on a large product catalogue in MySQL?
When would you choose Elasticsearch over MySQL full-text search?
Ask Aria about Full-Text Index
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.