MySQL全文索引需建在MyISAM或InnoDB表上,PHP仅调用其FULLTEXT功能;InnoDB要求≥5.6版本且字段为TEXT/VARCHAR(≤3072字符);MATCH...AGAINST不支持参数化,须手动过滤关键词;中文需ngram解析器或外部引擎。

MySQL 中 PHP 调用的全文索引必须建在 MyISAM 或 InnoDB 表上
PHP 本身不提供全文索引能力,实际是通过 MySQL 的 FULLTEXT 索引实现。关键限制在于:MySQL 5.6+ 的 InnoDB 支持 FULLTEXT,但对中文分词无原生支持;MyISAM 虽支持,但已逐步弃用。若用 InnoDB,必须确认 MySQL 版本 ≥ 5.6,且字段类型为 TEXT 或 VARCHAR(长度 ≤ 3072 字符)。
- 建表时直接定义:
CREATE TABLE articles (id INT, title VARCHAR(200), content TEXT, FULLTEXT(title, content)) ENGINE=InnoDB; - 已有表添加:
ALTER TABLE articles ADD FULLTEXT(title, content); - 不支持对
CHAR、BLOB或非文本类型字段建FULLTEXT索引
PHP 中执行 MATCH ... AGAINST 必须用原生 SQL,PDO 不自动转义关键词
PHP 的 PDO 或 mysqli 无法将用户输入安全地注入 MATCH() AGAINST() 的搜索词中——因为 MySQL 要求搜索字符串是字面量(literal),不能参数化。强行用 ? 占位会报错 ERROR 1064: Syntax error near '?' 。
- 必须手动过滤:只允许字母、数字、空格、短横线、下划线;剔除引号、括号、
+、-、~等操作符(除非你明确需要布尔模式) - 简单清理示例:
$keyword = preg_replace('/[^\w\s\-]/u', '', $_GET['q']); - 布尔模式需额外处理:
AGAINST('+php +mysql' IN BOOLEAN MODE),此时+和-是语法符号,不能被过滤掉,得用白名单或严格校验结构
中文检索效果差?不是 PHP 问题,是 MySQL 默认不支持中文分词
MySQL 原生 FULLTEXT 把中文当单字切分(如“数据库” → “数”、“据”、“库”),导致查不到完整词。这不是 PHP 写法错误,而是引擎限制。
- 临时缓解:用
LIKE '%数据库%'替代,但无法利用索引,大数据量极慢 - 可行方案:改用 Elasticsearch、Sphinx,或 MySQL 8.0+ 配合 ngram parser(需建表时指定:
FULLTEXT(content) WITH PARSER ngram) - 若坚持用 MySQL + ngram:ngram_token_size 默认为 2,意味着“数据库”会被拆成“数据”“库”——仍不理想,需调大该值并重建索引
PHP 查询时没返回结果?检查 AGAINST 的匹配模式和最小词长
MySQL 默认忽略长度 ≤ 4 的词(ft_min_word_len = 4),且停用词表(ft_stopword_file)会过滤常见词。例如搜“code”可能命中,“go”则直接被跳过。
立即学习“PHP免费学习笔记(深入)”;
- 查看当前设置:
SHOW VARIABLES LIKE 'ft_%'; - 修改需重启 MySQL,并重建全文索引:
ALTER TABLE articles DROP INDEX ft_title_content; ALTER TABLE articles ADD FULLTEXT(title, content); - 调试技巧:先用 MySQL 客户端执行
SELECT * FROM articles WHERE MATCH(title) AGAINST('php' IN NATURAL LANGUAGE MODE);,确认是否真有数据匹配,再排查 PHP 层逻辑
全文索引的坑基本集中在 MySQL 配置和 SQL 写法上,PHP 只是执行通道。最容易被忽略的是:以为加了 FULLTEXT 就能搜中文,或者把 AGAINST() 当普通查询参数来 bind。











