MySQL简介
一 MySQL和SQL语句介绍
数据库是一种按照数据结构来组织、存储和管理数据的仓库;是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。
关于数据库的工作,主要分为两种:OLTP和OLAP。
OLTP(online transaction processing)翻译为联机事务处理,主要是对数据库进行增删改查。
OLAP(On-Line Analytical Processing)翻译为联机分析处理,组要是对从数据库查询到的数据进行统计分析从中获取我们想要的信息。
SQL:结构化查询语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。
SQL语言分为:
- DQL
Data Query Language - 数据查询语言;
select :从一个或者多个表中检索特定的记录; - DML
Data Manipulate Language - 数据操作语言;
insert :插入记录;
update :更新记录;
delete :删除记录; - DDL
Data Define Languge - 数据定义语言;
create :创建一个新的表、表的视图、或者在数据库中的对象;
alter :修改现有的数据库对象,例如修改表的属性或者字段;
drop :删除表、数据库对象或者视图; - DCL
Data Control Language - 数据控制语言;
grant :授予用户权限;
revoke :收回用户权限; - TCL
Transaction Control Language - 事务控制语言;
commit :事务提交;
rollback :事务回滚;
数据库引擎是表级别的引擎。
二 MySQL体系结构
MySQL体系结构图如下图所示:
MySQL的组成部分分别是:连接池组件、管理服务和工具组件、SQL接口组件、查询分析器组件、优化器组件、缓冲组件、插件式存储引擎、物理文件。
下面介绍每个组件的用处:
- 连接池
管理缓冲用户连接、用户名、密码、权限校验、线程处理等需要缓存的需求;
网络处理流程:主线程接收连接,接收连接交由连接池处理;
主要处理方式:IO多路复用select + 阻塞的io;
需要理解:MySQL命令处理是并发处理的;
以下是MySQL连接池的网络模型:
主线程负责接收客户端连接,然后为每个客户端fd分配一个连接线程,负责处理该客户端的sql命令处理;其中连接线程的read是阻塞的,因为MySQL主要负责和磁盘进行交互,是重IO操作。 - 管理服务和工具组件
系统管理和控制工具,例如备份恢复、Mysql复制、集群等; - SQL接口
将SQL语句解析生成相应对象;DML,DDL,存储过程,视图,触发器等; - 查询解析器
将SQL对象交由解析器验证和解析,并生成语法树; - 查询优化器
SQL语句执行前使用查询优化器进行优化; - 缓冲组件
是一块内存区域,用来弥补磁盘速度较慢对数据库性能的影响;在数据库进行读取页操作,首先将从磁盘读到的页存放在缓冲池中,下一次再读相同的页时,首先判断该页是否在缓冲池中,若在缓冲池命中,直接读取;否则读取磁盘中的页,说明该页被LRU淘汰了;缓冲池中LRU采用最近最少使用算法来进行管理;
缓冲池缓存的数据类型有:索引页、数据页、以及与存储引擎缓存相关的数据(比如innodb引擎:undo页、插入缓冲、自适应hash索引、innodb相关锁信息、数据字典信息等);
三 数据库三范式和反范式
数据库范式就相当于数据库设计领域中的设计模式,是为了设计合理的数据库所遵循的一定的规则。
- 范式一:
确保每列保持原子性;数据库表中的所有字段都是不可分解的原子值; - 范式二:
确保表中的每列都和主键相关,而不能只与主键的某一部分相关(组合索引); - 范式三:
确保每列都和主键直接相关,而不是间接相关;减少数据冗余;
反范式:
范式可以避免数据冗余,减少数据库的空间和维护数据完整性的麻烦;但是采用数据库范式化设计,可能导致数据库业务涉及的表变多,并且造成更多的联表查询,将导致整个系统的性能降低;因此处于性能考虑,可以适当的违反一下三范式设计原则。
四 CRUD
CRUD的执行过程如图所示:
五 SQL语句介绍
- 创建数据库
CREATE DATABASE '数据库名' DEFAULT CHARACTER SET utf8;
- 删除数据库
DROP DATABASE '数据库名';
- 选择数据库
USE '数据库名'
- 创建表
CREATE TABLE 'table_name' (column_name column_tyjpe);
...
CREATE TABLE IF NOT EXISTS 'runoob_tbl' (
'id' INT UNSIGNED AUTO_INCREMENT COMMENT '编号',
'course' VARCHAR(100) NOT NULL COMMENT '课程',
'teacher' VARCHAR(40) NOT NULL COMMENT '价格',
'price' DECIMAL(8,2) NOT NULL COMMENT '价格‘,
PRIMARY KEY ('id')
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT = '课程表';
- 删除表
DROP TABLE 'table_nanme';
- 清空数据表
TRUNCATE TABLE 'table_name'; --截断表 以页为单位(至少有两行数据),有自增索引的话,从初始值开始增加
DELETE TABLE 'table_name'; --逐行删除,有自增索引的话,从之前值继续累加
- 增
INSERT INTO 'table_name' ('field1','field2',...,'fieldn') VALUES (value1,value2,...,valuen);
INSERT INTO 'Ovoice_tbl' ('course','teacher','price') VALUES ('C/C++Linux服务器开发/高级架构师’, ‘Mark’, 7580.0);
- 删
DELETE FROM 'table_name' [WHERE Clause];
DELETE FROM 'Ovoice_tbl' WHERE id = 3;
- 改
UPDATE table_name SET field1=new_value1,field2=new_value2 [, fieldn=new_valuen];
UPDATE '0voice_tbl' SET 'teacher' = 'Mark' WHERE id = 2;
UPDATE '0voice_tbl' SET 'age' = 'age' + 1 WHERE id = 2;
- 查
SELECT field1,field2,...fieldN FROM table_name [WHERE Clause]
查询是使用MySQL的重点,第五部分会详细讲解SQL查询。
五 SQL高级查询详解
先来一道面试题:面试题: 为什么innodb 建议主动创建主键索引,并且以自增的整数作为主键 ?
- 基础查询
SELECT * FROM student; -- 全部查询
SELECT ‘sname', 'class_id' FROM student; -- 只查询部分字段
SELECT 'sname' AS '姓名', 'class_id' AS '班级ID' FROM student; -- 别名用法
SELECT DISTINCT ’class_id' FROM student; -- 把查询出来的结果的重复记录去掉
- 条件查询
SELECT * FROM 'student' WHERE 'name' = '邓洋洋‘; -- 查询姓名为邓洋洋的学生信息
SELECT * FROM ’student‘ WHERE ‘gender' = '男’ AND 'class_id' = 2; --查询性别为男,并且班级为2的学生的信息
- 范围查询
SELECT * FROM 'student' WHERE 'class_id' BETWEEN 1 AND 3; -- 查询班级id1到3的学生的信息
- 判空查询
# is null 判断造成索引失效
# 索引 B+ 树
SELECT * FROM 'student' WHERE 'class_id' IS NOT NULL; -- 判断不为空
SELECT * FROM ‘student’ WHERE ’class_id' is NULL; -- 判断为空
SELECT * FROM ‘student’ WHERE ‘gender’ <> ''; -- 判断不为空字符串
SELECT * FROM 'student' WHERE 'gender' = ''; -- 判断为空字符串
- 模糊查询
-- 使用like关键字,"%"代表任意数量的字符,“_"代表占位符
-- 查询名字为m开头的老师的信息
SELECT * FROM 'teacher' WHERE 'tname' LIKE '谢%';
-- 查询姓名里第二个字为小的老师的信息
SELECT * FROM 'teacher' WHERE 'tname' LIKE '_小%';
- 分页查询
-- 分页查询主要用于查看第N条到第M条的信息。通常和排序查询一起用
-- 使用limit关键字,第一个参数表示从几条记录开始显示,第二个参数表示要显示的数目。表中默认第一条记录的参数为0
-- 查询第二条到第三条内容
SELECT * FROM 'student' LIMIT 1,2;
- 查询后排序
-- 关键字:order by field,asc:升序, desc:将序
SELECT * FROM 'score' ORDER BY 'num' ASC;
-- 按照多个字段排序
SELECT * FROM 'score' ORDER BY 'course_id' DESC, 'num' DESC;
- 聚合查询
-- 通过聚合函数进行查询
SELECT sum('num') FROM 'score';
SELECT avg('num') FROM 'score';
- 分组查询
-- 分组加group_concat
SELECT 'gender', group_concat('age') as ages FROM 'student' GROUP BY 'gender';
-- 可以把查询出来的结果根据某个条件来分组显示
SELECT 'gender' FROM 'student' GROUP BY 'gender';
-- 分组加聚合
SELECT ‘gender', count(*) as num FROM 'student' GROUP BY 'gender';
-- 分组加条件
SELECT ’gender', count(*) as num FROM 'student' GROUP BY 'gender' HAVING num;
- 联表查询
两张表的关系如下图所示:
- INNER JOIN
只取两张表有对应关系的记录
SELECT
cid
FROM
'course'
INNER JOIN 'teacher' ON course.teacher_id = teacher.tid;
- LEFT JOIN
在内连接的基础上保留左表没有对应关系的记录
SELECT
course.cid
FROM
'course'
LEFT JOIN 'teacher' ON course.teacher_id = teacher.tid;
- RIGHT JOIN
在内连接的基础上保留右表没有对应关系的记录
SELECT
course.cid
FROM
'course'
RIGHT JOIN 'teacher' ON course.teacher_id = teacher.tid;
单行子查询
当一个查询是另一个查询的条件时,这个查询被称为子查询。
SELECT * FROM 'course' where teacher_id = (SELECT 'tid' FROM 'teacher' WHERE 'tname' = '谢小二老师')
多行子查询
多行子查询,即返回多行记录的子查询
SELECT * FROM 'student' WHERE 'class_id' IN (SELECT 'cid' FROM 'course' WHERE 'teacher_id' = 2);
SELECT * FROM 'student' WHERE EXISTS (SELECT 'cid' FROM 'course' WHERE 'cid' = 5);
SELECT
'student_id',
'sname'
FROM
(SELECT * FROM score WHERE 'course_id' = 1 OR course_id = 2) AS A LEFT JOIN 'student' ON A.student_id = student.sid;
试图
试图(view)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。其内容由查询定义。
基表是用来创建视图的表。
视图总是显示最新的数据。每当用户查询视图时,数据库引擎通过使用视图的 SQL 语句重建数据。
试图的优点:
- 简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。
- 安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。
- 数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。
- 可复用,减少重复语句的书写,类似程序中函数的作用;
- 重构利器
CREATE VIEW <试图名> AS <SELECT 语句>
-- 创建视图
-- 查询"C++高级"课程比"音视频"课程成绩高的所有学生的学号;
CREATE VIEW view_test1 AS SELECT
A.student_id
FROM
(
SELECT
student_id,
num
FROM
score
WHERE
course_id = 1
) AS A -- 12
LEFT JOIN (
SELECT
student_id,
num
FROM
score
WHERE
course_id = 2
) AS B -- 11
ON A.student_id = B.student_id
WHERE
A.num >
IF (isnull(B.num), 0, B.num);
流程控制
- IF
IF condition THEN
...
ELSEIF condition THEN
...
ELSE
...
END IF
- CASE
-- 相当于switch语句
CASE value
WHEN value THEN ...
WHEN value THEN ...
ELSE ...
END CASE
- WHILE
WHILE condition DO
...
END WHILE;
-------------------------
-- LEAVE语句退出循环或程序块,只能和BEGIN ... END,LOOP,REPEAT,WHILE语句配合使用
-- 创建存储过程
DELIMITER //
CREATE PROCEDURE example_leave(OUT sum INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE s INT DEFAULT 0;
while_label:WHILE i<=100 DO
SET s = s+i;
SET i = i+1;
IF i=50 THEN
-- 退出WHILE循环
LEAVE while_label;
END IF;
END WHILE;
SET sum = s;
END
//
DELIMITER;
-- 调用存储过程
CALL example_leave(@sum);
SELECT @sum;
- LEAVE
-- 相当于break
LEAVE label;
- ITERATE
-- 相当于continue
ITERATE label
- LOOP
-- 相当于while(true) {...}
LOOP
...
END LOOP
-- 可以通过LEAVE语句退出循环
--------------------
-- 创建存储过程
DELIMITER //
CREATE PROCEDURE example_loop(OUT sum INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE s INT DEFAULT 0;
loop_label:LOOP
SET s = s+i;
SET i = i+1;
IF i>100 THEN
-- 退出LOOP循环
LEAVE loop_label;
END IF;
END LOOP;
SET sum = s;
END
//
DELIMITER ;
-- 调用存储过程
CALL example_loop(@sum);
SELECT @sum;
- REPEAT
-- 相当于do .. while(condition)
REPEAT
...
UNTIL condition
END REPEAT
--------------------------
DELIMITER //
CREATE PROCEDURE example_repeat(OUT sum INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE s INT DEFAULT 0;
REPEAT
SET s = s+i;
SET i = i+1;
UNTIL i > 100
END REPEAT;
SET sum = s;
END
//
DELIMITER ;
-- 调用存储过程
CALL example_repeat(@sum);
SELECT @sum;
触发器
触发器(trigger)是MySQL提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行DML操作( insert , delete , update )时就会激活它执行。
触发器四要素:
- 监视对象:table
- 监视事件:insert、update、delete
- 触发时间:before、after
- 触发事件:insert、update、delete
语法:
CREATE TRIGGER trigger_name
trigger_time trigger_event
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body -- 此处写执行语句
-- trigger_body:可以写一个语句,也可以是多个语句:多个语句写在BEGIN ... END间
-- trigger_time:{BEFORE | AFTER}
-- trigger_event:{INSERT | UPDATE | DELETE}
-- trigger_order:{FOLLOWS | PRECEDES} other_trigger_name
存储过程
SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中
的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。
语法:
CREATE PROCEDURE 过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型...]]) [特性...] 过程体
存储过程根据需要可能会有输入、输出、输入输出参数,如果有多个参数用","分割开。
MySQL 存储过程的参数用在存储过程的定义,共有三种参数类型 IN , OUT , INOUT 。
IN :参数的值必须在调用存储过程时指定,0在存储过程中修改该参数的值不能被返回,可以设
置默认值
OUT :该值可在存储过程内部被改变,并可返回
INOUT :调用时指定,并且可被改变和返回
过程体的开始与结束使用 BEGIN 与 END 进行标识。
游标
游标相当于迭代器。
游标是针对行操作的,对从数据库中 select 查询得到的结果集的每一行可以进行分开的独立的相同或者不相同的操作。对于取出多行数据集,需要针对每行操作;可以使用游标;游标常用于存储过程、函数、触发器、事件;
语法:
-- 定义游标
DECLARE cursor_name CURSOR FOR select_statement;
-- 打开游标
OPEN cursor_name;
-- 取游标数据
FETCH cursor_name INTO var_name[,var_name,......];
-- 关闭游标
CLOSE curso_name;
-- 释放
DEALLOCATE cursor_name;
-- 设置游标结束标志
DECLARE done INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET done = 1; -- done为标记
权限管理
创建用户的语法:
CREATE USER username@host IDENTIFIED BY password; -- 入果是本地用户,host可以使用localhost
授权:
GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
privileges :用户的操作权限,如SELECT , INSERT , UPDATE 等,如果要授予所的权限则使
用ALL;
databasename.tablename 如果是 . 表示任意数据库以及任意表;
WITH GRANT OPTION 这个选项表示该用户可以将自己拥有的权限授权给别人。注意:经常有人在
创建操作用户的时候不指定 WITH GRANT OPTION 选项导致后来该用户不能使用 GRANT 命令创建
用户或者给其它用户授权。
如果不想这个用户有这个 grant 的权限,则不要加该 WITH GRANT OPTION 选项;