暂无图片
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
打赏 0
文成

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

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

字符类型,主键来的

暂无图片 评论
暂无图片 有用 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
打赏 0
@J

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

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

暂无图片 评论
暂无图片 有用 0
打赏 0
回答交流
Markdown


请输入正文
提交
相关推荐
linux下yum安装mysql,怎么配置大小写
回答 1
已采纳
配置大小写和是不是yum没关系。都是这个参数owercasetablenames
MySQL使用In-Place方式5.7.35升级至最新,会有什么问题吗?
回答 3
已采纳
只要能升级上来,正常启动就没有问题。剩下的就是看看应用适配情况,jdbc的更换什么的。本地升级需要停机一下。其他没什么。
mysql未提交的事务redolog日志会不会被写进redolog磁盘文件?
回答 1
已采纳
会。脏日志 不是只受 innodbflushlogattrxcommit 这个参数控制 刷日志到磁盘有下面几个规则刷日志到磁盘有以下几种规则:1.发出commi
mysql锁是加在索引上的?如何理解
回答 1
在MySQL中,锁的行为和效率确实与索引紧密相关,但并非所有的锁都直接“加在索引上”。MySQL使用多种类型的锁来管理对数据库资源的并发访问,包括表锁和行锁。这里的关键点在于,当使用支持行级锁的存储引
MySQL开启审计日志问题
回答 2
推荐用第三方开源审计插件:libauditplugin.so来做mysql的审计工作
请问各位大佬mysql如何绑定执行计划?
回答 4
MySQL有丰富的hint功能。可以指定走某个索引,固定关联顺序等等。利用hint可以使MySQL走你想走的计划
不看官方文档,仅仅通过实例端的命令行,怎么判断某个参数,是否修改后需要重启?
回答 2
查看系统变量的全局值 selectfrom performanceschema.globalvariables;查看系统变量的当前会话值 selectfrom 
MySQL 字符串太长,想只显示100个字, 怎么实现?
回答 3
已采纳
MySQLleft函数可以满足吧。selectleft(errormsg,6)fromtvchrocrlimit3;mysql>selectsubstr(errormsg,1,6)fromtvc
pt-online-schema-change 中的dsn,使用报错,版本3.1,db-5.7
回答 3
这个错误信息表示在执行ptonlineschemachange工具时,遇到了一个数据库表名的问题。具体来说,它试图从名为dsns的表中选择数据,但是该表名存在空格,导致查询失败。要解决这个问题,你可以
MySQL中的IFNULL()有什么作用?
回答 1
已采纳
使用IFNULL()方法能使MySQL中的查询更加精确。IFNULL()方法会测试它的第一个参数,若不为NULL则返回该参数的值,否则返回第二个参数的值,类似于Oracle中的NVL函数。