0%

MySQL笔记

mysql学习笔记

mysql笔记


一、常用命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
##登录
mysql -h 主机名 -P 端口号 -u 用户名 -p 密码
##退出
exit或ctrl+C
##查看数据库
show databases;
##进入指定数据库
use database_name;
##查看当前数据库有哪些表
show tables;
##查看某个数据库有哪些表
show tables from database_name;
##查看处于哪个库
select databases();
##创建数据库(test)
create database test;
##创建表(stuinfo)
create table stuinfo(
id int,
name varchar(20)
);
##查看表结构(stuinfo)
desc stuinfo;
##查看数据库服务器版本
select version();
##查看数据库使用的字符集
select variables like '%char%';

二、数据查询语言(DQL)


基础查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
##起别名 使用as 或 空格 (别名有特殊字符需要加双引号)
select id as 编号 from stuinfo;
##去重
select distinct id from stuinfo;
##+号的作用(运算符)
select 100+90; 两个操作数都为数值型,则做加法运算
select '123'+90 只要一方为字符型,试图将字符型数值转换成数值型;
如果转换成功,则做加法运算 (213
select 'john'+90 如果转换失败,则将字符型数值转换成090
select null+90 只要一方为null,则结果肯定为null

##拼接
select concat(last_name,first_name) as 姓名 from stuinfo;
##转义(查询第二个字符为_的学生姓名)
select name from stuinfo where name like '_$_%' escape '$';
>>>其中$可以为任意字符
##查询NULL值(不能使用=)
select * from stuinfo where name is null;
##安全等于(可以判断NULL值,也可以判断普通值)
select * from stuinfo where name <=> NULL;
select * from stuinfo where name <=> 'zzz';
##if null(表达式1,表达式2) 表达式1为需判断的列名 表达式2为判断值为NULL时替换的值
select name,ifnull(age,0) from stuinfo;

字符函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
##length 获取参数值的字节个数
select length('john');
##concat 拼接字符串
select concat(last_name,'_',first_name) from stuinfo;
##upper、lower 大写 小写
select upper('john');
select concat(upper(last_name),lower(first_name)) 姓名 from stuinfo;
##substr 截取指定位置的字符(索引从1开始)
select substr('东方不败dongfangbubai',5); [dongfangbubai]
select substr('东方不败dongfangbubai',1,4); [东方不败]
》》》案例:姓名首字母大写,其他字符小写,并用_拼接,显示出来
select concat(upper(substr(last_name,1,1)),'_',lower(substr(last_name,2))) 姓名 from stuinfo;
##instr 返回字符串在原字符的第一次出现的索引,如果找不到返回0
select instr('楚留香chuliuxiang','xiang') as out_put from stuinfo;
##trim 去掉字符串两端指定的字符 如果不指定为去掉两端空格
select length(trim(' 张无忌 ')); [结果为9;mysql中一个汉字占3个字符]
select trim('a' from 'aaaaaaa张aaa无忌aaaaaaaaa');[结果为张aaa无忌]
##lpad 用指定字符左填充指定长度(超过会截断)
select lpad('张无忌',10,'*'); [结果为*******张无忌]
select lpad('张无忌',2,'*'); [结果为张无]
##rpan 用指定字符右填充指定长度
select rpad('张无忌',10,'ab'); [结果为张无忌abababa]
##replace 字符替换(会替换全部的字符)
select replace('张无忌爱上了周芷若','周芷若','赵敏'); [赵敏替换周芷若]
数学函数
1
2
3
4
5
6
7
8
9
10
11
##round 四舍五入
select round(1.65); [2]
select round(1.234,2); [1.23 小数点后保留两位]
##ceil 向上取整,返回大于等于该参数的最小整数
select ceil(1.02); [2]
##floor 向下取整 返回小于等于该参数的最大整数
select floor(-9.99); [-10]
##truncate 截断(小数点后指定位数)
select truncate(1.69999,1); [1.6]
##mod 取余 (公式:mod(a,b) = a-a/b*b)
select mod(10,3); [1]
日期函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
##now 返回当前系统日期+时间
SELECT NOW(); [2015-08-06 23:12:00]
##curdate 返回当前系统日期,不含时间
SELECT CURDATE();
##CURTIME 返回当前时间,不包含日期
SELECT CURTIME();
##可以获取指定的部分,年year、月month、日day、时hour、分minute、秒second
SELECT YEAR(NOW()) 年;
SELECT YEAR('1998-1-1') 年; [1998]
SELECT MONTHNAME(NOW()) 月; [September]
##str_to_date 将日期格式的字符转换成指定格式的日期
SELECT STR_TO_DATE('9-13-2015','%m-%d-%Y'); [2015-09-13]
##date_format 将日期转换成字符
SELECT DATE_FORMAT('2015/09/22','%Y年%m月%d日'); [2015年09月22日]
##datediff (前-后)
SELECT DATEDIFF('2015-10-2','2015-10-4'); [-2]

>>>格式符:
%Y 四位的年份
%y 2位的年份
%m 月份(01,02,03……)
%c 月份(1,2,3,4……)
%d 日(01,02,03……)
%H 小时(24小时制)
%h 小时(12小时制)
%i 分钟(00,01,02,……59)
%s 秒(00,01,02……59)
》》》案例:查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate = '1992-4-3';
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');
其他函数
1
2
3
4
5
6
7
##查看数据库版本
SELECT VERSION();
##查看当前数据库
SELECT DATABASE();
##查看当前用户
SELECT USER();

流程控制函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
##if函数 if else的效果
SELECT IF(10<5,'大','小'); [小]
##case函数
1、switch case的效果 (等值)
## case 要判断的字段或表达式 when 常量1 then 要显示的值1或语句1;
## when 常量2 then 要显示的值2或语句2;
## else 要显示的值n或语句n;
## end
2、类似于多重if (区间判断)
## case
## when 条件1 then 要显示的值1或语句1
## when 条件2 then 要显示的值2或语句2
## ...
## else 要显示的值n或语句n
## end
》》》案例1:查询员工的工资
如果部门号=30,显示的工资为1.1倍
如果部门号=40,显示的工资为1.2倍
如果部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
SELECT salary 原始工资,department_id,
CASE department_id
WHEN 30 THEN salary*1.1
WHEN 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE salary
END AS 新工资
FROM employees; [表达式之间不能加分号!!!语句之间需要]
》》》案例2:查询出员工的工资情况
如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示C级别
否则,显示D级别
SELECT salary,
CASE
WHEN salary > 20000 THEN 'A'
WHEN salary > 15000 THEN 'B'
WHEN salary > 10000 THEN 'C'
ELSE 'D'
END AS 工资级别
FROM employees;
分组函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
##sum 求和
SELECT SUM(salary) FROM employees;
##avg 平均值
SELECT AVG(salary) FROM employees;
##max 最大值
SELECT MAX(salary) FROM employees;
##min 最小值
SELECT MIN(salary) FROM employees;
##count 计算个数
SELECT COUNT(salary) FROM employees; //salary字段有几个非空值

>>>参数支持哪些类型
SUM 数值型 忽略NULL值 可和distinct搭配使用
AVG 数值型 忽略NULL值 可和distinct搭配使用
MAX 任何类型 忽略NULL值 可和distinct搭配使用
MIN 任何类型 忽略NULL值 可和distinct搭配使用
COUNT 任何类型 忽略NULL值 可和distinct搭配使用
>>>>>COUNT函数详细介绍
SELECT COUNT(*) FROM employees; //总行数
SELECT COUNT(1) FROM employees; //总行数

MYISAM之下 COUNT(*)效率最高
INNODB之下 COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些
##和分组函数一同查询的字段要求是group by后的字段
SELECT AVG(salary),employee_id FROM employees;
分组函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
##添加分组后筛选
SELECT 分组函数,列(要求出现在group by的后面)
FROM 表
WHERE 筛选条件
GROUP BY 分组的列表
ORDER BY 子句
##特点:
1、分组查询中的筛选条件分为两类
数据源 位置 关键字
分组前筛选 原始表 group by子句的前面 where
分组后筛选 分组后的结果集 group by子句的后面 having
>>> a)、分组函数做条件肯定要放在having子句中
b)、能用分组前筛选的,优先考虑分组前筛选
2、group by子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开,没有顺序要求)
也支持表达式或函数(用的较少)
3、可以添加排序(排序放在整个分组查询的最后)

》》》案例:查询哪个部门的员工个数>2
SELECT COUNT(*),department_id FROM employees
GROUP BY department_id Having COUNT(*)>2
按员工姓名长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
SELECT COUNT(*) c, LENGTH(last_name) len_name
FROM employees GROUP BY len_name HAVING c>5;
##按多个字段分组
SELECT AVG(salary),department_id,job_id
FROM employees GROUP BY job_id,department_id;
##添加排序
SELECT AVG(salary),department_id,job_id
FROM employees GROUP BY job_id,department_id
ORDER BY AVG(salary) DESC;

连接查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
##内连接	交集部分
SELECT 查询列表 FROM 表1 别名 INNER JOIN 表2 别名 ON 连接条件;
##外连接
外连接的查询结果为主表中的所有记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果=内连接查询结果+主表中有而从表中没有的记录
全外连接=内连接的结果+表1中有但表2没有的+表2有但表1没有的
##左外连接
left join 左边的是主表
SELECT b.name bo.* FROM beauty b LEFT OUTER JOIN boys bo ON b.boyfriend_id = bo.id;
##右外连接
right join 右边的是主表
SELECT b.name bo.* FROM boys bo RIGHT OUTER JOIN beauty b ON b.boyfriend_id = bo.id;

##交叉连接
两个表做笛卡尔乘积
SELECT b.*,bo.* FROM beauty b CROSS JOIN boys bo;
子查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
##分类
##按子查询出现的位置
SELECT后面 仅仅支持标量子查询
FROM后面 支持表子查询
WHERE或HAVING后面 支持*标量子查询、*列子查询、行子查询(用的较少)
EXISTS后面(相关子查询)表子查询
【标*为重点】
##按结果集的行列数不同
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
行子查询(结果集有一行多列)
表子查询(结果集一般为多行多列)

##特点:子查询放在小括号内
子查询一般放在条件的右侧
标量子查询,一般搭配着单行操作符(> < >= <= = <>)
列子查询,一般搭配这多行操作符(in any/some all)

###多行操作符
IN/NOT IN 等于列表中的任意一个
ANY/SOME (MIN) 和子查询返回的某一个值比较
ALL (MAX) 和子查询返回的所有值比较

##WHERE或HAVING后面
###标量子查询(单行子查询)
1、查询谁的工资比Tom高
SELECT * FROM employees WHERE salary>(SELECT salary FROM employees WHERE last_name = 'Tom');
2、查询job_id和141号员工相同,salary比143号员工多的员工 姓名、job_id和工资
SELECT last_name,job_id,salary FROM employees
WHERE job_id = (SELECT job_id FROM employees WHERE employees_id=141)
AND salary > (SELECT salary FROM employees WHERE employees_id =13);

###列子查询(多行子查询)
1、查询localtion_id是1400或1700的部门中所有员工姓名
SELECT last_name FROM employees WHERE department_id IN(
SELECT DISTINCT department_id FROM departments WHERE location_id IN(1400,1700)
);
2、查询其它工种中比job_id为'IT_PROG'部门任一工资低的员工的员工号、姓名、job_id以及salary
SELECT last_name,employee_id,job_id,salary FROM employees WHERE salary < ANY(
SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG');
或 SELECT last_name,employee_id,job_id,salary FROM employees WHERE salary < (
SELECT DISTINCT MAX(salary) FROM employees WHERE job_id = 'IT_PROG');

###行子查询(多列多行)
查询员工编号最小并且工资最高的员工信息
SELECT * FROM employees WHERE employee_id = (SELECT MIN(employee_id) FROM employees)
AND salary = (SELECT MAX(salary) FROM employees);
或 SELECT * FROM employees WHERE (employee_id,salary) = (
SELECT MIN(employee_id),MAX(salary) FROM employees);

##exists后面(相关子查询)
##exists(完整的查询语句)
##结果:1或0
》》》案例:查询有员工名的部门名
SELECT department_name FROM departments d WHERE EXISTS(
SELECT * FROM employees e WHERE d.department_id = e.department_id);
或 SELECT department_name FROM departments d WHERE d.department_id IN (
SELECT department_id FROM employees);

》》》**案例:查询各部门中工资比本部门平均工资高的员工的员工号,姓名和工资
SELECT employee_id,last_name,salary e.department_id FROM employees e INNER JOIN (
SELECT AVG(salary) ag,department_id FROM employees GROUP BY department_id) ag_dep
ON e.department_id = ag_dep.department_id WHERE salary > ag_dept.ag;
分页查询
1
2
3
4
5
6
7
8
9
10
##limit(offset,size)
##offset:要显示条目的起始索引(起始索引从0开始)
##size:要显示的条目个数

》》》案例1:查询前5条员工信息
SELECT * FROM employees LIMIT(0,5);
案例2:查询第11条——第25条数据
SELECT * FROM employees LIMIT(10,15);
案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT * FROM employees WHERE commission_pct IS NOT NULL ORDER BY salary DESC LIMIT 10;
联合查询
1
2
3
4
5
6
7
8
9
10
11
12
13
##union 将多条查询语句的结果合并成一个结果
##应用场景:要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询信息一致时

##特点:1、多条查询语句的查询列数是一致的
## 2、多条查询语句的查询的每一列的类型和顺序最好一致
## 3、使用UNION关键字默认去重,如果使用UNION ALL可以包含重复项

》》》案例:查询部门编号>90或邮箱包含a的员工信息
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id > 90;

或 SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id > 90;

三、数据操作语言(DML)


插入语句
1
2
3
4
5
6
7
8
9
10
11
12
INSERT INTO 表名 (列名,列名,...) VALUES (值1,值2,...)
INSERT INTO 表名 SET 列名 = 值,列名 = 值,...

##1、插入的值的类型要与列的类型一致或兼容
##2、不可以为NULL的列必须插入值,可以为NULL的列插入值可以为NULL或将列名去掉
##3、列数和值的个数必须一致
##4、可以省略列名,默认所有列,列的顺序和表中列的顺序一致
》》》语句示例:
INSERT INTO stuinfo (id,name,sex,phone) VALUES (12,'唐艺昕','女',NULL);
INSERT INTO stuinfo (id,name,sex) VALUES (12,'唐艺昕','女');

INSERT INTO stuinfo SET id = 19,name = '张飞',phone = '999';
修改语句
1
2
3
4
5
6
7
8
9
10
11
##修改单表记录
UPDATE 表名 SET 列 = 新值, 列 = 新值, ...

##修改多表的记录(级联更新)
UPDATE 表1 别名, INNER|LEFT|RIGHT JOIN 表2 别名,ON 连接条件 SET 列=值,...

》》》语句示例:
UPDATE stuinfo SET phone = '232343242' WHERE name LIKE '唐%';
UPDATE stuinfo SET phone = '232343242',age = 20 WHERE name LIKE '唐%';

UPDATE stuinfo stu INNER JOIN course c ON stu.id = c.id SET stu.phone = '23414' WHERE stu.name = '张无忌';
删除语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
##方式一:
###单表删除
DELETE FROM 表名 WHERE 筛选条件;

###多表删除
DELETE 表1的别名,表2的别名 FROM 表1 别名 INNER|LEFT|RIGHT JOIN 表2 别名 ON 连接条件 WHERE 筛选条件;
##方式二:
###整个表的数据都删除
TRUNCATE TABLE 表名;

##特点:
##1、如果要删除的表中有自增长列
##用DELETE删除后,再插入数据,自增长列的值从断点开始
##用TRUNCATE删除后,再插入数据,自增长列的值从1开始
##2、TRUNCATE删除没有返回值(影响行数),DELETE删除有返回值
##3、TRUNCATE删除不能回滚,DELETE删除可以回滚

》》》语句示例:
DELETE FROM stuinfo WHERE phone LIKE '%9';

DELETE FROM stu FROM stuinfo stu INNER JOIN course c ON stu.id = c.stuid;
WHERE stu.name = '张无忌';

TRUNCATE TABLE stuinfo;

四、数据定义语言(DDL)


库的管理
1
2
3
4
5
6
7
8
9
10
11
## CREATE 创建数据库
CREATE DATEBASE 库名;
CREATE DATEBASE IF NOT EXISTS 库名; (如果库已存在则不创建,如果库不存在则创建)
## ALTER 修改数据库
不建议修改

##可修改库的字符集
ALTER DATEBASE 库名 CHARACTER SET gbk;
## DROP 删除数据库
DROP DATABASE 库名;
DROP DATABASE IF EXISTS 库名; (如果存在则删除)
表的管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
## CREATE 创建表
CREATE TABLE IF NOT EXISTS 表名(
列名 列的类型 【(长度) 约束】,
列名 列的类型 【(长度) 约束】,
列名 列的类型 【(长度) 约束】
...
);

》》》语句示例:
CREATE TABLE books(
id INT,
bName VARCHAR(20),
price DOUBLE,
author VARCHAR(20),
publishDate DATETIME
);
【】代表可选
## ALTER 修改表
##修改列名
ALTER TABLE 表名 CHANGE COLUMN 列名 新列名 类型;

##修改列的类型和约束
ALTER TABLE book MODIFY COLUMN 列名 类型;

##添加新列
ALTER TABLE author ADD COLUMN 列名 类型;

##删除列
ALTER TABLE author DROP COLUMN 列名;

##修改表名
ALTER TABLE 表名 RENAME TO 新表名;

## DROP 删除表
DROP TABLE IF EXISTS 表名;

通用写法:

DROP DATABASE IF EXISTS 旧库名;

CREATE DATABASE 新库名;

​ DROP TABLE IF EXISTS 旧表名;

​ CAEATE TABLE 表名();

表的复制
1
2
3
4
5
6
7
8
9
10
11
12
##仅仅复制表的结构
CREATE TABLE 表名 LIKE 复制源表名;
##复制表的结构和数据
CREATE TABLE 表名 SELECT * FROM 复制源表名;
##复制部分数据
CREATE TABLE 表名 SELECT 列名,列名 FROM 复制源表名 WHERE 条件;
》》》语句示例:
CREATE TABLE copy SELECT id,au_name FROM author WHERE nation = '中国';
##仅仅复制某些字段
CREATE TABLE 表名 SELECT 列名,列名 FROM author WHERE 不满足的条件;
》》》语句示例:
CREATE TABLE copy SELECT id,au_name FROM author WHERE 0;

五、数据类型


数值型:

整型:

整数类型 字节 范围
Tinyint 1 有符号:-128127
无符号:0
255
Smallint 2 有符号:-3276832767
无符号:0
65535
Mediumint 3 有符号:-83886088388607
无符号:0
1677215
Int、Integer 4 有符号:-21474836482147483647
无符号:0
4294967295
Bigint 8 有符号:-92233720368547758089223372036854775807
无符号:0
9223372036854775807*2+1
1
2
3
4
5
6
7
8
9
10
##如何设置有符号和无符号
CREATE TABLE tab_int(
t1 int, 有符号(默认)
t2 int UNSIGNED 无符号
);

##如果插入的数值超出了整型的范围,会报out of range异常,并且插入临界值

##如果不设置长度,int有符号默认长度为11,无符号默认长度为10
##长度代表显示的最大宽度,如果不够会用0在左边填充 但必须搭配zerofill使用

小数:

定点数

定点数类型 字节 范围
DEC(M,D)
DECIMAL(M,D)
M+2 最大取值范围与double相同,给定decimal的有效取值范围由M和D决定

1
2
3
4
5
6
7
8
9
##特点
1、M:整数部位+小数部位
D:小数部位
如果超过范围,则插入临界值

2、M和D都可以省略,DECIMAL默认为10,0
如果是float和double会根据插入的数值的精度来决定精度

3、定点型的精确度较高,如果要求插入数值的精度较高考虑使用定点型

浮点数

浮点数类型 字节 范围
float 4 ±1.75494351E-38~±3.402823466E+38
double 8 ±2.2250738585072014E-308~±1.7976931348623157E+308

字符型:

​ 较短的文本:char、varchar

字符串类型 最多字符数 描述及存储需求
char(M) M可以省略,默认为1 M M为0~255之间的整数
varchar(M) M不可以省略 M M为0~65535之间的整数

​ 较长的文本:text、blob(较长的二进制数据)

1
2
char 		固定长度的字符		比较耗费空间		效率高
varchar 可变长度的字符 比较节省空间 效率低

日期型:

日期和时间类型 字节 最小值 最大值
date 4 1000-01-01 9999-12-31
datetime 8 1000-01-01 00:00:00 9999-12-31 23:59:59
timestamp 4 19700101080001 2038年的某个时刻
time 3 -838:59:59 838:59:59
year 1 1901 2155
1
2
3
##datetime 不受时区影响

##timestamp 受时区影响

六、约束


六大约束
1
2
3
4
5
6
7
8
9
10
11
NOT NULL		非空约束,用于保证该字段的值不能为空

DEFAULT 默认,用于保证该字段有默认值

PRIMARY KEY 主键,用于保证该字段的值具有唯一性,并且非空

UNIQUE 唯一约束,用于保证该字段的值具有唯一性,可以为空

CHECK 检查约束 ##mysql不支持

FOREIGN KEY 外键约束,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
##创建表时添加列级约束
CREATE TABLE stuinfo(
id INT PRIMARY KEY, #主键
stuName VARCHAR(20) NOT NULL, #非空
sex CHAR(1) CHECK(gender = '男' OR gender = '女'), #检查
seat INT UNIQUE, #唯一
age INT DEFAULT 18, #默认约束
majorId INT REFERENCES major(id) #外键
);

CREATE TABLE major(
id INT PRIMARY KEY,
marjorName VARCHAR(20)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
##创建表时添加表级约束
【CONSTRAINT 约束名】 约束类型(字段名)
【】可省略
CREATE TABLE stuinfo(
id INT,
stuName VARCHAR(20),
seat INT,
gender CHAR(1),
age INT,
majorId INT,

CONSTRAINT pk PRIMARY KEY (id), #主键
CONSTRAINT uq UNIQUE(seat), #唯一键
CONSTRAINT ck CHECK(gender), #检查
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorId)REFERENCES major(id) #外键
);
1
2
3
4
5
6
7
8
9
10
##通用的写法
CREATE TABLE IF NOT EXISTS stuinfo(
id INT PRIMARY KEY,
stuname VARCHAR(20) NOT NULL,
sex CHAR(1),
age INT DEFAULT 18,
seat INT UNIQUE,
majorid INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
);
主键和唯一的区别
保证唯一性 是否允许为空 一个表中可以有多少个 是否允许组合
主键 × 至多有1个 √(不推荐)
唯一 可以有多个 √(不推荐)
外键的特点

​ 1、要求在从表设置外键关系

​ 2、从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求

​ 3、主表的关联列必须是一个key(一般是主键或唯一)

​ 4、插入数据时,先插入主表,再插入从表;删除数据时,先删除从表,再删除主表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
##修改表时添加约束
##添加列级约束
ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 新约束;
##添加表级约束
ALTER TABLE 表名 ADD 【CONSTRAINT 约束名】约束类型 (字段名) 【外键的引用】;
【】可省略

##1、添加非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;

##2、添加默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;

##3、添加主键
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
或 ALTER TABLE stuinfo ADD PRIMARY KEY(id);

##4、添加唯一键
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
或 ALTER TABLE stuinfo ADD UNIQUE(seat);

##5、添加外键
ALTER TABLE stuinfo ADD FOREIGN KEY(majorid) REFERENCES major(id);
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id); #添加名字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
##删除表时删除约束


##1、删除非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;

##2、删除默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT;

##3、删除主键
ALTER TABLE stuinfo DROP PRIMARY KEY;

##4、删除唯一键
ALTER TABLE stuinfo DROP INDEX seat;

##5、删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;
标识列

​ 又称自增长列,可以不用手动的插入值,系统提供默认的序列值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
##创建表时设置标识列
CREATE TABLE tab_identity(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30)
);

##修改自增步长
SET auto_increment_increment = 3;


##特点:
##1、标识列不必须和主键搭配,但要求是一个key
##2、一个表中只能有一个标识列
##3、标识列仅支持数值型(int float double)


##修改表时设置标识列
ALTER TABLE tab_indentity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;

##修改表时删除标识列
ALTER TABLE tab_indentity MODIFY COLUMN id INT;

七、事务控制语言(TCL)


事务

​ 一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。

1
2
3
4
5
6
7
8
9
10
##事务的属性

#1、原子性
指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
#2、一致性
事务必须使数据库从一个一致状态切换到另一个一致状态。
#3、隔离性
指一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
#4、持久性
指一个事务一旦被提交,它对数据库的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
##事务的创建
#隐式事务:事务没有明显的开启和结束的标记
比如:insert、update、delete语句

#显式事务:事务具有明显的开启和结束的标记
>>>前提:必须先设置自动提交功能为禁用
SET autocommit = 0; #只对当前事务有效
#步骤1:开启事务
SET autocommit = 0;
start transaction; #可选
#步骤2:编写事务中的sql语句 (select、insert、update、delete)
语句1;
语句2;
...
#步骤3:结束事务
commit; #提交事务
rollback; #回滚事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
##事务的并发问题
#1、脏读
对于两个事务T1,T2,T1读取了已经被T2更新但还没被提交的字段,之后,若T2回滚,T1读取的内容就是临时且无效的
#2、不可重复读
对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段,之后,T1再次读取同一字段,值就不同了。
#3、幻读
对于两个事务T1,T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行,之后,如果T1再次读取同一个表,就会多出几行。

##数据库事务的隔离性
#READ UNCOMMITTED(读未提交数据):允许事务读取未被其他事务提交的变更,会出现脏读、不可重复读、幻读
#READ COMMITED(读已提交数据):只允许事务读取已经被其他事务提交的变更,可以避免脏读,但会出现不可重复读和幻读
#REPEATABLE READ(可重复读):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读,但会出现幻读
#SERIALIZABLE(序列化):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新、删除操作,所有并发问题都可以避免,但性能十分低下

MySql支持4种事务隔离级别,MySql默认的隔离级别为 REPEATABLE READ

ORACLE支持2种事务隔离级别,默认的隔离级别 READ COMMITED
1
2
3
4
5
6
7
8
##查看事务隔离级别
SELECT @@tx_isolation;

##设置事务隔离级别
SET session transaction isolation level 隔离级别;

##设置数据库系统的全局隔离级别
SET GLOBAL transaction isolation level 隔离级别;
1
2
3
##delete和truncate在事务使用时的区别
DELETE支持回滚 (rollback之后数据还在)
TRUNCATE不支持回滚 (rollback之后数据不存在)
1
2
3
4
5
6
7
##savepoint保存点的使用
SET autocommit = 0;
START TRANSACTION;
DELETE FROM account WHERE id = 25;
SAVEPOINT a; #设置保存点
DELETE FROM account WHERE id = 28;
ROLLBACK TO a; #回滚到保存点

八、视图


虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,只保存了sql逻辑,不保存查询结果。

应用场景:

​ 1、多个地方用到同样的查询结果

​ 2、该查询结果使用的sql语句较复杂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
##创建视图
CREATE view 视图名 AS 查询语句;

##视图的好处
1、重用sql;
2、简化复杂的sql操作,不必知道它的查询细节;
3、保护数据,提高安全性

##视图的修改
CREATE OR REPLACE VIEW 视图名 AS 查询语句;
或 ALTER VIEW 视图名 AS 查询语句;

##删除视图
DROP VIEW 视图名,视图名,...;

##查看视图
DESC 视图名;
或 SHOW CREATE VIEW 视图名;


》》》案例:查询姓张的学生名和专业名
SELECT stuname,majorname FROM stuinfo s
INNER JOIN major m ON s.majorid = m.id WHERE s.stuname LIKE '张%';
#创建视图
CREATE VIEW v1
AS SELECT stuname,majorname FROM stuinfo s INNER JOIN major m ON s.majorid = m.id;

##再次查询可直接使用视图
SELECT * FROM v1 WHERE stuname LIKE '张%';

视图的注意点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
##具备以下特点的视图不允许更新

#1、包含以下关键字的sql语句:分组函数、distinct、group by、having、union、union all
#2、常量视图
CREATE OR REPLACE VIEW myv1 AS SELECT 'Tom' NAME;
>>> UPDATE myv1 SET NAME = 'john'; [无法执行]
#3、select中包含子查询
CREATE OR REPLACE VIEW myv1 AS SELECT(SELECT MAX(salary) FROM employees) 最高工资;
>>> UPDATE myv1 SET 最高工资=10000; [无法执行]
#4、join
CREATE OR REPLACE VIEW myv1 AS
SELECT last_name,department_name,FROM employees e
JOIN departments d ON e.department_id = d.department_id;
>>> UPDATE myv1 SET last_name = '张飞' WHERE last_name = '张无忌'; [可以执行]
>>> INSERT INTO myv1 VALUES ('张三丰','dsdsadsadfa'); [无法执行]
#5、from一个不能更新的视图
CREATE OR REPLACE VIEW myv1 AS SELECT * FROM myv3;
>>> UPDATE myv1 SET 最高工资 = 10000 WHERE department_id = 50; [无法执行]
#6、where子句的子查询引用了from子句中的表
CREATE OR REPLACE VIEW myv1
AS SELECT last_name,email,salary FROM employees
WHERE employee_id IN (
SELECT manager_id FROM employees WHERE manager_id IS NOT NULL
);
>>> UPDATE myv1 SET salary = 10000 WHERE last_name = '张无忌'; [无法执行]

视图和表的区别
创建语法关键字 是否实际占用物理空间 使用
视图 create view 没有,只是保存了sql逻辑 增删改查,一般不能增删改,只做查询
create table 占用,保存了数据 增删改查都可以
1
2
##delete和truncate在事务使用时的区别
delete可以回滚 truncate不能回滚

九、变量


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
##系统变量
#变量由系统提供,不是用户定义,属于服务器层面
#系统变量:全局变量、会话变量
#自定义变量:用户变量、局部变量


##查看所有变量
SHOW GLOBAL|【SESSION】 VARIABLES;
##查看满足条件的部分变量
SHOW GLOBAL|【SESSION】 VARIABLES LIKE '%char%';
##查看指定的某个变量的值
SELECT @@GLOBAL|【SESSION】.系统变量名;
##为某个变量赋值
1、 SET GLOBAL|【SESSION】系统变量名 = 值;
2、 SET @@GLOBAL| 【SESSION】.系统变量名 = 值;

>>>如果是全局级别,需要加global,如果是会话级别,需要加session,如果不写,默认为session

>>>全局变量作用域:
服务器每次启动将为所有的全局变量赋初始值,针对于所有的会话(连接)有效,但不能跨重启。【如果需要重启有效需要修改配置文件】

>>>会话变量作用域:
仅仅针对于当前会话(链接)有效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
##自定义变量
#变量是用户自定义的
#使用步骤:声明、赋值、使用(查看、比较、运算等)

#1、声明并初始化 赋值操作符:=或:=
SET @用户变量名 = 值;
SET @用户变量名:= 值;
SELECT @用户变量名:= 值;
#2、赋值(更新用户变量的值)
#方式一:通过SET或SELECT
SET @用户变量名 = 值;
SET @用户变量名:= 值;
SELECT @用户变量名:= 值;
#方式二:通过SELECT INTO
SELECT 字段 INTO @变量名 FROM 表;

#3、使用(查看用户变量的值)
SELECT @用户变量名;

>>>用户变量作用域:
针对于当前会话(连接)有效,同于会话变量的作用域
可以应用在任何地方,也就是begin end里面或begin end外面

#局部变量的使用

#1、声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 DEFAULT 值;

#2、赋值
#方式一:通过SET或SELECT
SET 局部变量名 = 值;
SET 局部变量名:= 值;
SELECT @局部变量名:= 值;
#方式二:通过SELECT INTO
SELECT 字段 INTO 局部变量名 FROM 表;

#3、使用
SELECT 局部变量名;


>>>局部变量作用域:
仅仅在定义它的begin end中有效
应用在begin end中有效
对比用户变量和局部变量
作用域 定义和使用的位置 语法
用户变量 当前会话 会话中的任何地方 必须加@符号,不用限定类型
局部变量 begin end中 只能在begin end中,且为第一句话 一般不用加@符号,需要限定类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
》》》案例:声明两个变量并赋初始值,求和并打印
#用户变量
SET @m=1;
SET @n=2;
SET @sum=@m+@n;

SELECT @sum;

#局部变量
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 2;
DECLARE SUM INT;
SET SUM = m+n;

SELECT SUM; [报错,只能在 begin end 中声明使用]

十、存储过程


存储过程和函数:类似于Java中的方法

好处:

​ 1、提高代码的重用性

​ 2、简化操作

​ 3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率

含义:一组预先编译好的sql语句的集合,理解成批处理语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
##创建语法
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(一组合法的SQL语句)
END;

#注意:
1、参数列表包含三部分
参数模式 参数名 参数类型
》》》举例:
IN stuname VARCHAR(20)
#参数模式:
IN:该参数可以作为输入,也就是该参数需要调用方传入值
OUT:该参数可以作为输出,也就是该参数可以作为返回值
INOUT:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值
2、如果存储过程体仅仅只有一句话, BEGIN END 可以省略
存储过程体中的每条SQL语句的结尾要求必须加分号
存储过程的结尾可以使用 DELIMITER 重新设置
》》》语法;
DELIMITER 结束标记;
例如: DELIMITER $
##调用语法
CALL 存储过程名(实参列表);


##空参列表
》》》案例:插入到admin表中五条记录 (需要在dos窗口)
DELIMITER $
CREATE PROCEDURE myp1 ()
BEGIN
INSERT INTO admin(username,password)
VALUES('Tom','0000'),('john','1111'),('lily','2222'),('york','3333'),('rock','4444');
END $
#调用
CALL myp1()$

##创建带IN模式参数的存储过程
》》》案例1:创建存储过程实现 根据女神名,查询对应的男神信息
CREATE PROCEDURE myp2 (IN beautyName VARCHAR(20))
BEGIN
SELECT bo.* FROM boys bo RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name = beautyName;
END $
#调用
CALL myp2('唐艺昕')$

》》》案例2:创建存储过程实现 用户是否登录成功
CREATE PROCEDURE myp3 (IN userame VARCHAR(20),IN PASSWORD VARCHAR(20))
BEGIN
DECLARE result VARCHAR(20) DEFAULT ''; #声明并初始化
SELECT COUNT(*) INTO result #赋值
FROM admin WHERE admin.username = username AND admin.password = PASSWORD;

SELECT result; #使用
END $
#调用
CALL myp3('张飞','8888')$

##创建带out模式的存储过程
》》》案例1:根据女神名,返回对应的男神名
CREATE PROCEDURE myp5(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
SELECT bo.boyName INTO boyName
FROM boys bo
INNER JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name = beautyName;
END $
#调用
CALL myp5('小昭',@bName)$
SELECT @bName$

》》》案例2:根据女神名,返回对应的男神名和男神魅力值
CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT)
BEGIN
SELECT bo.boyName,bo.userCP INTO boyName, userCP
FROM boys bo
INNER JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name = beautyName;
END $
#调用
CALL myp6('小昭',@bName,@userCP)$

##创建带inout模式参数的存储过程
》》》案例1:传入A和B两个值,最终A和B都翻倍返回
CREATE PROCEDURE myp8(INOUT a INT,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2;
END $
#调用(不能直接调用,需要先创建两个用户变量)
SET @m=10$

SET @n=20$

CALL myp8(@m,@n)$

SELECT @m,@n$
1
2
3
4
5
##存储过程的删除
DROP PROCEDURE 存储过程名;

##查看存储过程的信息
SHOW CREATE PROCEDURE 存储过程名;

十一、函数


含义:一组预先编译好的sql语句的集合,理解成批处理语句

好处:

​ 1、提高代码的重用性

​ 2、简化操作

​ 3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率

和存储过程的区别:

​ 存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新

​ 函数:有且仅有一个返回,适合做处理数据后返回一个结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
##创建语法
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型;
BEGIN
函数体
END

#注意:
1、参数列表包含两部分:
参数名 参数类型

2、函数体:
肯定会有return语句,如果没有会报错
如果return语句没有放在函数体的最后也不报错,但不建议
3、函数体中仅有一句话,则可以省略 BEGIN END
4、使用 delimiter 语句作为设置结束标记

##调用
SELECT 函数名(参数列表)


##无参有返回
》》》案例1:返回公司的员工个数
CREATE FUNCTION myf1() RETURNS INT
BEGIN
DECLARE c INT DEFAULT 0; #定义变量
SELECT COUNT(*) INTO c #赋值
FROM employees;
RETURN c;
END $
#查看
SELECT myf1()$

##有参有返回
》》》案例1:根据员工名。返回他的工资
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
SET @sal=0; #定义用户变量
SELECT salary INTO @sal #赋值
FROM employees
WHERE last_name = empName;
RETURN @sal;
END $
#查看
SELECT myf2('lily') $

》》》案例2:根据部门名,返回该部门的平均工资
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE sal DOUBLE;
SELECT AVG(salary) INTO sal
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = deptName;
RETURN sal;
END $
#查看
SELECT myf3('IT')$


##查看函数
SHOW CREATE FUNCTION myf3;

##删除函数
DROP FUNCTION myf3;

十二、流程控制结构


分支结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
##if函数
实现简单的双分支
#语法:
if(表达式1,表达式2,表达式3)
#执行顺序:
如果表达式1成立,则if函数返回表达式2的值,否则返回表达式3的值

##case结构
情况1:类似于Java中的switch语句,一般用于实现等值判断
情况2:类似于Java中的多重if语句,一般用于实现区间判断

#语法:
情况1: case 变量|表达式|字段
when 要判断的值 then 返回的值1或语句1;
when 要判断的值 then 返回的值2或语句2;
...
else 要返回的值n或语句n;
end case;

情况2: case
when 要判断的条件1 then 返回的值1或语句1;
when 要判断的条件2 then 返回的值2或语句2;
...
else 要返回的值n或语句;
end case;

#特点:
1、可以作为表达式,嵌套在其他语句中使用,可以放在任何地方, BEGIN END 中或 BEGIN END 外面
可以作为独立的语句去使用,只能放在 BEGIN END 中
2、如果 when 中的值满足或条件成立,则执行对应的 then 后面的语句,并且结束 case
如果都不满足,则执行 else 中的语句或值
3、 else 可以省略,如果 else 省略了,并且所有 when 条件下都不满足,则返回 NULL

##if结构
实现多重分支
#语法:
if 条件1 then 语句1;
elseif 条件2 then语句2;
...
【 else 语句n】
end if;
#应用:
只能应用在 begin end 中
循环结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
##分类
while、 loop、 repeat

#循环控制
iterate类似于 continue,继续,结束本次循环,继续下一次
leave类似于 break,跳出,结束当前所在循环

##while
#语法:
【标签:】 while 循环条件 do
循环体;
end while 【标签】;

##loop
#语法
【标签:】 loop
循环体;
end loop 【标签】;

##repeat
#语法:
【标签:】 repeat
循环体;
until 结束循环的条件
end repeat 【标签】;

十三、存储引擎


InnoDB MyISAM
主外键 支持 不支持
事务 支持 不支持
行表锁 行锁,操作时只锁某一行,不对其他行有影响
适合高并发操作
表锁,即使操作一条记录也会锁住整个表
不适合高并发操作
缓存 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 只缓存索引,不缓存真实数据
表空间
关注点 事务 性能
默认安装

十四、索引


1
2
3
4
5
6
7
8
9
10
##性能下降SQL慢,执行时间长,等待时间长

#原因:
1、查询语句写的烂
2、索引失效
【索引分为单值索引和复合索引】
CREATE INDEX idx_user_name on user(name) #索引名一般为 idx_表名_需要建索引的字段名
CREATE INDEX idx_user_nameEmail on user(name,email)
3、关联查询太多 join (设计缺陷或不得已的需求)
4、服务器调优及各个参数设置(缓冲、线程数等)
什么是索引
1
2
3
4
5
6
7
8
9
10
##索引是什么
索引是一种排好序的快速查找数据结构
【索引会影响到 where 后面的筛选条件和 order by 后面的排序】

在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据;
这样就可以在这些数据结构上实现高级查找算法,这种数据结构,就是#索引

索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上


索引的优劣势
1
2
3
4
5
6
7
8
##索引的优劣势
#优势:
1、提高数据检索效率,降低数据库的IO成本
2、降低数据排序的成本,降低CPU的消耗
#劣势:
1、实际上索引也是一张表,保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的
2、虽然索引提高了查询速度,同时会降低更新表的速度,如对表进行增删改,因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
3、索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花大量时间研究建立最优秀的索引,或优化查询
索引分类
1
2
3
4
5
6
7
8
##单值索引
一个索引只包含单个列,一个表可以有多个单列索引 #建议一个表索引最多不超过5个

##唯一索引
索引列的值必须唯一,但允许有空值

##复合索引
一个索引包含多个列
哪些情况需要建立索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
##哪些情况需要建立索引
1、主键自动建立唯一索引
2、频繁作为查询条件的字段应该创建索引
3、查询中与其它表关联的字段,外键关系建立索引
4、查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度 #不仅要考虑查的快,还要考虑是否和order by排序诉求撞车
5、查询中统计或分组字段

##不要建立索引
1、频繁更新的字段不适合建立索引 #因为每次更新不仅更新记录还会更新索引
2、 where 条件里用不到的字段不创建索引
3、单键/组合索引的选择问题 #高并发条件下倾向创建组合索引
4、表记录太少 #300W左右
5、经常增删改的表
6、数据重复且分布平均的表字段
#假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建立索引一般不会提高数据库的查询速度
#索引的选择性是指索引列中不同值的数目与表中记录数的比,如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99。
#一个索引的选择性越接近于1,这个索引的效率就越高
性能分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
##explain属性

#1、id:select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
1、id相同,执行顺序由上至下
2、id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

#2、select_type:查询的类型,主要用于区别普通查询,联合查询,子查询等的复杂查询
#simple:简单的select查询,查询中不包含子查询或者union
#primary:查询中若包含任何复杂的子部分,最外层查询则被标记为primary
#subquery:在select或where列表中包含了子查询
#derived:在from列表中包含的子查询被标记为derived(衍生)MySQL会递归执行这些子查询,把结果放在临时表里
#union:若第二个select出现在union之后。则被标记为union,若union包含在from子句的子查询中,外层的select将被标记为derived
#union result:从union表获取结果的select