当前位置: 首页 > 科技观察

MySQL中的这14个小玩意,让人眼前一亮!!!

时间:2023-03-17 19:27:07 科技观察

前言这几年用了很多MYSQL数据库,发现了一些非常好用的小工具。我今天将与您分享。我希望它们对你有所帮助。1.group_concat在我们平时的工作中,有很多场景会使用groupby来进行分组。比如你要统计user表中不同名字的用户的具体名字?具体sql如下:selectnamefrom`user`groupbyname;但是如果你想把同名的代码拼接在一起放在另一列中怎么办?答:使用group_concat函数。例如:selectname,group_concat(code)from`user`groupbyname;执行结果:使用group_concat函数可以方便的将分组后的同名数据进行拼接,形成一个以逗号分隔的字符串。2.char_length有时候我们需要获取字符的长度,然后根据字符的长度进行排序。MYSQL为我们提供了一些有用的函数,例如:char_length。字符长度可以通过这个函数得到。获取字符长度并排序的sql如下:select*frombrandwherenamelike'%SuSan%'orderbychar_length(name)asclimit5;执行效果如图:name字段使用关键字模糊查询后,再使用char_length函数获取name字段的字符长度,然后按长度升序排序。3.locate有时候我们在寻找某个关键词的时候,比如:苏三,需要知道它在某个字符串中的位置怎么办?答:使用定位功能。使用locate函数后,sql如下:select*frombrandwherenamelike'%SuSan%'orderbychar_length(name)asc,locate('SuSan',name)asclimit5,5;执行结果:按长度排序,小的在前。如果长度相同,则按照关键字从左到右排序,靠左的排在第一位。此外,我们还可以使用:instr和position函数。它们的功能类似于定位功能。这里就不一一介绍了。有兴趣的朋友可以私聊我。4.replace我们经常会有替换字符串中部分内容的需求,例如:将字符串中的字符A替换为B,这时就可以使用replace函数。例如:updatebrandsetname=REPLACE(name,'A','B')whereid=1;这样就可以轻松实现字符替换功能。您还可以使用此函数删除前导和尾随空格:updatebrandsetname=REPLACE(name,'','')wherenamelike'%';updatebrandsetname=REPLACE(name,'','')wherenamelike'%';利用这个功能还可以替换json格式的数据内容,真的非常好用。5.现在时间是个好东西。它可以快速缩小数据范围。我们经常有获取当前时间的需求。在MYSQL中获取当前时间可以使用now()函数,例如:selectnow()frombrandlimit1;返回结果如下:包含年、月、日、时、分、秒。如果还想返回毫秒,可以使用now(3),例如:selectnow(3)frombrandlimit1;返回结果如下:使用起来很方便,也很容易记住。6.insertinto...select工作时需要多次插入数据。传统的插入数据的sql是这样的:INSERTINTO`brand`(`id`,`code`,`name`,`edit_date`)VALUES(5,'108','苏三','2022-09-0219:42:21');主要用于插入少量已经确定的数据。但是如果需要插入的数据量很大,尤其是插入的数据来自于另外一个表或者多个表的结果集。在这种情况下,使用传统的插入数据的方式就有点束手无策了。这时候可以使用MYSQL提供的语法:insertinto...select。例如:INSERTINTO`brand`(`id`,`code`,`name`,`edit_date`)selectnull,code,name,now(3)from`order`wherecodein('004','005');这样就可以方便地将order表中的部分数据插入到brand表中。7.insertinto...ignore不知道大家有没有遇到过这样的场景:在插入1000个品牌之前,需要根据名字判断是否存在。如果存在,则不插入任何数据。如果不存在,则需要插入数据。如果像这样直接插入数据:INSERTINTO`brand`(`id`,`code`,`name`,`edit_date`)VALUES(123,'108','苏三',now(3));肯定不是,因为brand表的name字段创建了唯一索引,而这张表中已经有name等于苏三的数据了。执行完直接报错:这个需要在插入前加判断。当然,很多人也可以通过在sql语句后拼接notexists语句来达到防止重复数据的目的,比如:INSERTINTO`brand`(`id`,`code`,`name`,`edit_date`)selectnull,'108','SuSan',now(3)fromdualwherenotexists(select*from`brand`wherename='SuSan');这个sql确实可以满足要求,但是总感觉有点麻烦。那么,有没有更简单的方法呢?答案:您可以使用insertinto...ignore语法。例如:INSERTignoreINTO`brand`(`id`,`code`,`name`,`edit_date`)VALUES(123,'108','苏三',now(3));这样改造后,如果品牌表中没有名字为苏三的数据,则可以直接插入成功。但是如果brand表中已经存在名称为苏三的数据,SQL语句也可以正常执行,不会报错。因为忽略异常,返回的执行结果影响的行数为0,不会重复插入数据。8.select...forupdateMYSQL数据库自带悲观锁,也就是排它锁。按照锁的粒度分为:表锁、间隙锁和行锁。在我们实际的业务场景中,有些情况下,并发度并不会太高。为了保证数据的正确性,也可以使用悲观锁。例如:用户扣分,用户操作不集中。但是还要考虑到系统自动赠送积分的并发性,所以需要加悲观锁来限制,防止积分添加错误的发生。这时候可以在MYSQL中使用select...forupdate语法。例如:begin;select*from`user`whereid=1forupdate;//业务逻辑处理update`user`setscore=score-1whereid=1;commit;这样,使用forupdate锁定一个事务记录中的一行,其他事务在该事务提交之前不能更新该行中的数据。需要注意的是,update之前的id条件必须是表的主键或者唯一索引,否则行锁可能失效,可能变成表锁。9.onduplicatekeyupdate通常,在插入数据之前,我们通常会检查数据是否存在。如果不存在则插入数据。如果已经存在,则不插入数据,直接返回结果。在并发量不大的场景下,这种方式是没有问题的。但是如果插入数据的请求有一定的并发量,这种方式可能会产生重复数据。当然,防止重复数据的方法有很多,比如:加唯一索引,加分布式锁等,但是这些方案都不能让二次请求也更新数据,一般判断为直接返回已经存在。在这种情况下,您可以使用onduplicatekeyupdate语法。该语法会在插入数据前进行判断,如果主键或唯一索引不存在,则插入数据。如果存在主键或唯一索引,则执行更新操作。可以指定具体要更新的字段,例如:INSERTINTO`brand`(`id`,`code`,`name`,`edit_date`)VALUES(123,'108','苏三',now(3))重复键更新name='SuSan',edit_date=now(3);这样的语句很容易满足要求,既不会重复数据,又能更新最新的数据。但是需要注意的是,在高并发场景下使用onduplicatekeyupdate语法可能会出现死锁问题,所以要根据实际情况酌情使用。10.showcreatetable有时候,我们想快速查看某个表的字段,通常使用desc命令,如:desc`order`;结果如图:我们确实可以看到订单表中的字段名和字段类型,字段长度,是否允许为空,是否为主键,默认值等信息。但是看不到表的索引信息。想查看创建了哪些索引怎么办?答:使用showindex命令。例如:显示来自`order`的索引;也可以查出表的所有索引:但是看字段和索引数据的呈现方式,总觉得有点怪怪的。有没有更直观的方法?答:需要使用showcreatetable命令。例如:showcreatetable`order`;执行结果如图:Table代表表名,CreateTable就是我们要看的表创建信息。展开数据:我们可以看到一个非常完整的建表语句,表名,字段名,字段类型,字段长度,字符集,主键,索引,执行引擎等等都可以看到。非常简单。11.createtable...select有时候,我们需要快速备份表。通常分为两步:创建临时表和向临时表插入数据。要创建临时表,可以使用命令:createtableorder_2022121819like`order`;创建成功后,新建一张表,名称为:order_2022121819,表与order的结构完全一样,只是这张表的数据为空。接下来,使用命令:insertintoorder_2022121819select*from`order`;执行后会将order表中的数据插入到order_2022121819表中,实现数据备份的功能。但是有没有什么命令,一个命令就可以实现上面两步的功能呢?答:使用createtable...select命令。例如:createtableorder_2022121820select*from`order`;执行后会创建order_2022121820表,order表中的数据会自动插入到新建的order_2022121820中。只需一条命令即可轻松完成表备份。12.explain很多时候,我们在优化一条SQL语句的性能时,需要查看索引的执行状态。答:可以使用explain命令查看mysql的执行计划,里面会显示索引的使用情况。例如:解释select*from`order`wherecode='002';结果:可以通过这些列来判断索引的使用情况,执行计划中包含的列的含义如下图所示:其他文章《?explain | 索引优化的这把绝世好剑,你真的会用吗?》说句实话,sql语句并没有用到索引,除了没有建索引,最大的可能就是索引失效了。下面说说索引失败的常见原因:如果不是上述原因,则需要进一步排查其他原因。13.showprocesslist有时候我们在线的sql或者数据库有问题。比如数据库连接太多,或者发现某个SQL语句执行时间特别长。这个时候怎么办?答:我们可以使用showprocesslist命令查看当前线程执行情况。如图:从执行结果中,我们可以查看当前的连接状态,帮助识别有问题的查询语句。idthreadidUseraccount执行sql执行sql的主机ip和端口号dbdatabasenameCommand执行命令,包括:Daemon,Query,Sleep等Time执行sql耗时StateExecutionstatusinfo执行信息,可能包含sql信息。如果发现异常的sql语句,可以直接kill掉,保证数据库不会出现大问题。14.mysqldump有时候我们需要导出MYSQL表中的数据。这种情况下可以使用mysqldump工具,它会把数据查出来,转换成insert语句写入文件,相当于数据备份。我们拿到文件,然后执行相应的insert语句,创建相关的表,写入数据,相当于数据还原。mysqldump命令的语法为:mysqldump-h主机名-P端口-u用户名-p密码参数1,参数2...>文件名。sql备份远程数据库中的数据库:mysqldump-h192.22.25.226-uroot-p123456dbname>backup.sql