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)。
相关推荐
牛奶咖啡133 天前
大数据Hadoop运维应用实践——HIVE与Hadoop实现整合_Hive的配置安装与使用
大数据·hive·hive的配置与安装·metastore服务的配置·hiveserver2服务配置·hive的常用sql操作·beeline的使用
向夏威夷 梦断明暄5 天前
基于Tez引擎的 Hive SQL 性能优化
hive·sql·性能优化
humbinal12 天前
同时支持 gui & cli 的 parquet 文件查看工具,高性能小清新!
hive·python·rust·spark·开源·github·parquet
吾AI科技14 天前
基于Tez引擎的 Hive SQL 性能优化
大数据·hive·性能优化·tez
abcy07121315 天前
hive 执行器原理
hive
香山上的麻雀100817 天前
Hive内部表(MANAGED_TABLE)的“批量删除分区”特性详解
数据仓库·hive·hadoop
jjjava2.019 天前
SpringMVC入门指南:从零掌握核心要点
数据仓库·hive·hadoop
AllData公司负责人21 天前
数据库同步平台|AIIData数据中台实现OceanBase、达梦数据库、OpenGauss、人大金仓、Hive、TDengine 一键接入Doris
大数据·数据库·hive·mysql·oceanbase·tdengine
AllData公司负责人21 天前
数据同步平台|AIIData数据中台实现MySQL、Hive、Kafka 一键接入Doris
大数据·数据库·hive·mysql·kafka·实时同步
李昊哲小课22 天前
Ubuntu26.04-Hadoop3.5.0搭建hive4.2.0
数据仓库·hive·数仓