系列文章
数据库 —— MySQL 01
数据库 —— MySQL 02
数据库 —— Java操作MySQL
文章目录
四、DQL查询数据
4.1、DQL
Data Query Language 数据查询语言
- 所有的查询操作都用它 select
- 简单的查询、复杂的查询它都能做
- 数据库中最核心的语言,最重要的语句
- 使用频率最高的语句
先复制下面代码执行,方便后面进行数据查询。
-- 测 试 数 据 库
CREATE DATABASE IF NOT EXISTS `school`;
-- 创建一个school数据库
USE `school`;-- 创建学生表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`(
`studentno` INT(4) NOT NULL COMMENT '学号',
`loginpwd` VARCHAR(20) DEFAULT NULL,
`studentname` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
`sex` TINYINT(1) DEFAULT NULL COMMENT '性别,0或1',
`gradeid` INT(11) DEFAULT NULL COMMENT '年级编号',
`phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空',
`address` VARCHAR(255) NOT NULL COMMENT '地址,允许为空',
`borndate` DATETIME DEFAULT NULL COMMENT '出生时间',
`email` VARCHAR (50) NOT NULL COMMENT '邮箱账号允许为空',
`identitycard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`studentno`),
UNIQUE KEY `identitycard`(`identitycard`),
KEY `email` (`email`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8;
-- 创建年级表
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade`(
`gradeid` INT(11) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeid`)
) ENGINE=INNODB AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8;
-- 创建科目表
DROP TABLE IF EXISTS `subject`;
CREATE TABLE `subject`(
`subjectno`INT(11) NOT NULL AUTO_INCREMENT COMMENT '课程编号',
`subjectname` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
`classhour` INT(4) DEFAULT NULL COMMENT '学时',
`gradeid` INT(4) DEFAULT NULL COMMENT '年级编号',
PRIMARY KEY (`subjectno`)
)ENGINE = INNODB AUTO_INCREMENT = 19 DEFAULT CHARSET = utf8;
-- 创建成绩表
DROP TABLE IF EXISTS `result`;
CREATE TABLE `result`(
`studentno` INT(4) NOT NULL COMMENT '学号',
`subjectno` INT(4) NOT NULL COMMENT '课程编号',
`examdate` DATETIME NOT NULL COMMENT '考试日期',
`studentresult` INT (4) NOT NULL COMMENT '考试成绩',
PRIMARY KEY `subjectno` (`studentno`, `subjectno`)
)ENGINE = INNODB DEFAULT CHARSET = utf8;
-- 插入学生数据
INSERT INTO `student` (`studentno`,`loginpwd`,`studentname`,`sex`,`gradeid`,`phone`,`address`,`borndate`,`email`,`identitycard`)
VALUES
(1000,'111111','李华',0,1,'13800001111','北京朝阳','1981-1-11','[email protected]','12345619811111234'),
(1001,'222222','郑爽',1,2,'13800002222',NULL,'1992-2-21','[email protected]','12345619922211233'),
(1002,'333333','华晨宇',0,3,'13800003333','四川达州','1973-3-21','[email protected]','12345619733211233'),
(1003,'444444','张碧晨',1,1,'13800004444','','1984-4-11','[email protected]','12345619844111233');
-- 插入成绩数据
INSERT INTO `result`(`studentno`,`subjectno`,`examdate`,`studentresult`)
VALUES
(1000,1,'2013-11-11 16:00:00',85),
(1000,2,'2013-11-12 16:00:00',70),
(1000,3,'2013-11-11 09:00:00',68),
(1000,4,'2013-11-13 16:00:00',98),
(1000,5,'2013-11-14 16:00:00',58),
(1001,1,'2013-11-11 16:00:00',86),
(1001,2,'2013-11-12 16:00:00',71),
(1001,3,'2013-11-11 09:00:00',69),
(1001,4,'2013-11-13 16:00:00',95),
(1001,5,'2013-11-14 16:00:00',59),
(1002,1,'2013-11-11 16:00:00',55),
(1002,2,'2013-11-12 16:00:00',60),
(1002,3,'2013-11-11 09:00:00',78),
(1002,4,'2013-11-13 16:00:00',58),
(1002,5,'2013-11-14 16:00:00',88),
(1003,1,'2013-11-11 16:00:00',65),
(1003,2,'2013-11-12 16:00:00',50),
(1003,3,'2013-11-11 09:00:00',68),
(1003,4,'2013-11-13 16:00:00',88),
(1003,5,'2013-11-14 16:00:00',78);
-- 插入年级数据
INSERT INTO `grade` (`gradeid`,`gradename`) VALUES(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');
-- 插入科目数据
INSERT INTO `subject`(`subjectno`,`subjectname`,`classhour`,`gradeid`)VALUES
(1,'高等数学-1',110,1),
(2,'高等数学-2',110,2),
(3,'高等数学-3',100,3),
(4,'高等数学-4',130,4),
(5,'C语言-1',110,1),
4.2、查询字段
语法:select 字段1, 字段2 from 表
-- 查询全部学生
SELECT * FROM student;
-- 查询指定字段: 学号、学生姓名
SELECT `studentno`, `studentname` FROM `student`;
-- 指定别名 表中显示的就是别名
SELECT `studentno` AS 学号, `studentname` AS 姓名 FROM `student`;
-- 函数 concat(a, b)
SELECT CONCAT('姓名:', `studentname`) AS 新名字 FROM `student`;
指定别名:将表抬头的字段换成指定的

函数concat():将内容和查询结果拼接起来

DISTINCT:去重复的数据
-- 查询哪些同学参加了考试
--查询考试学生的学号,但一位考生可能参加多门考试,会出现重复学号
SELECT `studentno` FROM result
-- distinct 关键字 去除重复数据
SELECT DISTINCT `studentno` FROM `result`;
SELECT VERSION() --查询系统版本
SELECT 100*4 - 1 AS 计算结果;-- 用来计算
SELECT @@auto_increment_increment;--查询自增的步长是多少
-- 学院考试成绩+1分的结果
SELECT `studentno`,`studentresult` AS 加分后 FROM `result`
4.3、where 条件
搜索的条件由一个或多个表达式组成,结果会返回一个布尔值!
作用:检索数据中符合条件的值。
运算符 | 语法 | 描述 |
---|---|---|
and 或者 && | A and B A && B | 逻辑与,两个都为真,结果为真 |
or 或者 || | A or B A || B | 逻辑或,其中一个为真, 结果为真 |
not 或者 ! | not A ! A | 逻辑非,真为假,假为真 |
-- 查询考试成绩在 95~100分之间的,下面三种效果一样
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult` BETWEEN 95 AND 100;
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult` >= 95 AND `studentresult`<=100;
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult`>= 95 && `studentresult`<=100;
-- 除了1000号学生之外同学的成绩,下面两个效果相同
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentno` != 1000;
SELECT `studentno`,`studentresult` FROM `result`
WHERE NOT `studentno` = 1000;
模糊查询:比较运算符
运算符 | 语法 | 描述 |
---|---|---|
is null | A is null | 如果操作符为null,结果为真 |
is not null | A is not null | 如果操作符不为null,结果为真 |
between | A between B and C | 如果A在B和C之间,结果为真 |
like | A like B | 如果B的内容包含了A,结果为真(例如’A‘,在’BCA’中) |
in | A in (A1, A2, A3…) | 如果A是A1或者A2或者A3…中某个值,结果为真 |
-- 查询姓张的同学:%表示任意个字符,_表示一个字符
SELECT `studentno`,`studentname` FROM `student` WHERE `studentname` LIKE '张%';
-- 查询名字带有华的同学
SELECT `studentno`,`studentname` FROM `student` WHERE `studentname` LIKE '%华%';
-- 查询学号1001,1003的同学
SELECT `studentno`,`studentname` FROM `student` WHERE `studentno` IN(1001,1003);
-- 查询地址为null或者空字符串''的同学
SELECT `studentno`,`studentname` FROM `student` WHERE `address` IS NULL OR `address`='';
4.4、联表查询 join on
前提:表与表之间有公共字段,例如上面创建的student表和result表,它们的studentid字段相同。
联接类型:Inner join 内联接、Outer join 外联接(包括 left join和right join)、Cross join交叉联接。
思路:
-
分析查询的字段来自哪些表,如果不止一张表,则需要联表查询。
-
确定使用哪种联表查询?参考下面的情况,细分为七种,但大题还是三种。
操作 描述 inner join 如果表中至少有一个匹配,则返回行 left join 会从左表中返回所有的值,即使右表没有匹配 right join 会从右表中返回所有的值,即使左表没有匹配
1、inner join
如上面表格描述。这里我们要的是student表的学生学号、学生姓名,以及result表的课程编号、分数。条件是两个表的studentno相同。所以这里返回的结果是student表与result表都有的studentno的字段。
-- 要查询学生学号、姓名、科目编号、分数
-- student表和result表的studentno相同,用别名区分两个表的studentno
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s -- 取别名
INNER JOIN `result` AS r -- 取别名
ON s.`studentno` = r.`studentno` -- 获取两个表的studentno相同的对应行
结果:

2、left join和right join
例如,在student表增加一个新同学,而对于的result表不增加,即新同学没有参加考试。
新同学的student表:

result表:

此时进行left join查询:
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
LEFT JOIN `result` AS r
ON s.`studentno` = r.`studentno`

可以发现,即使左表新同学的id 1004不存在右表(result)中,即条件s.studentno
= r.studentno
不成立,但依然返回了该值。
如果换成right left,则结果不会有新同学,因为右表(result)中没有新同学id。
根据这个结果,我们可以轻松查询缺考同学。
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
LEFT JOIN `result` AS r
ON s.`studentno` = r.`studentno`
WHERE studentresult IS NULL --这里获得成绩为空的人
下面再来一个,查询参加了考试的同学的学号、姓名、科目名、分数。
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult` -- 四个字段
FROM `student` s -- 这里的AS可以省略
RIGHT JOIN `result` r -- 这里将student和result联接,并以result为基准
ON r.`studentno` = s.`studentno` -- student要和result的学号相同
-- 第二次联接
LEFT JOIN `subject` sub -- 把上面的结果和subject联接,并以上面结果为准
ON r.`subjectno` = sub.`subjectno`; -- 上面结果的课程号和subject的课程好相同
第一次联接,因为是参加了考试的同学,因此以result表为基准,这样result表的内容就都会作为结果,用right join。第二次查询因为第一次的结果都会作为最终结果的一部分,而subject表中的课程不一定存在最终结果中,因此以第一次结果为基准,用left join。
是不是从这里感觉left join、right join这些有点复杂,其实大部分时候我们只需要用到inner join就行,下面给出一个完整解决思路!
要求:查出 参加 高等数学-1 同学的学号、姓名、科目名、分数。
-- 1.先根据待查询字段写出select的目标,并判断里面连接这些表的关键字段
-- select studentno,studentname,subjectname,studentresult
-- 关键字段 studentno连接student表和result表,subjectno连接result表和subject表
-- 2.通过inner join将这些表一一联接
-- 3.写where判断条件
select s.studentno,studentname,subjectname,studentresult
from student s
inner join result r
on s.studentno = r.studentno
inner join subject sub
on r.subjectno = sub.subjectno
where sub.subjectname = '高等数学-1';
4.5、自连接
自连接就是将自己和自己连接,其核心就是把一张表拆为两张表!
考虑这样一张表
自身编号 | 父类编号 | 类别名 |
---|---|---|
2 | 1 | 信息技术 |
3 | 1 | 软件开发 |
4 | 3 | 数据库 |
5 | 1 | 美术设计 |
6 | 3 | web开发 |
7 | 5 | ps技术 |
8 | 2 | 办公信息 |
可以将其拆分为父表和子表,父类编号为1表示自身就是顶层。
自身编号 | 父类编号 | 名称 |
---|---|---|
2 | 1 | 信息技术 |
3 | 1 | 软件开发 |
5 | 1 | 美术设计 |
自身编号 | 父类编号 | 名称 |
---|---|---|
4 | 3 | 数据库 |
8 | 2 | 办公信息 |
6 | 3 | web开发 |
7 | 5 | ps技术 |
现在,我们想通过第一张表得到一个整合的表:
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
-- 用两个别名,相当于把总表category拆分成两张表 parent、children
-- 父类表中自身的编号 和 子类表中父类的编号相同
SELECT parent.`名称` AS 父类, children.`名称` AS 子类
FROM category AS parent, category AS children
WHERE parent.`自身编号` = children.`父类编号`
4.5、排序和分页
排序语法:order by 基于的字段 升序/降序
-- 默认升序 ASC,降序DESC
-- 将上面联表查询拿来,对其按成绩降序排序
select s.studentno,studentname,subjectname,studentresult
from student s
inner join result r
on s.studentno = r.studentno
inner join subject sub
on r.subjectno = sub.subjectno
where sub.subjectname = '高等数学-1'
order by studentresult DESC;
分页:
-- ============== 分页 ====================
-- limit 当前数据,页面大小
-- 页面总数 = 数据总数/页面大小
-- 当前页 = (当前数据-1)*页面大小
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
ON s.studentno = r.studentno
INNER JOIN SUBJECT sub
ON r.subjectno = sub.subjectno
LIMIT 0,5; -- 第1页,共有20条,每页5条数据
-- LIMIT 5,5 第2页
-- LIMIT 10,5 第3页
-- LIMIT 15,5 第4页
4.6、嵌套子查询
1、子查询:就是利用select的查询结果,作为where条件的判断值。
-- 查询 高等数学-1 的所有考试结果(学号、课程编号、成绩) 降序排列
-- 方式一:使用联表查询
SELECT `studentno`,r.`subjectno`,`studentresult` --直接写出查询结果
FROM result r --学号和成绩来自result表
INNER JOIN `subject` sub --课程编号来自subject表
ON sub.`subjectno` = r.`subjectno` --result和subject的课程编号相同
WHERE `subjectname` = '高等数学-1' --条件:高等数学-1的结果
ORDER BY `studentresult` DESC
-- 方式二:使用子查询
-- 其实学号、课程编号、成绩都在result表中,但条件高等数学-1在subject表中
-- 所以可以先查出高等数学-1的课程编号,然后再去result表增加条件
SELECT `studentno`,`subjectno`,`studentresult`
FROM result
WHERE subjectno = ( -- 子查询是从里到外
SELECT subjectno FROM `subject`
WHERE subjectname = '高等数学-1'
)
ORDER BY `studentresult` DESC
练习:查询 高等数学-2 前三名同学的成绩信息(学号、姓名、分数)
-- 联表查询
SELECT s.`studentno`,`studentname`,`studentresult`
FROM `student` s
INNER JOIN `result` r
ON s.`studentno` = r.`studentno`
INNER JOIN `subject` sub
ON r.`subjectno` = sub.`subjectno`
WHERE sub.`subjectname` = '高等数学-2'
ORDER BY `studentresult` DESC
LIMIT 0,3;
-- 子查询
SELECT s.`studentno`,`studentname`,`studentresult`
FROM `student` s
INNER JOIN `result` r
ON s.`studentno` = r.`studentno`
WHERE `subjectno` = (
SELECT `subjectno` FROM `subject`
WHERE `subjectname` = '高等数学-2'
)
ORDER BY `studentresult` DESC
LIMIT 0,3;
两种方法结果相同:

4.7、分组和过滤
这里需要先知道select的完整语法,例如where必须在group by上面。
SELECT
[ DISTINCT ] --distinct 去重
待查询字段
FROM 表名
[INNER|LEFT|RIGHT JOIN 表名 ON 条件] -- 联表查询
[WHERE 条件] -- 指定条件,可以是子查询
[GROUP BY 列名] --通过列名分组
[HAVING 分组过滤条件] --过滤分组后的信息,和where一样,只是位置不同
[ORDER BY 列名 [ASC 升序| DESC 降序] ] -- 通过列名排序
[LIMIT 当前数据,页面大小]
-- ==========分组过滤==========
-- 查询不同课程的平均分、最高分、最低分,且只显示平均分大于60的
SELECT `subjectname` AS 课程名, AVG(`studentresult`) AS 平均分,
MAX(`studentresult`) AS 最高分, MIN(`studentresult`) AS 最低分
FROM result r
INNER JOIN `subject` sub
WHERE r.`subjectno` = sub.`subjectno`
GROUP BY r.subjectno
HAVING 平均分
五、MySQL函数
5.1、常用函数
-- ========常用函数===========
-- 数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 随机数
SELECT SIGN(-10) -- 判断数的符号,负数返回-1,整数返回1
-- 字符串
SELECT CHAR_LENGTH('12345') -- 字符串长度
SELECT CONCAT('123','456','789') -- 拼接字符串
SELECT INSERT('1234',1,2,'0') -- 把指定位置替换为新字符串
SELECT LOWER('ABC') -- 小写转大写
SELECT UPPER('abc') -- 大写转小写
SELECT REPLACE('123','1','0') -- 1替换为0
-- 时间重要
SELECT CURRENT_DATE() -- 获取当前日期,也可以直接写CURRENT_DATE
SELECT NOW() -- 当前时间
SELECT LOCALTIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
SELECT YEAR(NOW()) -- 获取年
5.2、聚合函数(重要)
-- ===========聚合函数========
-- count(列名)计算该列有多少行,包括null值
-- count(1)、count(*) 都为统计所有记录数,包括null
-- 执行效率上:当数据量1W+时count(*)用时较少,1w以内count(1)用时较少
-- 总结:若字段为主键则count(主键)效率最高,否则少量数据用count(1),大量用count(*)
SELECT COUNT(`studentname`) FROM `student`;
SELECT COUNT(*) FROM `student`;
SELECT COUNT(1) FROM `student`;
SELECT SUM(`studentresult`) AS 总和 FROM result;
SELECT AVG(`studentresult`) AS 平均分 FROM result;
SELECT MIN(`studentresult`) AS 最小值 FROM result;
SELECT MAX(`studentresult`) AS 最大值 FROM result;
5.3、数据库级MD5加密
在我之前的博客 前端学习 03 —— JavaScript 02 有说如何在前端实现MD5加密,其实我们也可以在数据库中实现加密,MySQL本身带有一个md5()加密函数。
-- ===========测试MD5加密================
DROP TABLE IF EXISTS `testMD5`;
CREATE TABLE IF NOT EXISTS `testMD5`(
`id` INT(4) NOT NULL COMMENT'用户号',
`pwd` VARCHAR(50) NOT NULL COMMENT '密码',
PRIMARY KEY(`id`)
)ENGINE=INNODB CHARSET=utf8;
-- 我们一般在Java中操作插入数据库时就进行加密
INSERT INTO `testMD5`(`id`,`pwd`) VALUES (1234, MD5('1234'));
-- 解密,对于用户输入的密码,也进行MD5加密。
-- 因为同一个密码经过MD5加密后的密文都相同。
-- 因此,将密文于和数据中的密码密文进行配对即可。
SELECT `id`,`pwd` FROM `testMD5` WHERE `pwd` = MD5('1234');
六、事物
6.1、什么是事务
事务原则:ACID原则(原子性、一致性、隔离性、持久性)
参考博客链接:https://blog.csdn.net/dengjili/article/details/82468576
原子性(Atomicity) :要么都成功,要么都失败。
一致性(Consistency) :事务前后的数据完整性要保持一致。
隔离性(Isolation) :多个用户访问数据库时,数据库为每个用户开启的事务相互独立,不能被其他事务 操作干扰。
持久性(Durability) :事务一旦提交则不可逆,会写入数据库中,若未提交而被中断,则会恢复到提交前状态。
一些问题:
- 脏读:一个事务读取了另一个事务还未提交的数据。
- 不可重复读:在一个事务内读取表中的某一行数据,多次读的结果不同。
- 虚读(幻读):在一个事务内读取到其他事务插入的数据,导致前后读取不一致。
6.2、事务的流程
-- ==========事务===============
-- mysql 默认开启事务自动提交
SET autocommit = 0; -- 关闭自动提交
SET autocommit = 1; -- 开启自动提交
-- 手动处理事务的流程!
SET autocommit = 0; -- 关闭自动提交
-- 开启一个事务
START TRANSACTION -- 标记一个事务的开始,从这之后直到提交,都处于一个事务中
-- 执行一些操作,例如插入数据
-- 提交
COMMIT
-- 回滚
ROLLBACK
-- 事务结束
SET autocommit = 1 -- 开启事务提交
-- 下面的了解即可
SAVEPOINT 保存点的名字 -- 设置事务保存点
ROLLBACK TO SAVEPOINT 保存的点的名字 -- 回滚到保存点
RELEASE SAVEPOINT 保存点的名字 -- 释放保存点
6.3、手动模拟转账
下面通过事务手动模拟转账:
-- ==========事务模拟==========
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci;
USE shop
CREATE TABLE `account`(
`id` INT(4) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `account`(`name`,`money`)
VALUES ('小红', 1000), ('小白', 100);
-- 事务:模拟转账
SET autocommit = 0;-- 关闭自动提交
START TRANSACTION -- 开启事务
UPDATE `account` SET `money`=`money`-200 WHERE `name`='小红';
UPDATE `account` SET `money`=`money`+200 WHERE `name`='小白';
COMMIT -- 提交
ROLLBACK -- 回滚
SET autocommit = 1;-- 开启自动提交
在模拟转账中,如果我们执行了两次update后,执行回滚,可以发现表中数据会恢复原来样子,但如果我们提交了之后再回滚,表中数据就不会恢复。
七、索引
7.1、索引分类
-
主键索引(primary key)
- 唯一的标识,主键不可重复,只能有一个列作为主键。
-
唯一索引(unique key)
- 避免重复列出现,唯一索引可以重复,多个列都可以标识唯一索引 。
-
常规索引(key/index)
- 默认的,用index、key关键字来设置
-
全文索引(full text)
- 在特定的数据库引擎下才有,MyISAM
- 快速定位数据
基础语法:
-- 索引的创建:
-- 1. 在创建表的时候给字段增加索引
-- 2. 通过alter增加
-- 显示索引信息
SHOW INDEX FROM school.student;
-- 增加一个全文索引
ALTER TABLE school.student ADD FULLTEXT INDEX `index_studentname`(`studentname`);
-- explain 分析SQL执行的状况 主要关注其中的rows列
EXPLAIN SELECT * FROM school.student;
7.2、测试索引
-- 通过循环函数 插入100百万行数据,这个函数不需要管,直接复制就行。
DROP FUNCTION IF EXISTS mock_data;
DELIMITER $$-- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO `app_user`(`id`,`name`,`email`,`phone`,`gender`)
VALUES(i,CONCAT('用户',i),'[email protected]','123456789',FLOOR(RAND()*2));
SET i=i+1;
END WHILE;
RETURN i;
END;
SELECT mock_data() -- 执行此函数 生成一百万条数据
SELECT * FROM `app_user` WHERE `name`='用户999999'; -- 执行时间 0.358 sec
-- 创建索引 create index 索引名 on 表名(字段名)
ALTER TABLE `app_user` ADD INDEX `id_app_user_name`(`name`);
SELECT * FROM `app_user` WHERE `name`='用户999999'; -- 执行时间 0 sec
7.3、索引原则
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要索引
- 索引一般加在常用来查询的字段
索引的数据结构:https://www.cnblogs.com/sheseido/p/11337074.html
八、权限管理和备份
SQLyog 可视化管理

SQL命令操作
本质上是对 mysql.user表增删改查
-- 创建用户
create user A identified by '密码';
-- 修改当前用户密码
set password = password('新密码');
-- 修改指定用户的密码
set password for 用户名 = password('密码');
-- 重命名
rename user 原用户名 to 新名字
-- 用户全部授权 所有库.所有表(但不包括给其他人授权的权限)
grant all privileges on *.* to 用户名
-- 查询权限
show grants for 用户名
-- 撤销权限 哪些权限 在哪个库.哪个表 给谁撤销
revoke all privileges on *.* from 用户名
-- 删除用户
drop user 用户名;
数据库备份
数据库备份方式:
-
拷贝物理文件 data文件夹
-
在SQLyog这样的可视化工具中手动导出
-
命令行 mysqldump(windows是在cmd里,不需要登录)
mysqldump -h主机 -u用户名 -p密码 数据库 表名 > 物理磁盘位置/文件名
导入,尽量先登录mysql,进入到某个数据库中。
source 文件名
九、规范数据库设计
9.1、为什么需要设计
糟糕的数据库设计:
- 数据冗余,浪费空间
- 数据库插入和删除都会麻烦
- 程序的性能差
良好的数据库设计:
- 节省内存空间
- 保证数据库的完整性
- 方便我们开发系统
软件开发中,关于数据库的设计:
- 分析需求:分析业务和需要处理的数据库需求
- 概要设计:设计E-R图
例如博客数据库设计:B站up 狂神说 视频
9.2、三大范式
更详细内容参考这个博客:https://www.cnblogs.com/wsg25/p/9615100.html
第一范式(1NF):保证每一列都不可再分。
第二范式(2NF):在满足第一范式前提下,每张表都只描述一件事。
第三范式(3NF):满足第二范式前提下,表中每一列数据都和主键直接相关,不能是间接关系。
但是!!三大范式的规范性常常会和数据库性能有冲突!
阿里规定,关联查询的表不得超过三张
- 要考虑到商业化的需求和目标(成本和用户体验),数据库的性能更加重要!
- 有时会故意给某些表增加一些冗余字段。(以便把多表查询变为单表查询)
- 有时会故意增加一些计算列(例如每增加一名用户,count列加1,而不用count()函数,以减少数据量)