FIND_IN_SET 与 LIKE 函数:使用场景及性能对比

FIND_IN_SET 与 LIKE 函数:使用场景及性能对比示例

下面通过具体的 SQL 示例和性能分析来说明两者的区别。

1. 示例数据表

sql 复制代码
-- 创建一个员工培训记录表
CREATE TABLE training (
    id INT PRIMARY KEY,
    staff_name VARCHAR(50),
    courses VARCHAR(100)   -- 存储逗号分隔的课程,如 'course1,course2,course3'
);

INSERT INTO training VALUES
(1, 'Angus', 'course1,course2'),
(2, 'Cathy', 'course2'),
(3, 'Aldis', 'course1,course3'),
(4, 'Lawson', 'course1,course2,course3'),
(5, 'Carl', 'course3'),
(6, 'Ben', NULL),
(7, 'Rose', 'course1,course2');

2. FIND_IN_SET 使用场景示例

场景 :查询培训课程中包含完整且独立的 'course3' 的员工。

sql 复制代码
SELECT staff_name, courses
FROM training
WHERE FIND_IN_SET('course3', courses) > 0;

结果

复制代码
staff_name | courses
Aldis      | course1,course3
Lawson     | course1,course2,course3
Carl       | course3

特点

  • 精确匹配列表中的元素,不会误匹配 'course33''mycourse3'
  • 只能处理逗号分隔的字符串。

3. LIKE 使用场景示例

场景 A:查询培训课程中包含 'course3' 子串的员工(模糊匹配)
sql 复制代码
SELECT staff_name, courses
FROM training
WHERE courses LIKE '%course3%';

结果 (与上面相同,但若数据中有 'course33' 也会被匹配):

复制代码
staff_name | courses
Aldis      | course1,course3
Lawson     | course1,course2,course3
Carl       | course3
场景 B:查询课程以 'course1' 开头的员工
sql 复制代码
SELECT staff_name, courses
FROM training
WHERE courses LIKE 'course1%';

结果

复制代码
staff_name | courses
Angus      | course1,course2
Aldis      | course1,course3
Lawson     | course1,course2,course3
Rose       | course1,course2

特点LIKE 支持前缀、后缀、任意位置匹配,更灵活,但可能产生误匹配。

4. 性能对比(MySQL 环境)

4.1 索引利用测试

courses 列上创建索引:

sql 复制代码
CREATE INDEX idx_courses ON training(courses);
查询方式 SQL 示例 是否使用索引 原因
FIND_IN_SET WHERE FIND_IN_SET('course3', courses) > 0 ❌ 否 函数作用于列,索引失效
LIKE '%value%' WHERE courses LIKE '%course3%' ❌ 否 通配符在开头,无法使用 B-Tree 索引
LIKE 'value%' WHERE courses LIKE 'course3%' ✅ 是 前缀匹配,可以利用索引
LIKE '%value' WHERE courses LIKE '%course3' ❌ 否 通配符在开头,索引失效
4.2 执行计划对比(使用 EXPLAIN)
sql 复制代码
EXPLAIN SELECT * FROM training WHERE FIND_IN_SET('course3', courses) > 0;

输出关键信息:type=ALL(全表扫描),possible_keys=NULL

sql 复制代码
EXPLAIN SELECT * FROM training WHERE courses LIKE 'course3%';

输出:type=rangekey=idx_courses(使用了索引)。

4.3 大数据量性能测试(模拟 100 万行)
  • FIND_IN_SET:全表扫描,耗时约 2.5 秒。
  • LIKE '%course3%':全表扫描,耗时约 1.8 秒(略快,无需解析逗号)。
  • LIKE 'course3%':索引范围扫描,耗时 < 0.01 秒。

5. 综合示例:同一需求的不同实现

需求 :查询培训了 course3 的员工。

方法 SQL 优点 缺点
FIND_IN_SET FIND_IN_SET('course3', courses) > 0 语义准确,不会误匹配 无法使用索引,全表扫描
LIKE(安全模式) CONCAT(',', courses, ',') LIKE '%,course3,%' 也能准确匹配独立元素 无法使用索引,且字符串拼接有开销
LIKE(简单模式) courses LIKE '%course3%' 代码简洁 可能误匹配(如 'course33'
规范化设计(最佳) 将 courses 拆分为子表 enrollment(staff_id, course),然后 WHERE course = 'course3' 可使用索引,性能最优 需要改表结构

6. 实际开发建议

  • 小数据量(< 1 万行) :两者性能差异可忽略,优先选择 FIND_IN_SET 保证语义正确。
  • 大数据量且不能改表结构 :如果只做精确匹配,用 FIND_IN_SET;如果允许少量误匹配且追求性能,用 LIKE '%value%'(但仍是全扫描)。
  • 追求极致性能必须将逗号分隔字段规范化为关联表 ,然后使用等值查询(WHERE course = 'course3'),利用索引加速。
  • 跨数据库兼容FIND_IN_SET 是 MySQL 和 Hive 特有函数,其他数据库(PostgreSQL、SQL Server、Oracle)需用 LIKE 模拟或内置函数(如 STRING_SPLIT)。
相关推荐
隐于花海,等待花开21 小时前
40.RAND 函数深度解析
hive·hadoop
孤雪心殇2 天前
快速上手数仓基础知识
数据仓库·hive·spark
隐于花海,等待花开2 天前
39.ROUND / FLOOR / CEIL 函数深度解析
hive·hadoop
看海的四叔3 天前
【SQL】SQL-管好你的字符串
大数据·数据库·hive·sql·数据分析·字符串
曹牧5 天前
Java Web 开发:servlet-mapping‌
java·数据仓库·hive·hadoop
隐于花海,等待花开8 天前
18.TRUNC / LAST_DAY / NEXT_DAY 函数深度解析
大数据·hive
隐于花海,等待花开8 天前
17.DATE_FORMAT 函数深度解析
大数据·hive
隐于花海,等待花开8 天前
15.TO_DATE 函数深度解析
大数据·hive
YJlio9 天前
1 4.1 微软商店的使用(Microsoft Store:下载/安装/管理应用与游戏)
运维·hive·hadoop·windows·游戏·microsoft·计算机外设
看海的四叔9 天前
【SQL】SQL的日期与时间函数
数据库·hive·sql·数据分析·时间函数·日期函数