MySQL入门操作详解

01-数据库简介

一、数据库相关概念:
1、数据:数据是事物的一种表现符号。
一本书有什么数据?
射雕英雄传
80.2
金庸
2018-10-01
2、数据库:存储数据的仓库。以某种格式将数据存储在硬盘上。
3、RDBMS:relational database management system
关系型数据库管理系统。
用来管理数据库中的数据,让用户对数据进行操作,如查询,添加等。
也可理解为操作数据库的软件。
常见的RDBMS软件有:
MySQL 被Oracle收购了,非常流行,有收费版也有免费版(社区版)
Oracle 较大型的数据库,收费。
SqlServer 微软公司的。

4、数据表:
列:
行:

5、SQL:structure query language
结构化查询语言
用来操作数据库数据的语言。
SELECT 查询
INSERT 添加
UPDATE 修改
DELETE 删除
CREATE 创建
DROP 删除
SQL语句不区分大小写: SELECT , select , SelEct 都一样。推荐用小写。

02-MySQL软件安装

在oracle官网下载mysql软件。

一、安装步骤

1、解压,找到 Setup.exe 安装程序

2、点击下一步:

3、选择Typical典型安装

4、确认安装目录位置,记住。

5、跳过广告

6、开始配置

7、选择Detailed 详细配置

8、配置为开发者数据库服务器

9、选择多功能数据库

10、确认数据表的存储位置,默认在C盘

11、设置多少人连接数据库

12、确认MySQL端口号 3306

13、选择 UTF8 字符集

14、确认服务名称,自动配置环境变量

15、设置密码。允许远程访问。

16、执行配置,当4个步骤都成功时,安装完成。

17、如果未响应,表示安装失败。

18、如果安装失败,在开始菜单中找到MySQL的配置,重新配置

二、测试是否安装成功

1、在任务管理器中找到MySQL服务

2、停止服务,启动服务
3、打开cmd窗口,登录mysql服务器

环境变量有问题,配置一下环境变量。

出现如下窗口,说明mysql安装成功。

正常情况下能看到welcome,登录成功。

03-MySQL命令操作

在cmd窗口中使用命令操作MySQL数据库

(1)、登录

mysql -u帐号 -p密码
mysql -u帐号 -p
mysql -hip -u帐号 -p密码

(2)、退出

quit

(3)、展示所有数据库

show databases;

(4)、创建数据库

create database 名;

(5)、删除数据库

drop database 名;

(6)、使用(打开)数据库

use 名;

(7)、展示数据库中的表

use mysql;
show tables;

(8)、查看表的结构(表有几列,每列存什么数据)

desc 表名; -- 查看表的列数信息

(9)、查看表中所有列的数据

select * from 表名;

(10)、导入sql脚本(一些sql语句组成的文件)。

1、打开test数据库。
2、导入 helloworld.sql 脚本
source F:\yunyouzhong\3-第三个月\sql脚本\helloworld.sql

如果出现 error ,说明脚本导入错误。
需要把导入成功的表删除,set names 'gbk' (设置gbk字符集),再重新导。

(11)、cmd窗口中文乱码问题,设置字符集。

set names 'gbk'

(12)、删除表

drop table 名;

(13)、修改命令分隔符

delimiter 名

04-MySQL数据类型

MySQL数据类型有三大类:

1、字符串类型


最常用的是 varchar ,变长字符串(var是可变的意思)
char与varchar的区别:
char是定长字符串,一旦长度设置为10,数据就不能超出这个长度。
varchar是变长字符串,如果长度设置为10,也可存长度超过10的字符串,它会根据存储的内容自动调整长度。

2、数字类型


常用的整数类型是 int(size) ,size规定最大位数,默认是11位。
常用的小数类型是 double(size,d) ,size规定整数+小数部分的最大位数,d规定小数点后面精确到几位。
例如:double(5,2) 3333.22不能存 0.223不能 30.2能存
double与decimal的区别:
double是双精度浮点型数字。
decimal是用字符串来存储小数,比double更加精准。

3、日期时间类型


date 是常用的日期类型,yyyy-MM-dd
datetime 是常用的日期时间类型,yyyy-MM-dd HH:mm:ss
timestamp 叫时间戳,yyyy-MM-dd HH:mm:ss
time 是时间类型,hh:mm:ss
year 是年份类型,1970-2069
datetime与timestamp的区别:
1、时间范围不同。
2、timestamp 会在添加新记录,或修改记录时,自动记录当前时间。

05-DDL语句

DDL 是 数据定义语言。
是SQL语句中的一种。
create 创建
drop 删除
alter 修改
以上三个关键字都是用来定义表的结构。
1、创建表
语法:
create table 表名(
列名1 数据类型(长度),
列名2 数据类型(长度),
...
);

创建图书表 book, 编号,书名,价格,作者,出版日期。
create table book(
id int(5),
name varchar(20),
price double(8,2),
author varchar(20),
publish_date date
); -- 分号代表sql语句的结束
数据库中的表名或列名或其它名称,多个单词用_连接,不能用驼峰式命名。
因为数据库不区分大小写。
2、删除表:
语法: drop table 表名;
3、修改表:
语法:
alter table 表名 add column 列名 类型(长度); -- 添加列
alter table 表名 drop column 列名; -- 删除列
给book表增加一个类别列(字段)
alter table book add column type varchar(20);
删除book表的type列
alter table book drop column type;

06-insert语句

insert是向表中添加记录的SQL语句 。
insert语句语法有两种:
1、insert into 表名 values (值1,值2,...);
注意:<1>值的个数要和列的个数一样。
<2>每个值要和相应的列类型匹配。
在sql中字符串内容要用单引号包住。
在sql中日期时间类型也要用单引号包住,格式必须正确。

向book表添加一条记录
insert into book values (1,'倚天',90.2,'金庸','2018-10-01');

上面错误是字符集问题,用set names 'gbk'设置后,重新添加。
2、insert into 表名 (列名1,列名2,...) values (值1,值2,...)
给指定几列添加数据。
注意:<1>值的个数要和列的个数一样
<2>值的类型要与该列数据类型匹配
向book表添加一条记录,不管出版日期
insert into book (id,name,price,author) values (2,'天龙',90.3,'查良庸');

07-数据库约束

约束就是一种限制,数据库约束就是对数据库表中的某列数据进行限制。
1、非空约束:此列数据不能空
语法:
create table 表名(
列名1 类型(长度) not null,
列名2 类型(长度) not null,
...
);

创建图书表,id,name两列,name不能为空
create table book(
id int(5),
name varchar(20) not null
);

2、唯一约束:此列数据必须唯一,不能重复
语法:
create table 表名(
列名1 类型(长度) unique,
列名2 类型(长度) unique,
...
);
创建图书表,id,name两列,id和name都必须唯一
create table book(
id int(5) unique,
name varchar(20) unique
);

在数据库中 NULL 值不能比较,如果有一个列有唯一约束,可以添加两个NULL。
**3、**默认约束:此列数据不添加值时,自动分配默认值
语法:
create table 表名(
列名1 类型(长度) default 值,
列名2 类型(长度) default 值,
...
);
创建图书表,id,name两列,id唯一约束,name非空约束,默认值'三国'
create table book(
id int(5) unique,
name varchar(20) not null default '三国'
);

4、主键约束:非空约束+唯一约束
语法:
create table 表名(
列名1 类型(长度) primary key,
列名2 类型(长度) ,
...
);
主键的特点:该列值不能为NULL,且必须唯一。
一般每个表都会创建一个主键。根据主键可以精确查找到一条记录。
主键一般添加在id列上。
一个表只能有一个主键。
创建图书表,id设置为主键约束,name非空。
create table book(
id int(5) primary key,
name varchar(20) not null
);

mysql的主键列可以自增。初始值1,每条记录,主键自动+1。
语法:
create table 表名(
列名1 类型(长度) primary key auto_increment,
列名2 类型(长度) ,
...
);
create table book(
id int(5) primary key auto_increment,
name varchar(20) not null
);

08-select查询语句

select查询语句是sql中使用最多的。

一、查询 所有列****的数据

select * from 表名;

查询学生表所有列的数据
select * from student;

二、查询 指定几列****的数据

select 列名1,列名2,... from 表名;

查询学生表中学生的姓名和性别两列
select sname,ssex from student;

三、带where条件的查询

where是条件查询的关键字
语法: select 语句 where 列名 运算符 值;
select 语句 where 条件1 and 条件2 and 条件3 ...;
select 语句 where 条件1 or 条件2 or 条件3 ... ;
select 语句 where (条件1 and 条件2)or 条件3 ... ;
常用条件示例: where ssex = '男'
where sage = 18
where sid > 1
常用的条件运算符: > , < , >= , <= , = , !=

|---------|----|-----|
| &lt; | < | 小于号 |
| &gt; | > | 大于号 |
| &amp; | & | 和 |
| ' | ' | 单引号 |
| &quot; | " | 双引号 |

查询所有的男生
select * from student where ssex = '男';
查询编号是4的学生
select * from student where sid = 4;
查询年龄大于17的学生
select * from student where sage > 17;
查询年龄小于等于18的学生
select * from student where sage <= 18;
查询年龄不是18岁的学生
select * from student where sage != 18;
where语句多条件
查询18岁的女生记录
select * from student where sage = 18 and ssex = '女';
查询18岁的学生或者性别是女的学生
select * from student where sage = 18 or ssex = '女';
查询18岁的女生或19岁的男生
select * from student where (sage = 18 and ssex = '女') or (sage = 19 and ssex = '男');
where语句中的特殊运算符:
between A and B 意思是在A值与B值之间,包含A,也包含B。
语法: select 语句 where 列名 between 小值 and 大值;
用来进行A到B之间的范围查询。
查询年龄在17-20之间的学生
select * from student where sage between 17 and 20;
等价:
select * from student where sage >= 17 and sage <= 20;
in (值1,值2,值3,...) 意思是等于值1或等于值2,或等于值3,...
in语句是一个不连续的范围查询。
语法: select 语句 where 列名 in (值1,值2,...);
查询年龄是17或19岁的学生记录
select * from student where sage in (17,19);
等价:
select * from student where sage = 17 or sage = 19;
like '值' 意思某一列的值像我们指定的值。
值可以包含两个特殊符号:_ , %
_ 可匹配任意一个字符。如:'a' , '+' , '张' 都能匹配,'' 不能匹配
% 可匹配任意数量的任意字符。如:'张','张三','张三丰','asdfasdfsaf','' 都能匹配
查询姓名是张三的学生
select * from student where sname = '张三';
select * from student where sname like '张三';
如果使用like模糊查询时,值里面没有 _ 或 % ,就相当于 = 查询。

查询姓张的学生记录
select * from student where sname like '张%';

查询姓名中第二个字是三的学生
select * from student where sname like '三%';
查询姓名中倒数第三个字是三的学生
select * from student where sname like '%三
_';
查询姓名中有三的学生记录
select * from student where sname like '%三%';

四、order by 排序语句

order by用来对查询的结果进行排序,两个方向,升序,降序。
语法:
select 语句 order by 列名 asc; -- asc是升序关键字,可省略。
select 语句 order by 列名 desc; -- desc是降序关键字,不能省略。

查询所有学生,按年龄升序排列
select * from student order by sage asc;
select * from student order by sage;
查询所有学生,按年龄降序排列
select * from student order by sage desc;
查询所有的男生,按年龄升序排列
select * from student where ssex = '男' order by sage asc;
注意:order by语句要在where 语句之后

SQL syntax 是sql语法错误。
查询所有学生,先按年龄降序排列,如果年龄相同,再按sid升序排列。
select * from student order by sage desc,sid asc;

09-update修改语句

update语句用来修改记录,只有一种语法:
update 表名 set 列1=值1,列2=值2,... ; --修改掉表中所有记录5
update 表名 set 列1=值2,列2=值2,... where 条件; --修改符合条件的记录

把张三的性别改为女
update student set ssex = '女' where sname = '张三';
把sid是1的记录姓名改成郭靖,年龄改成26,性别改成'未知'
update student set sname = '郭靖',sage=26,ssex='未知' where sid = 1;
把学生表中所有学生的性别改成未知
update student set ssex = '未知';

10-delete删除语句

delete语句用来删除数据库中的记录。
语法:delete from 表名 where 条件;

删除张三的学生记录
delete from student where sname = '张三';
删除19岁的学生记录
delete from student where sage = 19;
删除所有学生(清空学生表)
delete from student;

11-SQL高级

一、NULL值的处理

在sql NULL值不能参与比较,比较的结果都是false。
查询是NULL的数据: is null
查询不是NULL的数据: is not null

-- 查询年龄为NULL的学生
select * from student where sage is NULL;
-- 查询年龄不为NULL的学生
select * from student where sage is not null;
between A and B -> not between A and B
in (17,19,20) -> not in (17,19,20)
like '张%' -> not like '张%'

二、distinct 去重

去重就是去掉重复的记录,只保留一条。
select distinct 列名 from 表名;
-- 查询所有学生的性别
select ssex from student;

-- 查询所有学生的性别
select DISTINCT ssex from student;

三、limit 截取几条记录

limit语句一定要放在sql 语句的最后。
1、 select 语句 limit 5; -- 从查询结果中截取前5条。

取出学生表中的前3条记录
select * from student limit 3;
2、select 语句 limit m,n; -- 从索引为m开始截取,取n条。
m 是第一条的索引位置,索引从0开始
n 是取几条。
从学生表中截取第3到第5条记录
select * from student limit 2,3;
从学生表中截取前5条记录
select * from student limit 0,5;
select * from student limit 5;
limit语句作用是做分页查询。

四、union 合并

union用来把多个select查询的结果合并成一个。
语法: select 语句1 union select 语句2 union select 语句3 ...
注意:1、每个查询结果的列数要一样
2、相应的列数据类型要一致

查询张三的姓名,查询张三的性别,结果合并成一列。
select sname from student where sname = '张三'
union
select ssex from student where sname = '张三';
union 会对合并后的结果自动去重。
-- 查询李四的性别和赵六的性别 ,合并成一列,去重
select ssex from student where sname = '李四'
UNION
select ssex from student where sname = '赵六';

五、union all 合并全部

union all 也是用来合并多个select查询的结果,不会去重。

-- 查询李四的性别和赵六的性别 ,合并成一列,不去重
select ssex from student where sname = '李四'
UNION ALL
select ssex from student where sname = '赵六';

六、sql别名

给表名起别名:
select * from 表名 as 别名; -- as可以省略
select 别名.列名1,别名.列名 from 表名 as 别名;

查询学生表所有记录
select * from student as a;
select * from student a;
select student.sid,student.sname,student.sage,student.ssex from student;
select a.sid,a.sname,a.sage,a.ssex from student a;
给列起别名:
select 列1 as 别名,列2 as 别名,... from 表名; -- as 可以省略
select sname as '姓名',ssex as '性别' from student;
select sname xxx,ssex yyy from student;

12-表连接

一、RDBMS 关系****型数据库管理系统

关系指:表与表之间有关系,数据与数据之间有关系。

关系是靠外键列来维护的。
外键:意思是外来的键,如上图课程表中的 tid 就是外键列,因为课程表的tid的值是从老师表的tid列引用过来的。
外键一般情况下都是引用另一张表的主键列。
外键约束:保证外键列的值必须是从另一个表的主键引用过来的。
外键约束会降低查询性能,也可以不创建外键约束,程序员自己控制数据的安全性。
外键约束会影响删除功能,不能删除被外键引用的记录。

二、联表查询

1、交叉连接
A表的每一条记录都与B表的所有记录连接成新记录。
比如A表有10条记录,B表有5条记录,交叉连接后一共是50条记录。
语法 :
select * from A表 join B表 join C表 join ...;
select * from A表,B表,C表,...;

笛卡尔积:表A与表B交叉连接的结果就是笛卡尔积。
如表A有3条记录,表B有5条,笛卡尔积是15条。
如表A有3条记录,表B有3条,表C有5条,笛卡尔积是45条。
交叉连接的结果没太大意义,因为没有关系的数据被连到了一起。

2、内连接 inner join
A表与B表进行交叉连接,再根据连接条件进行过滤。
语法:
select * from 表A [inner] join 表B on 表A.列 = 表B.列; -- inner可省略
select * from 表A , 表B where 表A.列 = 表B.列;

3、 左****外连接 left outer join**:(最有用)**
A表与B表交叉连接,根据连接条件过滤掉一些记录,再把左表中丢掉的数据找回。
左表的数据一定都留下,不会过滤掉。
语法:
select * from A表 left [outer] join B表 on A表.列 = B表.列;

4、右外连接 right outer join
右外连接与左外连接正好相反,右表的数据不会丢失。

5、全外连接
特点是左右两张表数据都不会丢。
mysql不支持全外连接。

SELECT
*
FROM
student
LEFT JOIN sc ON student.sid = sc.sid
LEFT JOIN course ON sc.cid = course.cid
LEFT JOIN teacher ON course.tid = teacher.tid

13-聚合函数

聚合函数是用来统计的函数:
最大值 : max(列名)
最小值 : min(列名)
平均值 : avg(列名)
总和 : sum(列名)
总数: count(列名)
语法:
select 聚合函数(列名) from 表名;

查询所有学生的平均成绩
select avg(score) from sc;
查询所有学生的最小年龄
select min(sage) from student;
查询张三各科成绩总分
select sum(score) from sc where sid = 3; -- 没有用到姓名张三,有问题
select sum(sc.score) from student left join sc on student.sid = sc.sid
where student.sname = '张三'; -- 根据张三的姓名统计,sql才更准确
count() 函数经常用来查询表中的记录总数
null不会记数。
count(列名)可以统计表中的记录总数,这个列必须是主键列。
select count(score) from sc;
select count(*) from 表名; -- 准确统计表中的记录总数

14-group by分组

group by 列名 可以用来分组:
语法:
select 列名,聚合函数(列名) from 表名 group by 列名;

注意:select后面的列名必须与group by 后面的列名相同。其它列可放在聚合函数中。

统计男生女生人数各多少
select ssex,count(*) from student group by ssex;
统计各年龄学生的人数
select sage,count(*) from student group by sage;

group by 后面可以按多个列分组。

查询男生和女生各年龄段的人数
select ssex,sage,count(*) from student group by ssex,sage;
having 语句对聚合函数加条件过滤
select 列名,聚合函数(列名) from 表名 group by 列名 having 聚合函数 运算符 值;
查询各性别人数多于2人的性别及人数
select ssex,count(*) from student group by ssex having count(*) > 2;
查询各性别人数在2-5人之间的性别及人数
select ssex,count(*) from student group by ssex having count(*) between 2 and 5;
查询各性别各年龄人数多于1人的性别年龄及人数
select ssex,sage,count(*) from student group by ssex,sage having count(*) > 1;
where 与 having的区别:
where是对某个列加条件,having是对聚合函数加条件的。

15-mysql的其它函数

数据库有很多的函数(类似于java中的方法)
1)、字符串函数

concat('字符串','字符串',列名,....) 字符串拼接函数,返回拼接的字符串。

select CONCAT('abc','123','-',567,'张三') result;
select CONCAT(sname,'-',sage) result from student;
(2)、日期时间函数

curdate() 获取当前日期。
select CURDATE();
now() 获取当前的日期时间。
select now();
year( 日期/日期时间 ) 获取年份。
select year('1531-01-01');
select year('1666-01-01 10:00:01');
select year(publish_date) from book;
(3)、流程控制函数

if(表达式1,表达式2,表达式3)
类似于java中的三目运算: 表达式1?表达式2:表达式3
select if(1<2,'yes','no');
select sname,if(sage>=18,'已成年','未成年') from student;
ifnull(表达式1,表达式2) 用来过滤空值(滤空函数)
对表达式1判断是否为空,如果为空,返回表达式2作为结果,如果不为空,返回表达式1.
select ifnull(name,'未知') from book;
case 列名
when 值1 then 结果1
when 值2 then 结果2
......
else 默认结果
end
对某一个列的数据进行判断,如果等于值1,然后返回结果1;如果等于值2,然后返回结果2,...,如果都不等于前面的值,执行else,返回默认结果。end用来结束case。
查询所有学生,男生性别列返回帅哥,女生性别列返回美女,否则返回其它
select sid,sname,sage,
case ssex
when '男' then '帅哥'
when '女' then '美女'
else '未知'
end sex
from student;
(4)****、时间戳函数
获取当前时间戳
select current_timestamp();
时间戳转日期格式
select FROM_UNIXTIME(1429063399,'%Y年%m月%d日')
日期格式转时间戳
select UNIX_TIMESTAMP('2021-11-11')
常用的时间格式

|----|------------------------------|
| %a | 缩写星期名 |
| %b | 缩写月名 |
| %c | 月,数值 |
| %D | 带有英文前缀的月中的天 |
| %d | 月的天,数值(00-31) |
| %e | 月的天,数值(0-31) |
| %f | 微秒 |
| %H | 小时 (00-23) |
| %h | 小时 (01-12) |
| %I | 小时 (01-12) |
| %i | 分钟,数值(00-59) |
| %j | 年的天 (001-366) |
| %k | 小时 (0-23) |
| %l | 小时 (1-12) |
| %M | 月名 |
| %m | 月,数值(00-12) |
| %p | AM 或 PM |
| %r | 时间,12-小时(hh:mm:ss AM 或 PM) |
| %S | 秒(00-59) |
| %s | 秒(00-59) |
| %T | 时间, 24-小时 (hh:mm:ss) |
| %U | 周 (00-53) 星期日是一周的第一天 |
| %u | 周 (00-53) 星期一是一周的第一天 |
| %V | 周 (01-53) 星期日是一周的第一天,与 %X 使用 |
| %v | 周 (01-53) 星期一是一周的第一天,与 %x 使用 |
| %W | 星期名 |
| %w | 周的天 (0=星期日, 6=星期六) |
| %X | 年,其中的星期日是周的第一天,4 位,与 %V 使用 |
| %x | 年,其中的星期一是周的第一天,4 位,与 %v 使用 |
| %Y | 年,4 位 |
| %y | 年,2 位 |

其中 %Y年、%m、%d、%H、%i、%s最为常用
根据日期分组,type:区分

select FROM_UNIXTIME(create_time/1000,'%Y-%m-%d') createTime,count(*) count,1 as 'type' from code_product_repair a GROUP BY create_time
union ALL
select FROM_UNIXTIME(create_time/1000,'%Y-%m-%d') createTime,count(*) count,2 as 'type' from code_product b group by create_time

16-子查询

子查询指一个select语句中又嵌套了一个select语句。
一条查询语句中只能有一个select关键字吗?
不对,子查询语句中有多个select。

一、where型子查询

语法:
select * from 表名 where 列 = (select 语句);

查询张三的考试成绩
分成两步操作:
1、查询张三的sid
SELECT sid FROM student WHERE sname = '张三';
2、根据sid查询sc表中的成绩
SELECT * FROM sc WHERE sid =
(SELECT sid FROM student WHERE sname = '张三');

二、from型子查询

语法:
select * from (select 语句)别名;

查询学生的姓名和年龄
SELECT sname,sage FROM (SELECT * FROM student) a;

三、exists型子查询

exists 是存在的意思。
语法:
select * from A表
where exists (select * from B表 where A表.列 = B表.列);
1、先执行外层查询,查到很多结果
2、把外层结果每一条依次传入内层查询
3、内层查询如果能查到结果,验证成功,外层记录就留下
4、内层查询如果查不到结果,验证失败,外层记录就丢掉

查询最高分大于85的学生信息
select * from student
WHERE EXISTS
(SELECT max(score) FROM sc WHERE sid = student.sid HAVING MAX(score) > 85);
not exists 不存在。与exists正好相反。
如果内层能查到结果,验证失败,外层记录丢掉。
如果内层查不到结果,验证成功,外层记录留下。
查询最高分小于等于85的学生信息
select * from student
WHERE not EXISTS
(SELECT max(score) FROM sc WHERE sid = student.sid HAVING MAX(score) > 85);

17-SQL的执行顺序

7、select
8、distinct
1、from
2、left join
3、on
4、where
5、group by
6、having
9、order by
10、limit
1,2,3步是在准备表,准备数据的源材料。
4,5,6步是在过滤不符合要求的记录。
7,8,9,10步在组织最后的结果集。
复杂的SQL无法直接得到最后的结果集,数据库是需要一步一步,得到很多个虚拟表,不断的接近最后的结果。最后得到准确结果。

18-SQL的分类

DDL(数据定义语言):create , alter , drop
DML(数据操纵语言):select , insert , update , delete
DCL(数据控制语言):控制数据的操作权限 grant (授权) , revoke (收回权限)
TCL(事务控制语言):start transaction 开启事务
commit 提交事务
rollback 回滚事务
事务用来控制多条sql作为一个整体执行,只能全成功,或全失败。

19-索引

1.什么是索引

  • 官方定义: 一种帮助mysql提高查询效率的数据结构
  • 索引的优点:

1\]、大大加快数据查询速度 - 索引的缺点: \[1\]、维护索引需要耗费数据库资源 \[2\]、索引需要占用磁盘空间 \[3\]、当对表的数据进行增删改的时候,因为要维护索引,速度会受到影响 # 2.索引分类 - a.主键索引 设定为主键后数据库会自动建立索引,innodb为聚簇索引 - b.单值索引 即一个索引只包含单个列,一个表可以有多个单列索引 - c.唯一索引 索引列的值必须唯一,但允许有空值 - d.复合索引 即一个索引包含多个列 - e.Full Text 全文索引 (My5.7版本之前 只能由于MYISAM引擎) 全文索引类型为FULLTEXT,在定义索引的列上支持值的全文查找,允许在这些索引列中插入重复值和空值。全文索引可以在CHAR、VARCHAR、 TEXT类型列上创建。MYSQL只有MYISAM存储引擎支持全文索引

(1).主键索引 自动创建
--建表 主键自动创建主键索引
create table t_user(id varchar(20) primary key,name varchar(20));
--查看索引
show index from t_user;

(2).单列索引(普通索引|单值索引)
--建表时创建
create table t_user(id varchar(20) primary key,name varchar(20),key(name));
'注意:随表一起建立的索引索引名同列名一致'
--建表后创建
create index nameindex on t_user(name);
--删除索引
drop index 索引名 on 表名

(3).唯一索引
--建表时创建
create table t_user(id varchar(20) primary key,name varchar(20),unique(name));
--建表后创建
create unique index nameindex on t_user(name);

(4).复合索引
---建表时创建
create table t_user(id varchar(20) primary key,name varchar(20),age int,key(name,age));
--建表后创建
create index nameageindex on t_user(name,age);

4.索引的底层原理

1.思考
---建表
create table t_emp(id int primary key,name varchar(20),age int);
--插入数据
insert into t_emp values(5,'d',22);
insert into t_emp values(6,'d',22);
insert into t_emp values(7,'e',21);
insert into t_emp values(1,'a',23);
insert into t_emp values(2,'b',26);
insert into t_emp values(3,'c',27);
insert into t_emp values(4,'a',32);
insert into t_emp values(8,'f',53);
insert into t_emp values(9,'v',13);
--查询
select * from t_emp;

5.为什么上面数据明明没有按顺序插入,为什么查询时却是有顺序呢?

  • 原因是:mysql底层为主键自动创建索引,一定创建索引会进行排序
  • 也就是mysql底层真正存储是这样的
  • 为什么要排序呢?因为排序之后在查询就相对比较快了 如查询 id=3的我只需要按照顺序找到3就行啦(如果没有排序大海捞针,全靠运气😸!)

6.为了进一步提高效率mysql索引又进行了优化

  • 就是基于页的形式进行管理索引
  • 如 查询id=4的 直接先比较页 先去页目录中找,再去 数据目录中找

7.上面这种索引结构称之为B+树数据结构,那么什么是B+树呢?

  • 参考资料: https://www.cnblogs.com/lianzhilei/p/11250589.html

    B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
    从上一节中的B-Tree结构图中可以看到每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。
    B+Tree相对于B-Tree有几点不同:
  1. 非叶子节点只存储键值信息。
  2. 所有叶子节点之间都有一个链指针。
  3. 数据记录都存放在叶子节点中。
  • InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为〖10〗^3)。也就是说一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。
  • 实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作。

8.聚簇索引和非聚簇索引

  • 聚簇索引: 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据
  • 非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置
    注意:在innodb中,在聚簇索引之上创建的索引称之为辅助索引,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引。辅助索引叶子节点存储的不再是行的物理位置,而是主键值,辅助索引访问数据总是需要二次查找。

    InnoDB中
  • InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。
  • 若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。(重点在于通过其他键需要建立辅助索引)
  • 聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个唯一且非空的索引代替。如果没有这样的索引,InnoDB 会隐式定义一个主键(类似oracle中的RowId)来作为聚簇索引。如果已经设置了主键为聚簇索引又希望再单独设置聚簇索引,必须先删除主键,然后添加我们想要的聚簇索引,最后恢复设置主键即可。

MYISAM

  • MyISAM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

9.使用聚簇索引的优势

  • 问题: 每次使用辅助索引检索都要经过两次B+树查找,看上去聚簇索引的效率明显要低于非聚簇索引,这不是多此一举吗?聚簇索引的优势在哪?
  • (1).由于行数据和聚簇索引的叶子节点存储在一起,同一页中会有多条行数据,访问同一数据页不同行记录时,已经把页加载到了Buffer中(缓存器),再次访问时,会在内存中完成访问,不必访问磁盘。这样主键和行数据是一起被载入内存的,找到叶子节点就可以立刻将行数据返回了,如果按照主键Id来组织数据,获得数据更快。
  • (2).辅助索引的叶子节点,存储主键值,而不是数据的存放地址。好处是当行数据放生变化时,索引树的节点也需要分裂变化;或者是我们需要查找的数据,在上一次IO读写的缓存中没有,需要发生一次新的IO操作时,可以避免对辅助索引的维护工作,只需要维护聚簇索引树就好了。另一个好处是,因为辅助索引存放的是主键值,减少了辅助索引占用的存储空间大小。

10.聚簇索引需要注意什么?

  • 当使用主键为聚簇索引时,主键最好不要使用uuid,因为uuid的值太过离散,不适合排序且可能出线新增加记录的uuid,会插入在索引树中间的位置,导致索引树调整复杂度变大,消耗更多的时间和资源。
  • 建议使用int类型的自增,方便排序并且默认会在索引树的末尾增加主键值,对索引树的结构影响最小。而且,主键值占用的存储空间越大,辅助索引中保存的主键值也会跟着变大,占用存储空间,也会影响到IO操作读取到的数据量。

11. 为什么主键通常建议使用自增id

  • 聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。如果主键不是自增id,那么可以想象,它会干些什么,不断地调整数据的物理地址、分页,当然也有其他一些措施来减少这些操作,但却无法彻底避免。但,如果是自增的,那就简单了,它只需要一页一页地写,索引结构相对紧凑,磁盘碎片少,效率也高。

12. 什么情况下无法利用索引呢?

  • (1). 查询语句中使用LIKE关键字
    在查询语句中使用 LIKE 关键字进行查询时,如果匹配字符串的第一个字符为"%",索引不会被使用。如果"%"不是在第一个位置,索引就会被使用。
  • (2).查询语句中使用多列索引
    多列索引是在表的多个字段上创建一个索引,只有查询条件中使用了这些字段中的第一个字段,索引才会被使用。
  • (3).查询语句中使用OR关键字
    查询语句只有OR关键字时,如果OR前后的两个条件的列都是索引,那么查询中将使用索引。如果OR前后有一个条件的列不是索引,那么查询中将不使用索引。

20-复合主键

主键是一种约束,不能为NULL,且必须唯一。
每个表都应该创建主键,便于准确查询到一条记录。
一个表只能创建一个主键。
复合主键指多个列合起来做主键。

此图中两个钥匙并不是两个主键的意思,而是一个主键,由sid和cid两个列组成。
复合主键中单独的某个列值是可以重复的,复合主键所有列合起来的值不能重复。

上图中 sid 列的值可以重复,有多个1 , cid 列的值也可以重复,有多个1.
sid与cid的组合不能重复, 1-1 不能出现第二遍。

21-冗余

冗(rong)余:是多余的意思。
数据库表设计时,可以把某一列数据在多张表中都进行存储,存储多份,形成了冗余。
一、如果没有冗余,查询时经常需要连表
查询每个学生的姓名及考试各科总成绩
select sname,sum(score) from student a left join sc b
on a.sid = b.sid GROUP BY sname;
二、如果有冗余,查询时就可减少连表操作
下面student表存储了sname,sc表也存储了sname,形成了冗余。

查询每个学生的姓名及考试各科总成绩
select sname,sum(score) from sc group by sname;
冗余的缺点:占用更多的硬盘空间。

22-view视图

view是一张虚拟的表。
view不能存储数据,它的数据来自于select语句,从其它表查出的数据。
创建视图语法:
create view 视图名 as select 语句;

使用student表的sname,sage两列创建视图v_student
create view v_student as select sname,sage from student;
如果修改真实表中的数据,视图中的数据也会改变。
如果修改视图中的数据,真实表中的数据也会改变。
视图也可以简化查询操作,把常用的查询结果固定下来,存储为视图。
查询学生姓名及其各科总成绩
SELECT sname,sum(score) from student a LEFT JOIN sc b on a.sid = b.sid
GROUP BY sname;
使用上面的查询结果创建为视图
CREATE view v_student_score as
SELECT sname,sum(score) from student a LEFT JOIN sc b on a.sid = b.sid
GROUP BY sname;
再查成绩时就直接查询视图
select * from v_student_score;

23-数据库表关系

表关系一共有4种。
1、一对一关系:
A表的一条记录与B表的一条记录有关系。
妻子表 和 丈夫表

一对一关系需要有1个外键(wife_id),外键还需要唯一约束。
外键添加在哪一方都行。
一对一关系不太常见,因为完全可以合成一张表。
2、多对一关系:
A表的多条记录与B表的一条记录有关系。
学生表 和 班级表

多对一关系需要1个外键(class_id)。
外键必须添加在多的一方。
多对一关系很常见:学生对班级,学生对老师,员工对部门,下级对上级,
城市对省份
3、一对多关系:
A表的一条记录与B表的多条记录有关系。
班级表 和 学生表

一对多关系需要1个外键(class_id)。
外键添加在多的一方。
一对多与多对一正好相反,表结构是完全相同的,只是我们所看的角度不同。
4、多对多关系:
A表的一条记录与B表的多条记录有关系。
B表的一条记录与A表的多条记录有关系。
多对多关系需要三张表 A表 , AB中间表 , B表
学生表 和 课程表

菜鸟教程:https://www.runoob.com/mysql/mysql-administration.html

相关推荐
qq_3482318526 分钟前
MySQL 与 PostgreSQL PL/pgSQL 的对比详解
数据库·mysql·postgresql
cui_win1 小时前
Prometheus实战教程 - mysql监控
mysql·prometheus·压测
wsx_iot1 小时前
mysql的快照读和当前读
数据库·mysql
梁萌1 小时前
MySQL分区表使用保姆级教程
数据库·mysql·优化·分区表·分区·partitions
Logic1012 小时前
《数据库运维》 郭文明 实验4 数据库备份与恢复实验核心操作与思路解析
运维·数据库·sql·mysql·学习笔记·形考作业·国家开放大学
hssfscv2 小时前
Mysql学习笔记——多表查询
笔记·学习·mysql
MC皮蛋侠客3 小时前
MySQL数据库迁移脚本及使用说明
数据库·mysql
soft20015253 小时前
《Rocky Linux 9.6 部署 MySQL 8.0 生产手册(含错误处理)》
linux·mysql·adb
帝吃藕和3 小时前
MySQL 知识点复习- 6. inner/right/left join
mysql
你真的可爱呀4 小时前
3.MySQL 数据库集成
mysql·node.js·express