MySQL 部分小结

数据库概述

数据(Data)

对于计算机来说,数据就是计算机存储的(有用的)信息。既然是计算机存储的,那么实质上它就是一串二进制数据(0、1),但是人始终还是要用这个信息的,所以数据存储不能是毫无章法的,它必须遵循一定的规则,数据格式定义了这种规则。

我们之前说过的数据类型就是一种数据格式,比如它规定了整型的数在内存中应该是什么的,浮点型的应该是什么样子。

我们讲操作系统的时候,操作系统的文件系统也是一种数据格式。操作系统在处理读写磁盘文件的时候,肯定要先知道这个文件是什么大概什么格式的,比如word文档、文本文档等。

对于数据来说,最重要的就是它的格式,如果格式定义不清晰,数据就没法存储和处理。

但是即使我们定义清晰了,也还是会有问题。比如,Windows操作系统下的文件,复制到Linux操作系统下,就可能识别不出来。也就是说,数据格式还一个系统兼容性问题。对于文件系统这一类数据表示形式来说,它是高度依赖于操作系统的。如果我们写了一个软件,这个软件是把数据存储到了比如Windows上,那么即使这个软件我们是使用的Java(跨平台)语言开发的,迁移到Linux上,也不一定能够使用。因为Java跨平台,它解决的只是程序设计语言的跨平台,对于数据,它无能为力。所以就要有一种机制,来实现数据格式跨平台兼容。

数据库(DataBase)

数据库,顾名思义,就是遵循一定数据格式的数据集合,可以认为它是对文件系统的改进。它解决了不同操作系统之前,数据格式的兼容性问题。也就是说,只要是同一个数据库的数据文件,即使是从Windows迁移到了Linux上,也可以正常处理的。

数据库管理系统(DataBaseManagementSystem)

最靠近我们用户(开发人员)的其实不是数据库(这个概念要更接近硬件,更底层),我们通常说数据库,其实是说数据库管理系统(DBMS)。

扫描二维码关注公众号,回复: 4280887 查看本文章

DB是DBMS的一个组成部分(底层实现),对于一个DBMS来说,除了底层数据(DB),还有其他组成部分。比如存储引擎,比如服务器组件,比如UI(命令行,图形化界面),还有其他的一些类似SQL解释器,连接认证系统等。

一些应用广泛的DBMS

 

画红框的是我们重点关注的。

Oracle,这是一种关系型数据库。它的特点是闭源收费,但是功能强大稳定,而且有一支专业的技术支撑团队。使用这种数据库的一般是大型企业、银行业、金融业。

MySQL,它也是关系型数据库。它的特点是开源免费,功能还是不错的,也比较稳定。通常使用这种数据库的,是中小企业等。因为它是开源的,所以我们有些企业可以对它做定制化、二次开发,以支持自己特殊的业务。比如阿里。说它是目前应用最广泛的DBMS是不夸张的。

Memcached、Redis,这2者是非关系型数据库(Not Only SQL)。它们通常用K-V键值对的形式存储数据,使用场景为缓存(可做为关系型数据库的补充)。它俩都是基于内存存储的,它们的数据都是在内存中,所以访问速度要快。Redis还提供了定期向磁盘中进行序列化的机制,它的IO性能也是非常高的。

MongoDB,这个也是NOSQL数据库。它使用文档形式存储数据。使用场景,通常是大数据量高并发访问。它的性能也非常高。

 

 

DDL Data Definition Language,数据定义语言

use -

use test1; -- 使用库

desc

desc hello; -- 查看表结构

show

show tables; -- 查询当前库的所有表

show databases; -- 查询当前连接的数据库服务器的所有数据库

show create table student --查看建表语句

show create database test1 --查看建库语句

select - 方法

select version();-- 展示已连接数据库版本

select database();-- 展示当前使用的数据库,可用use切换

create - 建库、表

create database test1; -- 建库

create table hello( -- 建表

age int,

`name` varchar(30),

money decimal(18,2)

)ENGINE=InnoDNB DEFAULT CHARSET=utf8;

create index idx_sc_c on student_score(cname); 建索引

 

drop - 删,库、表、字段 慎重删除!!!

drop database test; -- 删库

drop table ss; -- 删表

alter table teacher drop birthday;

drop index idx_sc_c on student_score; 删索引

 

alter - 修改 慎重!!!

rename

alter table hello

rename hello_info; -- 改表名

change

alter table hello_info

change money money_copy varchar(20); -- 改表的字段名,顺带改型类

add

alter table hello_info

add address varchar(500); -- 给表加字段,在最后加

alter table hello_info

add address varchar(500) after teacher_name; -- 少用

alter table student_score add key idx_sc_s_c(sname,cname)

ALTER table student

add PRIMARY KEY(teacher_id,id,name);  --加主键

ALTER table student

add FOREIGN KEY(teacher_id)references teacher(teacher_id); --加外键

drop

alter table teacher drop birthday;      --删字段

alter table student_score drop key idx_sc_s_c; 删除索引

modify

alter table hello_info

modify address varchar(600) comment'家庭住址'; -- 改类型,改大小

type

alter table teacher type=InnoDB; -- 修改表的存储引擎

 

注意事项

通常,对于SQL语法中的关键字比如CREATE等,使用大写,其他可以用小写。

改类型的时候要注意,尽量把类型扩大(比如varchar(100)改成varchar(500)),不要反过来改。尽量不要跨类型改(比如把一个decimal改成了int)。

反引号(`):它的作用是为了区分开表名/字段名与SQL语法关键字的。

primary key -主键 实体完整性

表建立时添主键:

create table teacher(

id int not null default 0,

name varchar(20) not null default ' ',

teacher_id int not null default 0,

PRIMARY KEY(teacher_id)

);

表建完时添主键:

create table student(

id int not null default 0,

`name` varchar(100) not null default '',

teacher_id int not null default 0

);

ALTER table student

add PRIMARY KEY(teacher_id,id,name);

 

foreign key - 外键 关联完整性

表建立时添外键:

create table student_2(

id int not null default 0,

`name` varchar(100) not null default ' ',

student_id int not null default 0,

teacher_id int not null default 0,

PRIMARY KEY(student_id),

foreign key(teacher_id)references teacher(teacher_id)

);

表建完时添外键:

create table student(

id int not null default 0,

`name` varchar(100) not null default ' ',

teacher_id int not null default 0,

PRIMARY KEY(id)

);

ALTER table student

add FOREIGN KEY(teacher_id)references teacher(teacher_id);

 

DML Data Manipulation Language数据操纵语言

 

insert

insert into student_2(id,name,student_id,teacher_id)

values(1,'东邪',1,2);

insert into student -- 不建议使用

values(103,'陆军','男','1974-06-03','95031');

update

update person -- 更新数据,一定要加where限制!!否则会全表删除

set id = 19,

`name` = '南帝',

salary = 99.0,

address = '大理'

where `name` = '南海';

delete

delete from teacher

where name='老王'; -- 删除数据,一定要加where限制!!否则会全表删除

 

 

DQL(Data Query Language)数据查询语言

查表的某字段

union / union all

它俩的作用是把两张表或者更多表合并成一张表

前者会去重(去重的依据是,UNION时SELECT出来的字段如果对应相等则认为是同一条记录,这的逻辑我们可以参考Java equals)

后者则不会去重,它会保留两张表中的所有记录,但是它性能高(因为去重操作要花时间),

尽量使用union all,把去重这个工作交给代码去完成,这样可以减少MYSQL服务器的压力

 

使用union / union all的时候要注意:

1.参与合并的表,它们SELECT出来的字段数量必须一致(强制规则)

2.参与合并的表,它们SELECT出来的字段的类型建议一一对应(非强制,但是最好遵循这条规则)

3.参与合并的表,它们SELECT出来的字段的顺序建议一致(非强制,但是最好遵循这条规则)

 

单表查询

常用的where条件

查询语句select  *  from  student  where  A  and  B;筛选student表中既满足条件A又满足条件B的记录。

而select  *  from  student  where  A  or  B;筛选的则是只要满足A或者B其中一个条件即可的记录。

命令select  *  from  student  where  score  >  80;筛选的是student表中score字段值大于80的记录。

大于等于使用  >=。小于等于使用  <=。小于使用  <。等于使用  =。不等于使用  <>。

命令select  *  from  student  where  score>=60  and  score<=80;等价于

命令select  *  from  student  where  score  between  60  and  80;

命令select  *  from  student  where  score=10  or  score=20;等价于

命令select  *  from  student  where  score  in  (10,  20);

对score  in  (10,  20);的逻辑否是  score  not  in  (10,  20);

命令select  *  from  student  where  score  is  null;筛选student表中score字段值为null的记录。对is  null的逻辑否是 is  not  null。

 

去重distinct

select distinct teacher_id from student; - - 单一去重

select distinct teacher_id,id,name - - 联合去重

from student;

排序order   by  字段名   [desc|asc]

select * from  student order by score desc;按score字段降序排序。升序则使用 asc。

select * from  student order by teacher_id asc, score desc;先按teacher_id升序排序,如果teacher_id相同,再按score降序排序。

限制条数limit 条数。通常与order by 配合使用

select * from  student order by score desc limit 3;求成绩在前三名的学生

统计函数/聚合函数/分组查询

MYSQL中有一类特殊的函数,用于统计,或者分组统计。常用的有求数量的count(1)(等价于count(*)),求最大值的max(字段名),求最小值的min(字段名),求平均值的avg(字段名),求总和的sum(字段名)。

如select  count(*)  from   student;用于计算student表中一共有多少条记录。

而select  count(*)  from  student  where  A;用于计算student表中满足条件A的记录的条数

子查询

子查询又叫嵌套查询。它通常可以位于SELECT后面 FROM后面 WHERE后面。3种使用场景。

select嵌套

当位于SELECT后面时,要注意

1.一定要在两个表之间找好对应关系(teacher.id必须是主键或者必须保证teacher.id在teacher表中是唯一的)

2.子查询中只能有一个字段(子查询的结果必须是一行一列)

 

使用子查询的时候,建议大家养成使用别名的好习惯,这样可以让我们的查询语句更加清晰。别名可以用来命令新字段,也可以用来命名新表。

from嵌套

当位于FROM后面时,要注意

1.我们可以把子查询当成一张表

2.必须要有别名

where嵌套

当位于WHERE后面时,要注意

1.用in而不要用=,可使用exists优化

2.子查询中的SELECT后面只能有一个字段(多个字段的话会报错,但可以使用条件限制其在特点条件只有一条)

 

表连接查询

交叉连接(完全笛卡儿积)

    from t1,t2

    from t1 join t2

内连接

    隐式 from t1,t2 where

    显示 from t1 innerjoin t2 on t1.xx=t2.xx

外连接

左外连接  left join table on

右外连接  right join table on

 

子查询和连接查询性能比较

连接查询优于子查询(因为数据库对连接查询有优化),子查询和连接查询都能实现二点情况下使用连接查询

避免查询语句中多个子查询,最好一个,且子查询结果最最好一个字段(记录越少越好)

不得已必须使用子查询还得用子查询

 

MySQL常用系统函数

系统信息类

select version();显示当前MySQL软件的版本

SELECT DATABASE();显示当前所处数据库是哪个。(可以使用use  <数据库名>切换所在库)

字符类

如select  char_length('中国');返回字符个数。

如select  length('中国');返回字符所占字节数。MySQL中,一个UTF8编码的汉字占3个字节。

如select  concat(  'a',  'b',  'c',  'd');返回  'abcd'。字符串拼接函数(可变元参数)。

如select  concat_ws(  '=',  'a',  'b',  'c');返回  'a=b=c'。字符串拼接函数(可变元参数,但是第一个参数必须是拼接间隔符)。但是可以指定拼接间隔符。

如select   upper('abcd');返回ABCD。将参数中所有小写字母转换为大写。

如select  lower('ABCD');返回abcd。将参数中所有大写字母转换为小写。

如select  substring(  '系统信息类',  1,  3  );返回  系统信。第2个参数代表从1开始的第几个字符,第3个参数代表截取字符个数。

如select  trim('  abc  ');返回 abc。用于删去参数左右的所有空格。

日期时间类

select  curdate();返回当前日期

select  curtime();返回当前时间

select CURRENT_TIME();

select CURRENT_DATE();

select  now();返回当前日期时间

select  unix_timestamp();返回当前日期时间对应的时间戳(单位秒)

select  unix_timestamp('2018-05-24 20:00:00');返回参数指定的日期时间对应的时间戳(单位秒)

select  from_unixtime(1527163397);返回参数指定时间戳(单位秒)对应的日期时间

select  datediff(  '2018-05-23',  now()  );返回两个参数对应日期相差的天数(用第一个参数减第二个参数)

select  adddate( now(), -2 );返回指定天数前/后的日期时间(第一个参数是日期时间,第二个参数是天数,向后加是正数,向前减是负数)

条件判断类

select  if(  <判断条件>,  <条件为真时的返回值>,  <条件为假时的返回值>  );相当于Java中的三目运算符<判断条件>  ?  <条件为真的返回值>  :  <条件为假的返回值>。

如select  if(1=1,  2,  3);返回2。

select  ifnull(<表达式或者字段>,  <表达式或者字段为NULL时的返回值>);通常用于给有可能有NULL的情况下的提供默认值。

 

MySQL扩展

sql注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

性能优化

慢查询原因(通常DBMS都有自己的慢查询日志):

外部原因:内存太小,本地I/O瓶颈,网络I/O瓶颈;

内部原因:程序本身DB设计不合理,SQL语句使用不合理,无索引或者有索引但未充分利用。

学会使用explain分析简单的查询。

数据库设计层面的优化

遵循数据库设计三范式(通俗地讲就是每个字段不可再拆分,尽量减少冗余字段);

字段类型设计上,能使用数值就不要使用字符串,能使用日期时间就不要使用字符串,最好把字段声明为not null default 默认值;

为了避免表连接查询,必要的冗余字段是可以设置的;

能提前建立的索引要提前建好(经常用在where、group by、order by中的字段最好建索引)。

创建索引方式一:alter table student_score add key idx_sc_s_c(sname,cname);

删除索引方式一:alter table student_score drop key idx_sc_s_c;

创建索引方式二:create index idx_sc_c on student_score(cname);

删除索引方式二:drop index idx_sc_c on student_score;

如下图,联合索引,idx_sc_s_c,在红框中的用法,是使用不到联合索引的。

要想使用联合索引,要么把联合索引中的字段按顺序全都用上(sname= and cname= ),要么就使用最左边的字段(sname=)

 

 

SQL语句使用层面的优化

尽量不使用 select *,而是要具体指定字段,比如select id, name...;

尽量不使用不等于<>;

不使用is null/is not null(虽然也会使用索引,但是性能损耗是由于default null的字段要比not null的字段多出额外的存储空间来标识这个字段的值是不是null);

不使用or连接不同的字段;

不使用not in;

不在条件字段上使用函数;

不使用前置模糊查询(like '%a');等。

因为上面的使用方式都会产生全表扫描(当然,如果实在没办法优化,全表扫描就扫描吧)

索引优化

建立索引的字段从内容上要有差异要有区分度。

索引提升的是读性能,如果一张表的写操作更多,则尽量不建或者少建索引。

使用where、group by、order by时,尽量充分利用建立索引的字段。

数据导入和导出

先将老表数据导出为本地磁盘文件:

select * from  student into outfile 'stu_bak';

导出时,如果outfile使用相对路径,则基准目录是/var/lib/mysql/库名

如果是windows 7,则是C:/ProgramData/MySQL/MySQL Server 5.5/data/库名

再创建一个和老表结构相同的新表:

create table student4 select * from student where 1=2; 创建表结构但不复制数据

或者新创建一个库

create database aaa;

use aaa;

create table student_score select * from  lhl_test.student_score where false;

修改表的存储引擎alter table student_score type=innodb;

后将导出的本地磁盘文件导入新表:

load data local infile '/var/lib/mysql/lhl_test/stu_bak' into table student4;

如果是新创建库的则是

load data local infile '/var/lib/mysql/lhl_test/student_score_bak' into table student_score;

导入时,如果infile使用相对路径,则基准目录是家目录。

如果是windows 7,则infile后面必须使用绝对路径,\使用/代替

PS:

create table student4 select * from student where 1=1; 创建表结构同时复制数据

行转列

创建一张表,用于练习:

CREATE TABLE `student_score` (

  `id` int(11) NOT NULL DEFAULT '0',

  `sname` varchar(100) NOT NULL DEFAULT '',

  `cname` varchar(100) NOT NULL DEFAULT '',

  `score` decimal(18,2) NOT NULL DEFAULT '0.00',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

初始化数据后如下:

 

 

场景一(多行转为一行多列):

 

 

可以使用下面的SQL语句(group by 与 case when结合使用即可实现):

select sname,

max(

case cname

when 'Java' then score

else 0

end

) Java,

max(

case cname

when 'MySQL' then score

else 0

end

) MySQL

from student_score

group by sname;

 

 ---------------------------------------------------

select sname,

max(case cname

when 'Java' then score

end) Java,

max(case cname

when 'MySQL' then score

end) MySQL

from student_score

group by sname;

就得到最终结果啦。

 

场景二(多行转为一行一列):

 

 

第一步:拆分问题,先按分组的思路,只处理一个学员,如小李

select sname, cname, score

from student_score

where sname = '小李';

 

 

第二步:将课程名与成绩拼接成一列

select sname,

concat(cname,'=',score) '各科成绩'

from student_score

where sname = '小李';

 

 

第三步:利用group_concat函数将多行压扁到一行

select sname,

group_concat(cname,'=',score) '各科成绩'

from student_score

where sname = '小李';

 

 

第四步:修改分隔符(默认是逗号)

select sname,

group_concat(cname,'=',score  separator ' | ') '各科成绩'

from student_score

where sname = '小李';

 

 

第五步:按课程名称排序

select sname,

group_concat(cname,'=',score order by cname asc  separator ' | ') '各科成绩'

from student_score

where sname = '小李';

 

 

最后一步:对全表应用group by

select sname,

group_concat(cname,'=',score order by cname asc  separator ' | ') '各科成绩'

from student_score

group by sname;

 

 

猜你喜欢

转载自blog.csdn.net/weixin_42231373/article/details/84583516