暂无图片
mysql数据库find_in_set函数如何优化
我来答
分享
黄伟波
2021-02-04
mysql数据库find_in_set函数如何优化
暂无图片 5M

MySQL手册中find_in_set函数的语法:
FIND_IN_SET(str,strlist)

str 要查询的字符串
strlist 字段名 参数以”,”分隔 如 (1,2,6,8)
查询字段(strlist)中包含(str)的结果,返回结果为null或记录

假如字符串str在由N个子链组成的字符串列表strlist 中,则返回值的范围在 1 到 N 之间。 一个字符串列表就是一个由一些被 ‘,’ 符号分开的子链组成的字符串。如果第一个参数是一个常数字符串,而第二个是type SET列,则FIND_IN_SET() 函数被优化,使用比特计算。 如果str不在strlist 或strlist 为空字符串,则返回值为 0 。如任意一个参数为NULL,则返回值为 NULL。这个函数在第一个参数包含一个逗号(‘,’)时将无法正常运行。

》》生产数据库存在一个问题sql,耗时15s

	count( 1 ) 
FROM
	(
	SELECT
		a.id AS "id",
		a.sender_id AS "senderId",
		a.sender_name AS "senderName",
		a.accept_id AS "acceptId",
		a.accept_name AS "acceptName",
		a.create_time AS "createTime",
		a.remark AS "remark",
		a.parent_id AS "parentId",
		a.doc_id AS "docId",
		a.parent_ids AS "parentIds",
		a.source AS "source",
		a.STATUS AS "status" 
	FROM
		doc_accept_list a 
	WHERE
		a.parent_id IS NOT NULL 
		AND find_in_set(
			id,
		queryAcceptRecordParentsInfo ( '4554a0ed2eab4aa496913efd3fc354a4' )) 
	) tmp_count

测试发现是因为find_in_set函数导致,该表只有3000多条记录,单单查询queryAcceptRecordParentsInfo ( ‘4554a0ed2eab4aa496913efd3fc354a4’ )函数只需要0.1秒
queryAcceptRecordParentsInfo 函数如下:
```CREATE DEFINER=root@% FUNCTION queryAcceptRecordParentsInfo(rootId varchar(100)) RETURNS varchar(4000) CHARSET utf8
BEGIN
DECLARE fid varchar(2000) default ‘’;
DECLARE str varchar(10000) default rootId;

WHILE rootId is not null do
SET fid =(SELECT parent_id as parentid FROM doc_accept_list WHERE id = rootId);
IF fid is not null THEN
SET str = concat(str, ‘,’, fid);
SET rootId = fid;
ELSE
SET rootId = fid;
END IF;
END WHILE;
return str;
END


》》执行计划:
![image.png](https://oss-emcsprod-public.modb.pro/image/editor/20210204-3850d1e4-3230-4e49-a5b5-a1d2d2528968.png)

请问这类sql应如何优化
我来答
添加附件
收藏
分享
问题补充
5条回答
默认
最新
黄伟波

测试发现queryAcceptRecordParentsInfo ( ‘4554a0ed2eab4aa496913efd3fc354a4’ )返回的字符串没带单引号,可能是因为这导致全扫

暂无图片 评论
暂无图片 有用 0
文成

doc_accept_list.id 是什么类型
是否有索引?

暂无图片 评论
暂无图片 有用 0
黄伟波

字符类型,主键来的

暂无图片 评论
暂无图片 有用 0
黄伟波

等价于

	a.id AS "id",
	a.sender_id AS "senderId",
	a.sender_name AS "senderName",
	a.accept_id AS "acceptId",
	a.accept_name AS "acceptName",
	a.create_time AS "createTime",
	a.remark AS "remark",
	a.parent_id AS "parentId",
	a.doc_id AS "docId",
	a.parent_ids AS "parentIds",
	a.source AS "source",
	a.STATUS AS "status" 
FROM
	doc_accept_list a 
WHERE
	a.parent_id IS NOT NULL 
	AND id IN ( 
	 	select queryAcceptRecordParentsInfo ( '4554a0ed2eab4aa496913efd3fc354a4' )
-- '4554a0ed2eab4aa496913efd3fc354a4','a62d34b1adb241048ab2f16cdf4619e3','af041fe48b674ab8a383193d9f1dfd5a'	
)


如果这样写耗时是8s,走全扫,如果单独select queryAcceptRecordParentsInfo ( )里面内容再放进去,就是1s

暂无图片 评论
暂无图片 有用 0
@J

可以看下这篇文章,可以解决你的问题

https://blog.csdn.net/Street_Walker/article/details/88573195

暂无图片 评论
暂无图片 有用 0
回答交流
提交
问题信息
请登录之后查看
邀请回答
暂无人订阅该标签,敬请期待~~
暂无图片墨值悬赏