子查询也被称作内查询或者嵌套查询,是指在一个查询语句里面还嵌套着另一个查询语 句。子查询语句是先于主查询语句被执行的,其结果作为外层的条件返回给主查询进行下一 步的查询过滤。
PS: 子语句可以与主语句所查询的表相同,也可以是不同表
相
select name,score from info where id in (select id from info where score >80);
以上同表示例:
主语句:select name,score from info where id
子语句(集合): select id from info where score >80
PS:子语句中的sql语句是为了,最后过滤出一个结果集,用于主语句的判断条件
⭐⭐ in: 将主表和子表关联/连接的语法
不同表/多表示例:
mysql> create table ky30(id int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into ky30 values(1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
#多表查询
mysql> select id,name,score from ky29 where id in (select * from ky30);
+------+--------+-------+
| id | name | score |
+------+--------+-------+
| 1 | liuyi | 80.00 |
| 2 | wangwu | 90.00 |
| 3 | lisi | 60.00 |
+------+--------+-------+
3 rows in set (0.00 sec)
子查询不仅可以在 SELECT 语句中使用,在 INERT、UPDATE、DELETE 中也同样适用。在嵌套的时候,子查询内部还可以再次嵌套新的子查询,也就是说可以多层嵌套。
(1)语法
IN 用来判断某个值是否在给定的结果集中,通常结合子查询来使用
语法:
<表达式> [NOT] IN <子查询>
当表达式与子查询返回的结果集中的某个值相等时,返回 TRUE,否则返回 FALSE。 若启用了 NOT 关键字,则返回值相反。需要注意的是,子查询只能返回一列数据,如果需 求比较复杂,一列解决不了问题,可以使用多层嵌套的方式来应对。 多数情况下,子查询都是与 SELECT 语句一起使用的
查询分数大于80的记录
mysql> select name,score from info where id in (select id from info where score>80);
+----------+-------+
| name | score |
+----------+-------+
| wangwu | 90.00 |
| tianqi | 99.00 |
| jiaoshou | 98.00 |
| lilei | 11.00 |
+----------+-------+
4 rows in set (0.01 sec)
将t1里的记录全部删除,重新插入info表的记录
mysql> insert into t1 select * from info where id in (select id from info);
Query OK, 7 rows affected (0.00 sec)
Records: 7 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+----+-----------+-------+----------+-------+
| id | name | score | address | hobbid |
+----+-----------+-------+----------+-------+
| 1 | shidapeng | 90.00 | nanjing | NULL |
| 2 | shangzhen | 80.00 | beijing | NULL |
| 3 | tangyan | 98.00 | shanghai | NULL |
| 6 | chengu | 88.00 | nanjing | NULL |
| 7 | caicai | 70.00 | hangzhou | NULL |
| 8 | zhaokun | 80.00 | hangzhou | NULL |
| 9 | xiawenjie | 80.00 | hangzhou | NULL |
+----+-----------+-------+----------+-------+
7 rows in set (0.00 sec)
将caicai的分数改为50
mysql> update info1 set score=50 where id in (select * from ky30 where id=2);
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from info;
+------+-----------+-------+------------+--------+
| id | name | score | address | hobbid |
+------+-----------+-------+------------+--------+
| 1 | liuyi | 80.00 | beijing | 2 |
| 2 | wangwu | 50.00 | shengzheng | 2 |
| 3 | lisi | 60.00 | shanghai | 4 |
| 4 | tianqi | 99.00 | hangzhou | 5 |
| 5 | jiaoshou | 98.00 | laowo | 3 |
| 6 | hanmeimei | 10.00 | nanjing | 3 |
| 5 | lilei | 11.00 | nanjing | 5 |
+------+-----------+-------+------------+--------+
7 rows in set (0.00 sec)
update info set score=100 where id not in (select * from member where id >1);
表示 先匹配出member表内的id字段为基础匹配的结果集(2,3)
然后再执行主语句,以主语句的id 为基础 进行where 条件判断/过滤
删除分数大于80的记录
mysql> delete from info where id in (select id where score>80);
Query OK, 3 rows affected (0.00 sec)
mysql> select id,name,score from t1;
+----+-----------+-------+
| id | name | score |
+----+-----------+-------+
| 2 | shangzhen | 80.00 |
| 7 | caicai | 50.00 |
| 8 | zhaokun | 80.00 |
| 9 | xiawenjie | 80.00 |
+----+-----------+-------+
4 rows in set (0.00 sec)
删除分数不是大于等于80的记录
mysql> delete from t1 where id not in (select id where score>=80);
Query OK, 1 row affected (0.00 sec)
mysql> select id,name,score from t1;
+----+-----------+-------+
| id | name | score |
+----+-----------+-------+
| 2 | shangzhen | 80.00 |
| 8 | zhaokun | 80.00 |
| 9 | xiawenjie | 80.00 |
+----+-----------+-------+
3 rows in set (0.00 sec)
EXISTS 这个关键字在子查询时,主要用于判断子查询的结果集是否为空。如果不为空, 则返回 TRUE;反之,则返回 FALSE
查询如果存在分数等于80的记录则计算info的字段数
mysql> select count() from info where exists(select id from info where score=80);
学校里面 (人员信息统计,只有当所有人全部签到之后,在人员信息统计表录入完成侯,我才需要进行统计)
±---------+
| count() |
±---------+
| 7 |
±---------+
1 row in set (0.00 sec)
查询如果存在分数小于50的记录则计算info的字段数,info表没有小于50的,所以返回0
mysql> select count() from info where exists(select id from info where score<50);
±---------+
| count() |
±---------+
| 0 |
±---------+
1 row in set (0.00 sec)
子查询,别名as
#查询info表id,name 字段
select id,name from info;
以上命令可以查看到info表的内容
#将结果集做为一张表进行查询的时候,我们也需要用到别名,示例:
需求:从info表中的id和name字段的内容做为"内容" 输出id的部分
mysql> select id from (select id,name from info);
ERROR 1248 (42000): Every derived table must have its own alias
#此时会报错,原因为:
select * from 表名 此为标准格式,而以上的查询语句,“表名"的位置其实是一个完整结果集,mysql并不能直接识别,而此时给与结果集设置一个别名,以”select a.id from a“的方式查询将此结果集视为一张"表”,就可以正常查询数据了,如下:
select a.id from (select id,name from info) a;
相当于
select info.id,name from info;
select 表.字段,字段 from 表;
#############MySQL视图#############
视图:优化操作+安全方案 ⭐⭐
数据库中的虚拟表,这张虚拟表中不包含真实数据,只是做了真实数据的映射
视图可以理解为镜花水月/倒影,动态保存结果集(数据)
基础表info (7行记录) ——》映射(投影)–视图
作用场景[图]:
针对不同的人(权限身份),提供不同结果集的“表”(以表格的形式展示)
作用范围:
select * from info; #展示的部分是info表
select * from view_name; #展示的一张或多张表
功能:
简化查询结果集、灵活查询、可以针对不同用户呈现不同结果集、相对有更高的安全性
本质而言视图是一种select(结果集的呈现)
PS:视图适合于多表连接浏览时使用!不适合增、删、改
而存储过程适合于使用较频繁的SQL语句,这样可以提高执行效率!
##视图和表的区别和联系
#区别:
①、视图是已经编译好的sql语句。而表不是
②、视图没有实际的物理记录。而表有。
show table status\G
③、表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能有创建的语句来修改
④、视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图可以不给用户接触数据表,从而不知道表结构。
⑤、表属于全局模式中的表,是实表;视图属于局部模式的表,是虚表。
⑥、视图的建立和删除只影响视图本身,不影响对应的基本表。(但是更新视图数据,是会影响到基本表的)
#联系:
视图(view)是在基本表之上建立的表,它的结构(即所定义的列)和内容(即所有数据行)都来自基本表,它依据基本表存在而存在。一个视图可以对应一个基本表,也可以对应多个基本表。视图是基本表的抽象和在逻辑意义上建立的新关系。
示例:
需求:满足80分的学生展示在视图中
PS:这个结果会动态变化,同时可以给不同的人群(例如权限范围)展示不同的视图
mysql> create view v_score as select * from t1 where score>=80;
Query OK, 0 rows affected (0.01 sec)
#查看视图
mysql> select * from v_score;
+------+-----------+--------+----------+--------+
| id | name | score | address | hobbid |
+------+-----------+--------+----------+--------+
| 1 | liuyi | 100.00 | beijing | 2 |
| 4 | tianqi | 100.00 | hangzhou | 5 |
| 5 | jiaoshou | 100.00 | laowo | 3 |
| 6 | hanmeimei | 100.00 | nanjing | 3 |
| 7 | lilei | 100.00 | nanjing | 5 |
+------+-----------+--------+----------+--------+
#查看视图与源表结构
mysql> desc v_score;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(10) | NO | | NULL | |
| score | decimal(5,2) | YES | | NULL | |
| address | varchar(20) | YES | | NULL | |
| hobbid | int(5) | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
mysql> desc ky29;
+---------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(10) | NO | PRI | NULL | |
| score | decimal(5,2) | YES | | NULL | |
| address | varchar(20) | YES | | NULL | |
| hobbid | int(5) | YES | | NULL | |
+---------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
创建test01表
create table test01 (id int,name varchar(10),age char(10));
insert into test01 values(1,'zhangsan',20);
insert into test01 values(2,'lisi',30);
insert into test01 values(3,'wangwu',29);
需求:需要创建一个视图,需要输出id、学生姓名、分数以及年龄
mysql> create view v_info(id,name,score,age) as select info.id,info.name,info.score,test01.age from info,test01 where info.name=test01.name;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from v_info;
+------+--------+-------+------+
| id | name | score | age |
+------+--------+-------+------+
| 3 | lisi | 80.00 | 30 |
+------+--------+-------+------+
2 rows in set (0.00 sec)
mysql> update info set score='60' where name='liuyi';
Query OK, 1 row affected (1.62 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from v_score;
+------+-----------+--------+----------+--------+
| id | name | score | address | hobbid |
+------+-----------+--------+----------+--------+
| 4 | tianqi | 100.00 | hangzhou | 5 |
| 5 | jiaoshou | 100.00 | laowo | 3 |
| 6 | hanmeimei | 100.00 | nanjing | 3 |
| 7 | lilei | 100.00 | nanjing | 5 |
+------+-----------+--------+----------+--------+
4 rows in set (0.00 sec)
mysql> update v_score set score='120' where name='tianqi';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from v_score;
+------+-----------+--------+----------+--------+
| id | name | score | address | hobbid |
+------+-----------+--------+----------+--------+
| 4 | tianqi | 120.00 | hangzhou | 5 |
| 5 | jiaoshou | 100.00 | laowo | 3 |
| 6 | hanmeimei | 100.00 | nanjing | 3 |
| 7 | lilei | 100.00 | nanjing | 5 |
+------+-----------+--------+----------+--------+
4 rows in set (0.00 sec)
mysql> select * from info;
+------+-----------+--------+------------+--------+
| id | name | score | address | hobbid |
+------+-----------+--------+------------+--------+
| 1 | liuyi | 60.00 | beijing | 2 |
| 2 | wangwu | 50.00 | shengzheng | 2 |
| 3 | lisi | 50.00 | shanghai | 4 |
| 4 | tianqi | 120.00 | hangzhou | 5 |
| 5 | jiaoshou | 100.00 | laowo | 3 |
| 6 | hanmeimei | 100.00 | nanjing | 3 |
| 7 | lilei | 100.00 | nanjing | 5 |
+------+-----------+--------+------------+--------+
7 rows in set (0.00 sec)
修改表不能修改以函数、复合函数方式计算出来的字段
查询方便、安全性
查询方便:索引速度快、同时可以多表查询更为迅速(视图不保存真实数据,视图本质类似select)
安全性:我们实现登陆的账户是root ——》所拥有权限 ,视图无法显示完整的约束
6、NULL 值
在 SQL 语句使用过程中,经常会碰到 NULL 这几个字符。通常使用 NULL 来表示缺失 的值,也就是在表中该字段是没有值的。如果在创建表时,限制某些字段不为空,则可以使用 NOT NULL 关键字,不使用则默认可以为空。在向表内插入记录或者更新记录时,如果该字段没有 NOT NULL 并且没有值,这时候新记录的该字段将被保存为 NULL。需要注意 的是,NULL 值与数字 0 或者空白(spaces)的字段是不同的,值为 NULL 的字段是没有 值的。在 SQL 语句中,使用 IS NULL 可以判断表内的某个字段是不是 NULL 值,相反的用 IS NOT NULL 可以判断不是 NULL 值。
查询info表结构,name字段是不允许空值的
⭐
null值与空值的区别(空气与真空)
空值长度为0,不占空间,NULL值的长度为null,占用空间
is null无法判断空值
空值使用"=“或者”<>"来处理(!=)
count()计算时,NULL会忽略,空值会加入计算
mysql> desc info;
±--------±-------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±--------±-------------±-----±----±--------±---------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | NO | UNI | NULL | |
| score | decimal(5,2) | YES | | NULL | |
| address | varchar(50) | YES | | 未知 | |
| hobbid | int(3) | YES | | NULL | |
±--------±-------------±-----±----±--------±---------------+
5 rows in set (0.00 sec)
插入一条记录,分数字段输入null,显示出来就是null
#验证:
alter table info add column addr varchar(50);
update info set addr=‘nj’ where score >=70;
#统计数量:检测null是否会加入统计中
select count(addr) from info;
#将info表中其中一条数据修改为空值’’
update info set addr=‘’ where name=‘wangwu’;
#统计数量,检测空值是不会被添加到统计中
select count(addr) from info;
#查询null值
mysql> select * from info where addr is NULL;
+------+-----------+-------+---------+--------+------+
| id | name | score | address | hobbid | addr |
+------+-----------+-------+---------+--------+------+
| 6 | hanmeimei | 10.00 | nanjing | 3 | NULL |
| 7 | lilei | 11.00 | nanjing | 5 | NULL |
+------+-----------+-------+---------+--------+------+
2 rows in set (0.00 sec)
#查询不为空的值
<mysql> select * from info where addr is not null;
+------+----------+-------+------------+--------+------+
| id | name | score | address | hobbid | addr |
+------+----------+-------+------------+--------+------+
| 1 | liuyi | 80.00 | beijing | 2 | nj |
| 2 | wangwu | 90.00 | shengzheng | 2 | nj |
| 3 | lisi | 60.00 | shanghai | 4 | |
| 4 | tianqi | 99.00 | hangzhou | 5 | nj |
| 5 | jiaoshou | 98.00 | laowo | 3 | nj |
| 1 | xiaoer | 80.00 | hangzhou | 3 | nj |
+------+----------+-------+------------+--------+------+
6 rows in set (0.00 sec)
MySQL 的连接查询,通常都是将来自两个或多个表的记录行结合起来,基于这些表之间的 共同字段,进行数据的拼接。首先,要确定一个主表作为结果集,然后将其他表的行有选择 性的连接到选定的主表结果集上。使用较多的连接查询包括:内连接、左连接和右连接
模板:
create table test1 (
a_id int(11) default null,
a_name varchar(32) default null,
a_level int(11) default null);
create table test2 (
b_id int(11) default null,
b_name varchar(32) default null,
b_level int(11) default null);
insert into test1 values (1,'aaaa',10);
insert into test1 values (2,'bbbb',20);
insert into test1 values (3,'cccc',30);
insert into test1 values (4,'dddd',40);
insert into test2 values (2,'bbbb',20);
insert into test2 values (3,'cccc',30);
insert into test2 values (5,'eeee',50);
insert into test2 values (6,'ffff',60);
MySQL 中的内连接就是两张或多张表中同时符合某种条件的数据记录的组合。通常在 FROM 子句中使用关键字 INNER JOIN 来连接多张表,并使用 ON 子句设置连接条件,内连接是系统默认的表连接,所以在 FROM 子句后可以省略 INNER 关键字,只使用 关键字 JOIN。同时有多个表时,也可以连续使用 INNER JOIN 来实现多表的内连接,不过为了更好的性能,建议最好不要超过三个表
(1)语法
SELECT column_name(s)FROM table1 INNER JOIN table2 ON table1.column_name = table2.column_name;
模板表:
create table infos(name varchar(40),score decimal(4,2),address varchar(40));
insert into infos values('wangwu',80,'beijing'),('zhangsan',99,'shanghai'),('lisi',100,'nanjing');
mysql> select * from infos;
+----------+-------+----------+
| name | score | address |
+----------+-------+----------+
| wangwu | 80.00 | beijing |
| zhangsan | 99.00 | shanghai |
| lisi | 99.99 | nanjing |
+----------+-------+----------+
mysql> select info.id,info.name from info inner join infos on info.name=infos.name;
+------+--------+
| id | name |
+------+--------+
| 2 | wangwu |
| 3 | lisi |
+------+--------+
2 rows in set (0.00 sec)
内连查询:通过inner join 的方式将两张表指定的相同字段的记录行输出出来
内连查询:面试,直接了当的说 用inner join 就可以
左连接也可以被称为左外连接,在 FROM 子句中使用 LEFT JOIN 或者 LEFT OUTER JOIN 关键字来表示。左连接以左侧表为基础表,接收左表的所有行,并用这些行与右侧参 考表中的记录进行匹配,也就是说匹配左表中的所有行以及右表中符合条件的行。
mysql> select * from info left join infos on info.name=infos.name;
+------+-----------+--------+------------+--------+------+--------+-------+---------+
| id | name | score | address | hobbid | addr | name | score | address |
+------+-----------+--------+------------+--------+------+--------+-------+---------+
| 2 | wangwu | 50.00 | shengzheng | 2 | nj | wangwu | 80.00 | beijing |
| 3 | lisi | 50.00 | shanghai | 4 | nj | lisi | 99.99 | nanjing |
| 1 | liuyi | 60.00 | beijing | 2 | nj | NULL | NULL | NULL |
| 4 | tianqi | 100.00 | hangzhou | 5 | | NULL | NULL | NULL |
| 5 | jiaoshou | 100.00 | laowo | 3 | NULL | NULL | NULL | NULL |
| 6 | hanmeimei | 100.00 | nanjing | 3 | NULL | NULL | NULL | NULL |
| 7 | lilei | 100.00 | nanjing | 5 | NULL | NULL | NULL | NULL |
| 7 | lilei | 100.00 | nanjing | 5 | NULL | NULL | NULL | NULL |
| 8 | abn | 81.00 | bj | 1 | nj | NULL | NULL | NULL |
+------+-----------+--------+------------+--------+------+--------+-------+---------+
左连接中左表的记录将会全部表示出来,而右表只会显示符合搜索条件的记录,右表记录不足的地方均为 NULL。
右连接也被称为右外连接,在 FROM 子句中使用 RIGHT JOIN 或者 RIGHT OUTER JOIN 关键字来表示。右连接跟左连接正好相反,它是以右表为基础表,用于接收右表中的所有行,并用这些记录与左表中的行进行匹配
mysql> select * from info right join infos on info.name=infos.name;
+------+--------+-------+------------+--------+------+----------+-------+----------+
| id | name | score | address | hobbid | addr | name | score | address |
+------+--------+-------+------------+--------+------+----------+-------+----------+
| 2 | wangwu | 50.00 | shengzheng | 2 | nj | wangwu | 80.00 | beijing |
| NULL | NULL | NULL | NULL | NULL | NULL | zhangsan | 99.00 | shanghai |
| 3 | lisi | 50.00 | shanghai | 4 | nj | lisi | 99.99 | nanjing |
+------+--------+-------+------------+--------+------+----------+-------+----------+
3 rows in set (0.00 sec)
在右连接的查询结果集中,除了符合匹配规则的行外,还包括右表中有但是左表中不匹 配的行,这些记录在左表中以 NULL 补足
涉及到面试
1.select、order by 和limit的一个集合
mysql数据库如何查一张表;(select语法)
查ky29表中的id,name(指定字段的查询)
查ky29表中score大于90 select 配合where条件过滤的查询
查询ky29表中前4行的记录 select配合limit查询
ky29表中第四行记录后的两行记录select配合limit指定以下的多行内容
ky29表怎么查看最后三行记录 select结合order by {asc|desc}之后的limit查询
2.内连接、左连接、右连接
内连接:linner join
左连接: left join
右连接:right join
3.子查询(多表查询)
2表关联查询条件,写一个子查询sql
select id,name from ky29 where name in (select name from infos);
1、了解存储过程
2、存储过程控制结构以及应用场景
3、存储过程的特点
4、了解存储过程的语法
5、存储过程案例(证明语法结构)
6、如何调用和查看存储过程
7、存储过程输入输出参数有哪些
8.修改删除存储过程
1.概述
前面学习的 MysQL相关知识都是针对一个表或几个表的单条sgL语句,使用这样的SQL
语句虽然可以完成用户的需求,但在实际的数据库应用中,有些数据库操作可能会非常复杂,可能会需要多条SQL语句一起去处理才能够完成,这时候就可以使用存储过程,轻松而高效的去完成这个需求,有点类似shell脚本里的函数
2.简介
1、存储过程是一组为了完成特定功能的SQL语句。两个点 第一触发器(定时任务) 第二判断
2.存储过程这个功能是从5.0版本才开始支持的,它可以加快数据库的处理速度,增强数据库在实际应用中的灵活性。存储过程在使用过程中是将常用或者复杂的工作预先使用SQL语句写好并用一个指定的名称存储起来,这个过程经过编译和优化后存储在数据库服务器中。当需要使用该存储过程时,只需要调用它即可
语句在执行时需要先编译,然后再去执行,跟存储过程一对比,明显存储过程在执行上速度更快,效率更高
开发人员 访问select 如果访问过多100万 触发存储过程
存储过程在数据库中L创建并保存,它不仅仅是sql语句的集合,还可以加入一些特殊的控制结构,也可以控制数据的访问方式。存储过程的应用范围很广,例如封装特定的功能、在不同的应用程序或平台上执行相同的函数等等。
3.存储过程的优点
(1)执行一次后,会将生成的二进制代码驻留缓冲区,提高执行效率
( 2) sQL语句加上控制语句的集合,灵活性高
( 3)在服务器端存储,客户端调用时,降低网络负载
(4)可多次重复被调用,可随时修改,不影响客户端调用
(5)可完成所有的数据库操作,也可控制数据库的信息访问权限
创建存储过程
delimiter $$
create procedure proc()
begin
create table mk (id int(10),name char(10),score int(10));
insert into mk values(1,'gao',13);
select * from mk;
end $$
delimiter ;
in输入参数:表示调用者向过程传入值(传入值可以是字面量或变量)
out输出参数:表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)
inout输入输出参数:即表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)
即表示调用者向过程传入值,又表示过程向调用者传出值(只能是变量)
删除存储过程
drop procedure if exists proc;
成熟的业务通常数据量都比较大
单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求
配置多台从数据库服务器以实现读写分离
二、主从复制原理
2.1MySQL的复制类型
基于语句的复制statement,MySQL默认类型
基于行的复制(row)
混合类型的复制(mixed)
2.2MySQL主从复制的工作过程
主-从进行复制
为什么复制?保证数据完整性
谁复制谁?salve角色复制master角色的数据
数据放在哪?二进制日志文件中mysql-bin.00000x–>记录完整sql,salve复制二进制日志到本节点,保存为中继日志文件方式
最后基于这个中继日志,进行’恢复‘操作,将执行的sql同步执行在自己数据库内部,最终达到与master数据一致性
MySQL主从复制过程
master二进制日志文件
slave中继日志
i/o线程
两日志、三线程
(1)在每个事务更新数据完成之前,Master在二进制日志(Binary log)记录这些改变。写入二进制日志完成后,Master通知存储引擎提交事务。
(2) Slave将Master的复制到其中继日志(Relay log)。首先slave开始一个工作线程(I0),I/O线程在Master 上打开一个普通的连接,然后开始Binlog dump process。Binlog dump process 从Master的二进制日志中读取事件,如果已经跟上Master,它会睡眠并等待Master产生新的事件,IO线程将这些事件写入中继日志。
(3)SQl slave thread(SQL从线程)处理该过程的最后一步,SQL线程从中继日志读取事件,并重放其中的事件而更新Slave数据,使其与Master中的数据一致,只要该线程与I/O线程保持一致,中继日志通常会位于OS缓存中,所以中继日志的开销很小。
复制过程有一个很重要的限制,即复制在Slave上是串行化的,也就是说Master上的并行更新操作不能在Slave上并行操作。
总结:主从复制简化
主从复制核心部分就是两个日志三个线程(高版本的mysql以及异步复制、半同步复制、全同步复制三种模式)
主从复制原理
两个日志:1.二进制日志
2.中继日志
三个线程:master dump线程和salved的I/O线程、SQL线程如何工作以达成一致
主要原理:master将数据保存在二进制日志中,I/O像dump发出同步请求,dump把数据发送给I/O线程,I/O写入本地的中继日志,SQL线程读取本地中继日志数据,同步到自己数据库中,完成同步
主从复制延迟
1.maste服务器高并发,形成大量事务
2.网络延迟
3.主从硬件设备导致
4.本来就不是同步复制、而是异步复制
从库优化Mysql参数。比如增大innodb_buffer_pool_size,让更多操作在Mysql内存中完成,减少磁盘操作。从库使用高性能主机。包括cpu强悍、内存加大。避免使用虚拟云主机,使用物理主机,这样提升了ilo方面性。从库使用SSD磁盘
问题解决方法
半同步复制-解决数据丢失的问题
并行复制—解决从库复制延迟的问题
MySQl有几种同步方式
1.异步复制(Async Replication)
2.同步复制(sync Replication)
3.半同步复制(Async Replication)
4.增强半同步复制(lossless Semi-Sync Replication)、无损复制
异步复制(Async Replication)
主库将更新写入Binlog日志文件后,不需要等待数据更新是否已经复制到从库中,就可以继续处理更多的请求。Master将事件写入binlog,但并不知道Slave是否或何时已经接收且已处理。在异步复制的机制的情况下,如果Master宕机,事务在Master上已提交,但很可能这些事务没有传到任何的Slave上。假设有Master->Salve故障转移的机制,此时Slave也可能会丢失事务。MySQL复制默认是异步复制,异步复制提供了最佳性能。
同步复制(sync Replication)
主库将更新写入Binlog日志文件后,需要等待数据更新已经复制到从库中,并且已经在从库执行成功,然后才能返回继续处理其它的请求。同步复制提供了最佳安全性,保证数据安全,数据不会丢失,但对性能有一定的影响.
半同步复制(Async Replication)
主库提交更新写入二进制日志文件后,等待数据更新写入了从服务器中继日志中,然后才能再继续处理其它请求.该功能确保至少有1个从库接收完主库传递过来的binlog内容已经写入到自己的relay log里面了,才会通知主库上面的等待线程,该操作完毕。