首页 > 数据库 >一个mysql的group_concat导致的问题

一个mysql的group_concat导致的问题

时间:2023-05-27 14:33:06浏览次数:40  
标签:SET group mysql 查询 sql id concat

  好久都没有写点东西了,是时候有点写东西的必要了。

  去年下年底离职了,躺了几个月,最近又兜兜转转换了一家公司继续当牛马了,前段时间八股文背了好多,难受呀,不过我也趁着前段时间自己也整理了属于我自己的八股文,有好几万字吧,哈哈哈,以后就不用到处去找八股文了。

  说回正题,这个group_concat的问题是最近在修复一个问题的时候发现的,是以前的人挖的坑,最近都不知道填了多少坑了,特喵的。

一. 问题背景

  一个机构树的表,就是那种有层级的,类似于下图这样的,然后我想查询某一个公司下所有部门的员工,我们就要把这个机构表递归找到一个公司下所有的部门,然后关联一下用户表查询就行了

 

  但是有人为了追求性能高一点,就把递归查询机构的逻辑使用使用find_in_set()函数和group_concat()函数封装成了mysq的自定义函数,然后调用的时候在sql级别进行处理了, 

DROP FUNCTION IF EXISTS queryChildrenAreaInfo;
DELIMITER ;;
CREATE FUNCTION queryChildrenAreaInfo(areaId INT)
RETURNS VARCHAR(4000)
BEGIN
DECLARE sTemp VARCHAR(4000);
DECLARE sTempChd VARCHAR(4000);
SET sTemp='$';
SET sTempChd = CAST(areaId AS CHAR);
WHILE sTempChd IS NOT NULL DO
SET sTemp= CONCAT(sTemp,',',sTempChd);
SELECT GROUP_CONCAT(id) INTO sTempChd FROM t_areainfo WHERE FIND_IN_SET(parent_id,sTempChd)>0;
END WHILE;
RETURN sTemp;
END
;;
DELIMITER ;

 

  使用这种方式,在测试环境肯定没问题,但是到了生产环境机构表数据多了之后肯定就会踩坑,GROUP_CONCAT(id)返回的数据有最大限制的,可以使用SHOW VARIABLES LIKE "group_concat_max_len" 进行查询,默认是1024个字节,下图所示。

  也就是如果查询的数据超过1024个字节后,只会保留前1024个字节的数据,至于修复方法,需要修改mysql配置文件或者使用sql语句临时修改:SET GLOBAL group_concat_max_len=10240000; SET SESSION group_concat_max_len=10240000;

 

  如果没有修改的话,就可能导致一个问题,一样的代码在测试环境跑的很正常,一到生产上就拉胯,你肯定以为是代码哪里和生产不一致,可能比对了很久,然后测试环境自己也测试了n次,但就是生产上数据不完整,此时你就会两眼无神,怀疑人生....

 

二 解决方

  2.1. 直接修改mysql的配置文件,扩大group_concat_max_len的最大容量,至于扩大到多少,就要靠你自己去根据数据量去衡量了,不过一般的开发也不想去为了这个一点问题就改生产数据库配置吧,麻烦....

  2.2 如果是oracle数据库,自带了递归查询的关键字:start with connect by prior, 有兴趣的可以自己研究一下,挺好用的,但是如果项目中是mysql数据库,那就不适用了

  2.3 使用sql进行递归查询,不过这种sql就是很鸡儿难看懂,要是让你维护这样的sql你想打人的心都有了,所以我也不是很推荐

-- 根据⼀个⽗节点为id为1 查询所有⼦节点(包含⾃⾝)
SELECT au.id, au.name, au.parent_id
  FROM (SELECT * FROM t_areainfo WHERE parent_id IS NOT NULL) au,
       (SELECT @pid := 1) pd
 WHERE FIND_IN_SET(parent_id, @pid) > 0
   AND @pid := concat(@pid, ',', id)
UNION
SELECT id, name, parent_id
  FROM t_areainfo
 WHERE id = '1'
 ORDER BY id;  

 

  2.4. 其实我们陷入了误区了,想一想有必要把这么复杂的逻辑都放到sql语句上处理么?其实这种越复杂的sql,会给服务器的压力也是倍增的,而且特别难排查出问题,这点是最致命的,因为只要能排查出来的问题就都不是问题。

  我的解决方案是: 首先查询出所有的机构信息,注意,如果机构信息太多,我们可以再细化,比如先查询一级机构,再查询二级机构....分批次去查询我们的数据,再内存级别进行组装; 然后根据我们查询的机构信息再调用一次数据库查询用户信息就好了,虽然和数据库交互可能多了两三次,但是逻辑变得简单了,有问题一下子就能排查出来了。

  错误示范: 先查询一级机构下所有的部门,然后遍历每一个部门分别再去数据库中查询下一级部门.....这样你会被打死的,千万不要循环中嵌套着查询数据库的逻辑

三 还有话说

  继续瞎逼逼几句,最近就是搞公司的历史遗留的项目,技术栈老,问题多,一个几万用户的对内商城项目,扣减库存的逻辑是查询数据库,内存中扣减了之后再将库存更新到数据库中......看到代码我都惊呆了呀。

  由于我刚来没几个月,之前听他们讨论有什么超卖问题,我想着这尼玛不超卖就出了鬼了, 然后我就提出了这个缺陷, 并使用了数据库乐观锁嘎嘎优化了。这段时间帮着压测这个商城项目,真的就是一堆破代码,我还要去给各种优化,性能起码提升了好多倍都不止,尼玛数据库关键的索引都有不加的,有的sql执行都需要好几秒的,加了索引之后30ms......

  继续苟着吧,现在这里最大的好处就是不怎么加班,干完自己的事情后五点半就可以走了,嘿嘿

标签:SET,group,mysql,查询,sql,id,concat
From: https://www.cnblogs.com/wyq1995/p/17436691.html

相关文章

  • Mysql练习
    1. 练习11.1 选择题   811代码在E:\java学习\初级\course166\db_exercise01--选择题写法对错判断811--错误,as可以省略但是AnnualSalary中间有空格会被认为Salary是最终的别名SELECTename,sal*12ASAnnualSalaryFROMempSELECTename,sal*12AS"AnnualSalary"FR......
  • MySQL学习进阶篇Day2
    2.索引2.1索引概述2.1.1介绍索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。 一提到数据结构,大......
  • MySQL数据类型
    数据类型的选取原则:更小的通常更好:尽量使用可以正确存储数据的最小数据类型(它们占用更少的磁盘,内存,cpu缓存,处理时需要的cpu周期也更少)简单:简单数据类型的操作通常所需cpu周期更少,例如整型就是比字符串类型的操作代价更低尽量避免NULL:最好指定列为NOTNULL,如果......
  • ubuntu 20.4 安装msyql+创建mysql用户
    sudoapt-getupdatesudoapt-getupgratesudoaptinstallmysql-server设置运行远程访问修改:sudovim/etc/mysql/mysql.conf.d/mysqld.cnf用#注释掉bind-address=127.0.0.1进入mysql创建用户mysql-uroot-pCREATEUSER'test'@'%'IDENTIFIEDBY'12345......
  • MySQL的间隙锁
    什么是间隙锁?间隙锁就是在MySQL的一个范围锁,对某个不存在数据的范围进行加锁,加锁后,不能在这个范围内插入数据;在可重复读事务隔离级别下,默认使用的是next-keyLock(行锁+间隙锁);间隙锁是为了解决什么问题?间隙锁就是MySQL在Innodb存储引擎在可重复读的事务隔离级别下为了解决当前读......
  • MySQL刷题记录
    1. select*fromemployeesorderbyhire_datedesclimit1; 笔记: limit 0,1;使用limit关键字从第0条记录向后读取一个,也就是第一条记录  2.select*fromtestLIMIT 3OFFSET 1;(在mysql 5以后支持这种写法)当limit和offset组合使用的时候,limit后面只......
  • rhel 7.3搭建mysql的主从复制—非单机场景
    文档课题:rhel7.3搭建mysql的主从复制—非单机场景.数据库:mysql8.0.27系统:rhel7.3安装包:mysql-8.0.27-linux-glibc2.12-x86_64.tar.xz环境介绍:1、理论知识master将操作语句记录到binlog日志,然后授予slave远程连接权限(master需开启binlog,为数据安全考虑,slave也开启binlog).s......
  • mysql在执行start slave命令时报错"ERROR 1872 (HY000)"
    问题描述:mysql在执行startslave命令时报错"ERROR1872(HY000)",如下所示:数据库:mysql8.0.27系统:rhel7.31、问题重现mysql>startslave;ERROR1872(HY000):Slavefailedtoinitializerelayloginfostructurefromtherepository2、异常原因从库已经存在之前的relay......
  • rhel 7.3安装mysql 8.0.27
    文档课题:rhel7.3安装mysql8.0.27.系统:rhel7.364位数据库:mysql8.0.27安装包:mysql-8.0.27-linux-glibc2.12-x86_64.tar.xz1、安装前检查1.1、系统版本[root@leo-mysql-master~]#cat/etc/*releaseNAME="RedHatEnterpriseLinuxServer"VERSION="7.3(Maipo)"ID=......
  • 阿里云服务器Linux MySQL root 密码忘记了如何操作?
    阿里云服务器Linux MySQL root密码忘记了如何操作?假如我们使用的MySQL数据库忘记的账号密码,是能够土工调节配置文件,然后跳过密码方式登录到数据库的。然后在数据库里面修改账号和密码,通常在默认情况下账号为root具体操作步骤如下:1】编辑MySQL配置文件my.cnf【注】在具体的操作......