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)。
相关推荐
夕除9 小时前
javaweb--04
数据仓库·hive·hadoop
虚幻如影2 天前
Hive 中“STRING类型无需显式指定长度
数据仓库·hive·hadoop
橘子编程8 天前
Hive大数据实战指南:从入门到精通
大数据·hive·hadoop
橘子编程8 天前
Apache Hadoop知识全解析
大数据·hive·hadoop·apache
dovens8 天前
Spring Boot 从 2.7.x 升级到 3.3注意事项
数据库·hive·spring boot
Joy T10 天前
【大数据】离线数仓核心组件:Hive 架构解析与进阶操作指南
大数据·数据仓库·hive·hadoop·架构
jasnet_u10 天前
在Hadoop3.3.6上搭建Hive3.1.2
hive·hadoop
二进制_博客11 天前
使用Datax批量将mysql数据导入hive
数据库·hive·mysql
talen_hx29611 天前
《零基础入门Spark》学习笔记 Day 10
大数据·hive·笔记·学习·spark