FIND_IN_SET仅适用于逗号分隔字符串字段,无法走索引,性能差且易误匹配;正确用法为FIND_IN_SET('3', category_ids),需注意参数类型、空值处理及字段格式规范。

FIND_IN_SET 不是通用集合查询工具,它只适用于逗号分隔的字符串字段,且无法走索引——直接用在大表上容易拖慢查询。
WHERE 条件中匹配逗号分隔字段里的某个值
当字段(比如 category_ids)存的是 '1,3,5,8' 这种格式,而你想查“包含 3”的记录,不能写 WHERE 3 IN (category_ids),那会当成单个值比对,永远不成立。
正确写法是:
SELECT * FROM products WHERE FIND_IN_SET('3', category_ids);
注意点:
-
FIND_IN_SET第一个参数必须是字符串,哪怕查数字也要加引号,'3'✅,3❌(会隐式转成字符串但行为不可靠) - 第二个参数必须是字符串类型字段或表达式,不能是数字列,否则返回
NULL或0 - 如果
category_ids是空字符串'',结果为0;如果是NULL,结果为NULL,整行被过滤掉 - 字段里有空格不影响,比如
'1, 3, 5'中查'3'仍能命中(MySQL 会忽略逗号前后的空格)
ORDER BY 按指定顺序排列结果集
你有一组 ID 列表 '105,23,99,41',想让查出来的记录严格按这个顺序返回,IN 只能保证“在其中”,不保序。
这时用:
SELECT * FROM articles WHERE id IN (105,23,99,41) ORDER BY FIND_IN_SET(id, '105,23,99,41');
说明:
-
FIND_IN_SET返回位置序号(从 1 开始),所以排序天然符合你的列表顺序 - 务必确保
id字段是字符串类型,或显式转成字符串:FIND_IN_SET(CAST(id AS CHAR), '105,23,99,41'),否则数值型id和字符串列表比较可能出错 - 不在列表中的
id会返回0,排在最前面——如果不想出现,得额外加AND id IN (...)过滤
为什么不能用 LIKE 替代 FIND_IN_SET
有人试过 WHERE category_ids LIKE '%3%',这会导致误匹配:比如 '13,23,30' 也会被选中。
FIND_IN_SET 的安全边界在于“完整项匹配”:
-
FIND_IN_SET('3', '1,3,5')→2✅ -
FIND_IN_SET('3', '13,23,30')→0✅(不误中) -
FIND_IN_SET('3,', '1,3,5')→0✅(尾部带逗号就完全不匹配)
但要注意:如果字段本身存了多余空格或换行(比如 '1,\n3 ,5'),FIND_IN_SET 就失效了——它不处理换行、制表符,也不做 trim。
性能差在哪?为什么线上慎用
FIND_IN_SET 本质是全表扫描 + 字符串拆解,无法使用任何索引。
真实场景下容易踩的坑:
- 表有 10 万行,
category_ids平均长度 20 字符,每次查询都要对每行执行一次字符串遍历和分割 - 即使给
category_ids加了索引,FIND_IN_SET也完全不走 - 字段含中文、特殊符号(如顿号、分号)时,只要不是英文逗号
,,函数直接失效 - 第一个参数含逗号(如
FIND_IN_SET('a,b', 'a,b,c'))会截断解析,结果不可预测
真正需要高频查询的场景,应该把逗号分隔结构拆成关联表,用 JOIN + 索引代替——FIND_IN_SET 只适合低频、小数据、临时补救或管理后台类需求。











