|
- S/ Q" g0 W& o4 S8 h5 y# S! ~' T% i
原标题:MySQL中这14个必备神器,谁用了不说好?!前言:最近几年用MYSQL数据库挺多的,发现了一些非常有用的小玩意,今天拿出来分享到大家,希望对你会有所帮助1.group_concat在我们平常的工作中,使用group by进行分组的场景,是非常多的。 / f) L3 p& }* B- \/ Q, ]' j% i
比如想统计出用户表中,名称不同的用户的具体名称有哪些?具体sql如下:select name from `user`group by name;但如果想把name相同的code拼接在一起,放到另外一列中该怎么办呢? + X% t8 p; I% _) r
答:使用group_concat函数。例如:select name,group_concat(code) from `user`group by name;执行结果:
6 V1 E' i8 v" j# u# H- m 使用group_concat函数,可以轻松的把分组后,name相同的数据拼接到一起,组成一个字符串,用逗号分隔2.char_length有时候我们需要获取字符的长度,然后根据字符的长度进行排序MYSQL给我们提供了一些有用的函数,比如:char_length。
$ D( u1 t, U) ~ 通过该函数就能获取字符长度获取字符长度并且排序的sql如下:select * from brand where name like %苏三% order by char_length(name) asc limit 5;。 0 k% S: c8 l7 P; N9 X" g( R
执行效果如图所示:
6 p4 g, Y6 q5 f$ B3 L; J, [ name字段使用关键字模糊查询之后,再使用char_length函数获取name字段的字符长度,然后按长度升序3.locate有时候我们在查找某个关键字,比如:苏三,需要明确知道它在某个字符串中的位置时,该怎么办呢?。 * Z7 g& g! ~" M. G: f, T0 p
答:使用locate函数使用locate函数改造之后sql如下:select * from brand where name like %苏三% order by char_length(name) asc, locate(苏三,name) asc limit 5,5;。 * u. g5 U9 t+ B( q- Z& ^, k
执行结果:
, ]9 m& U6 Z* M/ r( E 先按长度排序,小的排在前面如果长度相同,则按关键字从左到右进行排序,越靠左的越排在前面除此之外,我们还可以使用:instr和position函数,它们的功能跟locate函数类似,在这里我就不一一介绍了,感兴趣的小伙伴可以找我私聊。
7 c w: z4 h$ ^2 G 4.replace我们经常会有替换字符串中部分内容的需求,比如:将字符串中的字符A替换成B这种情况就能使用replace函数例如:update brand set name=REPLACE(name,A,B) 。 ; C& m3 ]2 R) Z* D
where id=1;这样就能轻松实现字符替换功能也能用该函数去掉前后空格:update brand set name=REPLACE(name, ,) where name like %;update brand set name=REPLACE(name, ,) where name like % ;。
( ~" Y/ a! K: _1 G 使用该函数还能替换json格式的数据内容,真的非常有用5.now时间是个好东西,用它可以快速缩小数据范围,我们经常有获取当前时间的需求在MYSQL中获取当前时间,可以使用now()函数,例如:select now() from brand limit 1;。 & X- o# ^ o6 c. z- Y, ~
返回结果为下面这样的:
. U: m: F# P, r# u; K. C5 P 它会包含年月日时分秒。如果你还想返回毫秒,可以使用now(3),例如:select now(3) from brand limit 1;返回结果为下面这样的:
* r# |0 n$ X% ?- T 使用起来非常方便好记6.insert into ... select在工作中很多时候需要插入数据传统的插入数据的sql是这样的:INSERT INTO `brand`(`id`, `code`, `name`, `edit_date`) 。
" d; \& k$ }7 g7 h5 k$ \$ Q VALUES (5, 108, 苏三, 2022-09-02 19:42:21);它主要是用于插入少量并且已经确定的数据但如果有大批量的数据需要插入,特别是是需要插入的数据来源于,另外一张表或者多张表的结果集中。 & R3 H; s* p1 {. }6 |
这种情况下,使用传统的插入数据的方式,就有点束手无策了这时候就能使用MYSQL提供的:insert into ... select语法例如:INSERT INTO `brand`(`id`, `code`, `name`, `edit_date`) 。 ( a" Z% K+ s8 R* s6 _& F' F6 _
select null,code,name,now(3) from `order` where code in (004,005);这样就能将order表中的部分数据,非常轻松插入到brand表中7.insert into ... ignore。
, b8 _( {2 F) C& G& Y! O5 m0 g 不知道你有没有遇到过这样的场景:在插入1000个品牌之前,需要先根据name,判断一下是否存在如果存在,则不插入数据如果不存在,才需要插入数据如果直接这样插入数据:INSERT INTO `brand`(`id`, `code`, `name`, `edit_date`) 。
; V- M& I- W# v VALUES (123, 108, 苏三, now(3));肯定不行,因为brand表的name字段创建了唯一索引,同时该表中已经有一条name等于苏三的数据了。执行之后直接报错了:
5 l# `- W+ g& y0 ? 这就需要在插入之前加一下判断当然很多人通过在sql语句后面拼接not exists语句,也能达到防止出现重复数据的目的,比如:INSERT INTO `brand`(`id`, `code`, `name`, `edit_date`) 。 5 M' B1 \9 E9 U0 r2 M) X
select null,108, 苏三,now(3) from dual where not exists (select * from `brand` where name=苏三);这条sql确实能够满足要求,但是总觉得有些麻烦。 7 e5 T7 \ `: w+ `7 c# i" N7 }% D
那么,有没有更简单的做法呢?答:可以使用insert into ... ignore语法例如:INSERT ignore INTO `brand`(`id`, `code`, `name`, `edit_date`) 。
0 @: R0 w1 }- U, v VALUES (123, 108, 苏三, now(3));这样改造之后,如果brand表中没有name为苏三的数据,则可以直接插入成功但如果brand表中已经存在name为苏三的数据了,则该sql语句也能正常执行,并不会报错。
5 F6 e# b! G n& |9 [3 I. r 因为它会忽略异常,返回的执行结果影响行数为0,它不会重复插入数据8.select ... for updateMYSQL数据库自带了悲观锁,它是一种排它锁,根据锁的粒度从大到小分为:表锁、间隙锁和行锁在我们的实际业务场景中,有些情况并发量不太高,为了保证数据的正确性,使用悲观锁也可以。
* Y5 o1 ^# w" F4 ?) l& v5 q. O% _ 比如:用户扣减积分,用户的操作并不集中但也要考虑系统自动赠送积分的并发情况,所以有必要加悲观锁限制一下,防止出现积分加错的情况发生这时候就可以使用MYSQL中的select ... for update语法了。
4 \5 t, Q7 {( }/ b 例如:begin;select * from `user` where id=1 for update;//业务逻辑处理update `user` set score=score-1 where id=1; 7 s+ M* J# c2 i
commit;这样在一个事务中使用for update锁住一行记录,其他事务就不能在该事务提交之前,去更新那一行的数据需要注意的是for update前的id条件,必须是表的主键或者唯一索引,不然行锁可能会失效,有可能变成表锁。
( c" _( ?8 ?: y5 V, v/ E# K4 h+ m3 _' w 9.on duplicate key update通常情况下,我们在插入数据之前,一般会先查询一下,该数据是否存在如果不存在,则插入数据如果已存在,则不插入数据,而直接返回结果在没啥并发量的场景中,这种做法是没有什么问题的。 2 o- k1 p& O& h
但如果插入数据的请求,有一定的并发量,这种做法就可能会产生重复的数据当然防止重复数据的做法很多,比如:加唯一索引、加分布式锁等但这些方案,都没法做到让第二次请求也更新数据,它们一般会判断已经存在就直接返回了。 % j5 c3 ~) n7 i2 U$ u
这种情况可以使用on duplicate key update语法该语法会在插入数据之前判断,如果主键或唯一索引不存在,则插入数据如果主键或唯一索引存在,则执行更新操作具体需要更新的字段可以指定,例如:。 1 C( F W" w$ J2 q! ^; ^
INSERT INTO `brand`(`id`, `code`, `name`, `edit_date`) VALUES (123, 108, 苏三, now(3))on duplicate key update name=苏三,edit_date=now(3); 5 x$ t$ S/ `* f* }
这样一条语句就能轻松搞定需求,既不会产生重复数据,也能更新最新的数据但需要注意的是,在高并发的场景下使用on duplicate key update语法,可能会存在死锁的问题,所以要根据实际情况酌情使用。
9 h7 q5 U& X+ }2 s 10.show create table有时候,我们想快速查看某张表的字段情况,通常会使用desc命令,比如:desc `order`;结果如图所示:
! v# r! i. n" t4 h z 确实能够看到order表中的字段名称、字段类型、字段长度、是否允许为空,是否主键、默认值等信息但看不到该表的索引信息,如果想看创建了哪些索引,该怎么办呢?答:使用show index命令比如:show index from `order`;。
7 w. E' F S) n: a: c+ d" C 也能查出该表所有的索引:
9 E# ^8 F( U- g8 b' | 但查看字段和索引数据呈现方式,总觉得有点怪怪的,有没有一种更直观的方式?答:这就需要使用show create table命令了例如:show create table `order`;执行结果如图所示:。 8 _1 E7 U% ]% S
其中Table表示表名,Create Table就是我们需要看的建表信息,将数据展开:图片我们能够看到非常完整的建表语句,表名、字段名、字段类型、字段长度、字符集、主键、索引、执行引擎等都能看到非常直接明了。 2 r x" `$ l6 ^5 {
11.create table ... select有时候,我们需要快速备份表通常情况下,可以分两步走:创建一张临时表将数据插入临时表创建临时表可以使用命令:create table order_2022121819 like `order`;。
2 C2 U6 E# p8 I- }: D9 {' g 创建成功之后,就会生成一张名称叫:order_2022121819,表结构跟order一模一样的新表,只是该表的数据为空而已接下来使用命令:insert into order_2022121819 select * from `order`;。
* k$ d: Y/ V1 Q9 m) X 执行之后就会将order表的数据插入到order_2022121819表中,也就是实现数据备份的功能但有没有命令,一个命令就能实现上面这两步的功能呢?答:用create table ... select命令。
; F9 v! {7 h' F7 a 例如:create table order_2022121820 select * from `order`;执行完之后,就会将order_2022121820表创建好,并且将order表中的数据自动插入到新创建的order_2022121820中。
2 b' d; u5 I/ y6 ?1 s# e! m4 Y 一个命令就能轻松搞定表备份12.explain很多时候,我们优化一条sql语句的性能,需要查看索引执行情况答:可以使用explain命令,查看mysql的执行计划,它会显示索引的使用情况例如:explain select * from `order` where code=002;。 - a/ @! [3 G y6 e: F
结果:通过这几列可以判断索引使用情况,执行计划包含列的含义如下图所示:说实话,sql语句没有走索引,排除没有建索引之外,最大的可能性是索引失效了下面说说索引失效的常见原因:如果不是上面的这些原因,则需要再进一步排查一下其他原因。 # d( \ M$ B' r6 M: s; `4 B
13.show processlist有些时候我们线上sql或者数据库出现了问题比如出现了数据库连接过多问题,或者发现有一条sql语句的执行时间特别长这时候该怎么办呢?答:我们可以使用show processlist命令查看当前线程执行情况。 ( T0 |6 M$ C7 K; K% w: Z) U, d
如图所示:从执行结果中,我们可以查看当前的连接状态,帮助识别出有问题的查询语句id 线程idUser 执行sql的账号Host 执行sql的数据库的ip和端号db 数据库名称Command 执行命令,包括:Daemon、Query、Sleep等。
' r; c1 A5 E5 \ Time 执行sql所消耗的时间State 执行状态info 执行信息,里面可能包含sql信息如果发现了异常的sql语句,可以直接kill掉,确保数据库不会出现严重的问题14.mysqldump有时候我们需要导出MYSQL表中的数据。 . ~. F6 p- T* Y" ^9 F) X
这种情况就可以使用mysqldump工具,该工具会将数据查出来,转换成insert语句,写入到某个文件中,相当于数据备份我们获取到该文件,然后执行相应的insert语句,就能创建相关的表,并且写入数据了,这就相当于数据还原。
+ L" V3 g* A3 P) O i, l, [, F mysqldump命令的语法为:mysqldump -h主机名 -P端口 -u用户名 -p密码 参数1,参数2.... > 文件名称.sql备份远程数据库中的数据库:mysqldump -h 192.22.25.226 -u root -p123456 dbname > backup.sql M% l- i- G5 F# k4 ?6 o
作者丨苏三呀来源丨公众号:苏三说技术(ID:susanSayJava)dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn关于我们dbaplus社群是围绕Database、BigData、AIOps的企业级专业社群。 . d6 `; e& {5 n8 m7 k# b
资深大咖、技术干货,每天精品原创文章推送,每周线上技术分享,每月线下技术沙龙,每季度Gdevops&DAMS行业大会关注公众号【dbaplus社群】,获取更多原创技术文章和精选工具下载返回搜狐,查看更多
* T* c5 \+ O, X% R: r* o0 ~ 责任编辑: 2 r4 _' r; s, U# p
% ~8 D5 u! i& o
5 I O! e' y* j( }( p( n, ?: g- o. U
/ o2 x$ f1 e2 F0 F
|