MySQL核心点笔记

条件查询

-- 1、关系运算符:> < >= <= = <> (也可以用!=,是一种宽容处理,不建议)
select count(last_name),last_name,first_name FROM employees WHERE salary<>20000    -- 聚集函数只能显示一行
-- 2、按逻辑表达式筛选:and or
-- 3、范围表达式:between and,not between and
-- 4、确定集合:in,not in
-- 5、字符匹配:like,not like
-- 6、空值:is null ,is not null

select last_name,first_name,manager_id FROM employees limit 0,3

select last_name,first_name FROM employees WHERE commission_pct is NULL

嵌套查询

-- 1、in

不相关子查询:子查询不依赖父级参数

select * from student where sdep in(select * from sdept)

-- 2、单一关系子查询,即子查询只会返回一条记录

相关子查询:子查询依赖父级参数

select sno,sname,grade 
from sc x
where grade >= (
    select AVG(grade) from sc y 
    where x.sno = y.sno 
)

-- 3、(any、all)多关系子查询,即子查询会返回多条记录

相关的关系函数格式:>any、>all、=any、>=all、<=any、<=all、=any、=all、<>any、<>all

select sname,sage 
from student 
where sdept

-- 4、exists子查询:存在返回true,反之false,比如select *,只要有一条记录就返回true

select sname 
from student 
where exists(
    select * 
    from sc 
    where sno = student.sno and cno = '1'
)

集合查询

-- 1、union:并集

select * from student where sdept = 'cs'
union
select * from student where sage <= 19

-- 2、intersect:交集

select * from student where sdept = 'cs'
intersect
select * from student where sage <= 19

-- 3、except:差集,如下获取院系为cs的19岁以上学生

select * from student where sdept = 'cs'
except
select * from student where sage <= 19

派生表查询

select sno,cno
from sc,(select sno,avg(grade) from sc group by sno)
as avg_sc(avg_sno,avg_grade) //临时表
where sc.sno = avg_sc.avg_sno and sc.grade >= avg_sc.avg_grade

排序查询

-- 排序查询,另外讲下查询顺序,先from表,然后where条件查询,接着select,最后order by 
select last_name,first_name,salary FROM employees WHERE commission_pct is NULL ORDER BY salary,first_name DESC
select last_name,first_name,salary FROM employees WHERE commission_pct is NULL ORDER BY first_name DESC,salary

常见函数

-- 常见函数:字符函数、数学函数、日期函数、流程控制函数、自定义函数
-- 1、字符函数
-- 拼接:CONCAT(str1,str2,...)    
select CONCAT(first_name,last_name,IFNULL(commission_pct,"null")) FROM employees
-- 获取字节长度:LENGTH(str)
select LENGTH(first_name) FROM employees
-- 获取字符长度:CHAR_LENGTH(str)
select CHAR_LENGTH(first_name) FROM employees
-- 截取子串:SUBSTR(str FROM pos FOR len)
SELECT SUBSTR('张三丰爱上了郭襄',1,3)
-- 替换数据:INSERT
select INSERT('mysql',1,2,'MY')
-- 获取字符第一次出现的索引:INSTR(str,substr)
select INSTR('中华人民共和国和中华民国的那些事儿','中华')
-- 去除前后空格:TRIM([remstr FROM] str)
select TRIM('  虚  竹  ')
-- 去除前后指定的字符:TRIM([remstr FROM] str)
select TRIM('xy' FROM 'xyxxx虚xx竹xxxxxy')
-- 去掉左边/右边指定字符
select LTRIM('     虚  竹  ')
select RTRIM('     虚  竹  ')
-- 返回字符串str最左边/右边的len个字符:LEFT(str,len)/RIGHT(str,len)
select LEFT('str',2)
select RIGHT('str',2)
-- LPAD/RPAD 左填充/右填充,结果都一样只是方向不同
select LPAD('木婉清',3, 'a')
select RPAD('木婉清',10,'a')
-- UPPER/LOWER 大小写
select UPPER('abcd')

-- 案例:查询员工表的姓名,要求格式:姓首字符大写,其它字符小写,名所有字符大写,且姓和名之间用_分割,最后起别名为OUTPUT
select UPPER(SUBSTR(first_name,1,1)),first_name FROM employees
select LOWER(SUBSTR(first_name,2)),first_name FROM employees
select UPPER(last_name) FROM employees
select concat(UPPER(SUBSTR(first_name,1,1)),LOWER(SUBSTR(first_name,2)),'_',UPPER(last_name)) OUTPUT FROM employees

-- STRCMP(expr1,expr2) 比较
select STRCMP('A','a')
select STRCMP('B','a')
-- 2、数学函数
-- 绝对函数:ABS(X)
select abs(-2.6)
-- 向上取整:CEIL(X)
select CEIL(1.09)
-- 四舍五入
select ROUND(1.87123)
-- 四舍五入小数点后保留三位
select ROUND(1.87123,3)
-- 截断:truncate
select TRUNCATE(1.87,1)
select TRUNCATE(1.87,0)
-- 取余数:MOD(N,M)
select MOD(-10,3)
select 3/10
-- 3、日期函数
select NOW()
select CURDATE()
select CURTIME()
select DATEDIFF('2019-7-13','1998-7-16')
select DATE_FORMAT('2019-7-13 18:20:20','%Y年%m月%d日 %H小时%i分钟%s秒')
select STR_TO_DATE('3/15 1998','%m/%d %Y')
select * from employees WHERE hiredate < STR_TO_DATE('3/15 1998','%m/%d %Y')

-- 4、流程控制
SELECT IF ( 100 > 9,
'好',
'坏' 
)

SELECT
    department_id,
    salary,
CASE
    department_id 
    WHEN 30 THEN
    1 
    WHEN 50 THEN
    2 ELSE 3 
    END result 
FROM
    employees

聚合函数/统计/分组函数

-- 聚合/统计函数

COUNT(DISTINCT expr,[expr...])
MAX(expr)
MIN(expr)
AVG([DISTINCT] expr)
SUM(expr)
-- 补充:一般查询count直接用*,意思是只要查询行有字段不为null就算上,相对快速
COUNT(*)

-- 分组
select count(*),salary from employees 
-- 分组+HAVING:having是对统计函数作条件过滤
select COUNT(*),AVG(salary) avg from employees GROUP BY salary HAVING avg>4000

连接

1.笛卡尔连接:

        select * from tableA,tableB...

2.内连接(其实所有连接操作底层都是笛卡尔的特定格式)

        2.1.内连接:SELECT * FROM student INNER JOIN score ON student.studentno=score.studentno

        2.2.等值连接:基于笛卡尔积,添加等值条件:SELECT * FROM student, score WHERE student.studentno=score.studentno

        2.3.不等值连接:同等值连接,只是运算符包括>、>=、<=、<、!>、!<和<>。

        2.4.自然连接:有去重功能的内连接,比如两张表有同名同类型字段,联表查询结果一般会显示两列该字段,而自然连接可以去重,保证只显示一列即可:SELECT ... FROM ... NATURAL JOIN ... ON ...=...

3.外连接

        3.1.左外连接:select * from student LEFT JOIN score ON student.studentno=score.studentno

        3.2.右外连接:select * from student RIGHT JOIN score ON student.studentno=score.studentno

        3.3.全连接:select * from student FULL JOIN score ON student.studentno=score.studentno

Join介绍(MySQL不提供full join


Join是SQL语句中非常重要的一个运算操作,常见的Join操作如下:

MySQL核心点笔记_第1张图片

 mysql 官方只提供了内连接,左外连接,右外连接三种方式。通过一定的方法也可以实现其它的连接。

数据准备
a.创建两张表

create table  `person` (
  `id` int(11),
  `name` varchar(255),
  `city_id` int(11) 
) ;

create table `city` (
  `city_id` int(11) ,
  `city_name` varchar(255)
) ;

插入数据

# 向person表中插入数据
insert into person values (1, 'name1', 1);
insert into person values (2, 'name2', 2);
insert into person values (3, 'name3', 3);
insert into person values (4, 'name4', 5);

#向city表中插入数据
insert into city values (1, 'city1');
insert into city values (2, 'city2');
insert into city values (3, 'city3');
insert into city values (4, 'city4');

1、左外连接

MySQL核心点笔记_第2张图片

左外连接返回左表的所有行,如果右表中没有匹配行,则返回NULL。

select * from city left join person on city.city_id = person.city_id;

运行结果:

+---------+-----------+------+-------+---------+
| city_id | city_name | id   | name  | city_id |
+---------+-----------+------+-------+---------+
|       1 | city1     |    1 | name1 |       1 |
|       2 | city2     |    2 | name2 |       2 |
|       3 | city3     |    3 | name3 |       3 |
|       4 | city4     | NULL | NULL  |    NULL |
+---------+-----------+------+-------+---------+

2、内连接

MySQL核心点笔记_第3张图片

内连接返回的是两张表共有的数据。

select * from person inner join city on person.city_id = city.city_id

运行结果:

+------+-------+---------+---------+-----------+
| id   | name  | city_id | city_id | city_name |
+------+-------+---------+---------+-----------+
|    1 | name1 |       1 |       1 | city1     |
|    2 | name2 |       2 |       2 | city2     |
|    3 | name3 |       3 |       3 | city3     |
+------+-------+---------+---------+-----------+

3、右外连接

MySQL核心点笔记_第4张图片
右外连接返回右表的所有行,如果左表中没有匹配行,则返回NULL。 

select * from city right join person on person.city_id = city.city_id;

运行结果:

+---------+-----------+------+-------+---------+
| city_id | city_name | id   | name  | city_id |
+---------+-----------+------+-------+---------+
|       1 | city1     |    1 | name1 |       1 |
|       2 | city2     |    2 | name2 |       2 |
|       3 | city3     |    3 | name3 |       3 |
|    NULL | NULL      |    4 | name4 |       5 |
+---------+-----------+------+-------+---------+

4、左连接

MySQL核心点笔记_第5张图片

左连接是得到A表中去除B表内容的剩下的部分,也就是A表独有的一部分。可以看做是在左外连接的结果中将双方共有的部分去掉得到的。

select * from city  left join person  on city.city_id = person.city_id where person.city_id is  null;

运行结果:

+---------+-----------+------+------+---------+
| city_id | city_name | id   | name | city_id |
+---------+-----------+------+------+---------+
|       4 | city4     | NULL | NULL |    NULL |
+---------+-----------+------+------+---------+

5、右连接

MySQL核心点笔记_第6张图片
右连接是得到B表中去除A表内容的剩下的部分,也就是B表独有的一部分。可以看做是在右外连接的结果中将双方共有的部分去掉得到的。

select * from city  right join person  on city.city_id = person.city_id where city.city_id is null;

运行结果:

+---------+-----------+------+-------+---------+
| city_id | city_name | id   | name  | city_id |
+---------+-----------+------+-------+---------+
|    NULL | NULL      |    4 | name4 |       5 |
+---------+-----------+------+-------+---------+

6、全连接

MySQL核心点笔记_第7张图片

全连接返回AB两表全部的数据,mysql没有提供full join关键字,不过可以使用使用union来实现,全连接等于左外连接与右外连接的并集。

select * from city left join person on person.city_id = city.city_id
union 
select * from city right join person on person.city_id = city.city_id;

运行结果:

+---------+-----------+------+-------+---------+
| city_id | city_name | id   | name  | city_id |
+---------+-----------+------+-------+---------+
|       1 | city1     |    1 | name1 |       1 |
|       2 | city2     |    2 | name2 |       2 |
|       3 | city3     |    3 | name3 |       3 |
|       4 | city4     | NULL | NULL  |    NULL |
|    NULL | NULL      |    4 | name4 |       5 |
+---------+-----------+------+-------+---------+

7、差集

MySQL核心点笔记_第8张图片

差集就是两张表都没有同时出现的数据集,其实也就是左连接与右连接的并集。

select * from city  left join person  on city.city_id = person.city_id where person.city_id is  null 
union
select * from city  right join person  on city.city_id = person.city_id where city.city_id is null;

运行结果:

+---------+-----------+------+-------+---------+
| city_id | city_name | id   | name  | city_id |
+---------+-----------+------+-------+---------+
|       4 | city4     | NULL | NULL  |    NULL |
|    NULL | NULL      |    4 | name4 |       5 |

————————————————

例题

1、简单的两表查询

use myemployees

select last_name,department_name FROM employees e,departments d

2、添加筛选条件

查询部门编号>100的部门名和所在的城市名

查询有奖金的员工名、部门名

查询城市名中第二个字符为o的部门名和城市名

3、添加分组+筛选
查询每个城市的部门个数
查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
查询部门中员工个数>10的部门名

4、添加分组+筛选+排序
查询部门中员工个数>10的部门名,并按照部门名降序
查询每个工种的员工个数和工种名,并按照个数降序

5、三表连接
案例查询员工名、城市名

常用类型

整型
tinyint smallint int bigint
浮点型
double(m,n) float decimal    m表示总长,n表示小数点后保留位数
字符型
char varchar text
二进制,用来存储图形数据
blob
日期型
date    格式:yyyy-MM-dd 
time    格式:hh:mm:ss
timestamp    格式:yyyyMMdd hhmmss
datetime 格式:yyyy-MM-dd hh:mm:ss

六大约束

not null
default 
primary key
FOREIGN KEY
unique 
check

例如:create table sc(
    sno char(9) [not null,unique,PRIMARY KEY],
    cno char(4),
    grade SMALLINT,
    [PRIMARY key(sno,cno),]
    [FOREIGN KEY(sno) REFERENCES student(sno),]
    [check(grade<>0 and grade>60)]
)

四大SQL语句

1、DDL (database definition language)
创表
CREATE TABLE IF NOT EXISTS xxx;
删表
drop table if exists xxx [RESTRICT/CASCADE];
修改:ALTER TABLE 语句用于在已有的表中添加、修改或删除列,。
1. ALTER TABLE table_name ADD column_name datatype
2. ALTER TABLE table_name DROP COLUMN  column_name
3. ALTER TABLE table_name ALTER COLUMN column_name datatype
4. ALTER TABLE table_name RENAME COLUMN column_name to newname
5. ALTER TABLE table_name RENAME to newname
复制表
    复制结构+数据
    create table xxx select * from yyy
    create table xxx select * from yyy.column
    复制结构
    create table xxx like yyy

2、DML(database manipulate language)

delete from tablename

update tablename set colume = newvalue where ...

insert into tablename values(...)

3、DQL

select * from tablename [lock in share mode|for update]

4、DCL

rollback、commit、grant...

存储引擎

innodb默认事务自动开启

1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务; 

2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败; 

3. InnoDB支持主键

4. InnoDB是聚簇索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。而辅助(非聚簇)索引需要两次查询,先查询到主键,然后再通过主键查询到数据。

5. 5.6版本后InnoDB也支持了全文索引

6. InnoDB不只支持表锁还支持行锁

7. Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI

        Innodb:frm是表定义文件,ibd是结构+数据文件

        Myisam:frm是表定义文件,myd是数据文件,myi是索引文件

事务

show variables like '%auto%'
关闭自动提交
set autocommit =0
开启手动事务
start TRANSACTION
编写事务的sql语句
...
提交或者回滚(如果在执行时有上行锁)
commit or rollback

举例
START TRANSACTION
select count(*) FROM departments
delete FROM departments where department_id = 1
select count(*) FROM departments
ROLLBACK

ACID:原子性、一致性、隔离性、永久性

1、查看当前会话的 隔离级别:
select @@tx_isolation;
2、查看系统的隔离级别:
select @@global.tx_isolation;
3、设置会话的隔离级别,隔离级别由低到高设置依次为:
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
4、设置当前系统的隔离级别,隔离级别由低到高设置依次为:
set global transaction isolation level read uncommitted;
set global transaction isolation level read committed;
set global transaction isolation level repeatable read;

【注:】mysql默认的事务处理级别是'REPEATABLE-READ',而Oracle和SQL Server是READ_COMMITED

MVCC

全网最全的一篇数据库MVCC详解,不全我负责-mysql教程-PHP中文网

SQL语句归根结底是读写操作,因而只有读写锁,而读写锁根据加锁范围又分为行锁和表锁:

行锁( 是读写锁、是可重入锁、是行锁/间隙锁、是悲观锁)

    行锁的劣势:开销大;加锁慢;会出现死锁

    行锁的优势:锁的粒度细(就是管理范围,越细越小,越粗越大),发生锁冲突的概率低;处理并发的能力强

    上锁方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:

        1、读/共享锁:select * from tableName where … + lock in share more

        2、写/独占锁/排他锁:select * from tableName where … + for update、UPDATE、DELETE 和 INSERT

    上锁时机:SQL执行语句时
    
    解锁时机:有事务的话要到commit/rollback时解锁,无事务执行完SQL时解锁

表锁(是读写锁、是表锁、是可重入锁、是悲观锁)

    表锁的劣势:并发慢,锁冲突可能性大
    
    表锁的优势:锁粒度粗,资源占用少
    
    一般表锁上锁/解锁时机:

        1、读/共享锁(S锁):lock/unlock table 表名 read

        2、写/独占锁(X锁):lock/unlock table 表名 write
        
        3、全部解锁:unlock tables,必须手动解锁,不像行锁,事务或语句结束后自动解锁
        
        4、表锁的兼容性(即表级S、X兼容性)
        
                        S      X
            S       +      -
            X          -      -

意向锁(是读写锁、是表锁、是可重入锁、是悲观锁)。

           1、作用仅为了解决行锁和表锁冲突:例如事务A加了行锁,事务B想加表锁,B需要遍历每行查看是否有行锁,而等查到事务A的行锁时已经花了很长时间,为了解决这种问题引入了意向锁,意向锁是一种表级读写锁,加行锁前先加意向锁,这样当事务B要加表锁时只需要查看是否加了表锁或者意向锁即可,效率提升;

           2、意向锁不操心行锁与行锁间的冲突:如果两个事务都申请意向锁,则意向锁间相互兼容(即 IS和IX、IS和IS、IX和IS 间相互兼容),因为1中已经说了在加行锁前才会加意向锁,所以当前实际是行锁间冲突,而行锁机制会解决并发问题,不需要意向锁来操心
            
           3、意向锁IS、IX和表级锁S和X的冲突:
        
                            IS     IX      S    X
                IS         +      +      +     -
                IX         +      +      -      -
                S          +      -       +      -
                X          -      -        -       -
        
        上锁/解锁时机:MySQL加行锁前先自动加上意向锁,解锁时如果有事务的话commit/rollback时解锁,如果没有事务SQL语句结束就释放锁
                    
        读写锁:意向锁是表层级的读写锁,分为意向共享锁(IS锁)、意向独占锁(IX锁),只要有s锁就上is锁,共享s锁,隔离x锁、ix锁

        上锁时机:SQL执行语句时
    
        解锁时机:有事务的话要到commit/rollback时解锁,无事务执行完SQL时解锁

缓存

MySQL缓存https://zhuanlan.zhihu.com/p/55947158#:~:text=MySQL%E8%83%BD%E5%A4%9F%E7%BC%93%E5%AD%98%E7%9A%84%E6%9C%80%E5%A4%A7%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%9C%EF%BC%8C%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%9C%E5%A4%A7%E4%BA%8E%E8%AF%A5%E5%80%BC%E6%97%B6%E4%B8%8D%E4%BC%9A%E8%A2%AB%E7%BC%93%E5%AD%98%E3%80%82,%E9%BB%98%E8%AE%A4%E5%80%BC%E6%98%AF1048576%20%281MB%29%E5%A6%82%E6%9E%9C%E6%9F%90%E4%B8%AA%E6%9F%A5%E8%AF%A2%E7%9A%84%E7%BB%93%E6%9E%9C%E8%B6%85%E5%87%BA%E4%BA%86%E8%BF%99%E4%B8%AA%E5%80%BC%EF%BC%8CQcache_not_cached%E7%9A%84%E5%80%BC%E4%BC%9A%E5%8A%A01%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9F%90%E4%B8%AA%E6%93%8D%E4%BD%9C%E6%80%BB%E6%98%AF%E8%B6%85%E5%87%BA%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%80%83%E8%99%91%E5%9C%A8SQL%E4%B8%AD%E5%8A%A0%E4%B8%8ASQL_NO_CACHE%E6%9D%A5%E9%81%BF%E5%85%8D%E9%A2%9D%E5%A4%96%E7%9A%84%E6%B6%88%E8%80%97%E3%80%82
MySQL缓存的应用场景https://www.jianshu.com/p/63ce65e4dc23

总的来说MySQL缓存用的比较少,在大数据量、小并发、变动小的系统中非常适用,高并发时还是用分布式缓存吧

索引

以innoDB为例,创建表时通过B树实现了主键的聚簇索引,因此查询时想要发挥B树的快查威力就必须用主键查询,但一般SQL查询都是以主键以外的字段查询,因此需要以常用的查询字段建立非聚簇索引

索引添加

1 新建表中添加索引

① 普通索引

create table t_dept(
    no int not null primary key,
    name varchar(20) null,
    sex varchar(2) null,
    info varchar(20) null,
    index index_no(no)    //基于索引的colume设置索引名,比如no,则命名格式为index_no
  )

② 唯一索引

create table t_dept(
       no int not null primary key,
       name varchar(20) null,
       sex varchar(2) null,
       info varchar(20) null,
       unique index index_no(no)
     )

③ 全文索引

create table t_dept(
       no int not null primary key,
       name varchar(20) null,
       sex varchar(2) null,
       info varchar(20) null,
       fulltext index index_no(no)

④ 多列索引

create table t_dept(
       no int not null primary key,
       name varchar(20) null,
       sex varchar(2) null,
       info varchar(20) null,
       key index_no_name(no,name)
     )

2 在已建表中添加索引

① 普通索引

create index index_name          //index_name是索引名
             on t_dept(name);    //t_dept是表名

② 唯一索引

create unique index index_name
              on t_dept(name);

③ 全文索引

create fulltext index index_name
              on t_dept(name);

④ 多列索引

create index index_name_no
               on t_dept(name,no)

3 以修改表的方式添加索引

① 普通索引

alter table t_dept
          add index index_name(name);

② 唯一索引

alter table t_dept
            add unique index index_name(name);

③ 全文索引

alter table t_dept
           add fulltext index_name(name);

④ 多列索引

alter table t_dept
              add index index_name_no(name,no);

 以下情况适合创建索引

  1. 在经常需要搜索的列上,可以加快搜索的速度。

  2. 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构。

  3. 在经常用于连接两张表的列上,这些列主要是一些外键,可以加快连接的速度。

  4. 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的。

  5. 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间。

  6. 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

以下情况不适合创建索引

  1. 表记录太少。

  2. 经常增删改的表。

  3. 数据重复且分布平均的表字段,因此应该只为最经常查询和经常排序的数据列建立索引(如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果)

sql调优

索引失效

        索引失效是指索引不支持查询条件导致全表扫描,索引失效有全局失效和局部失效。调优sql 需要清楚如何避免索引失效

      1、全值匹配:查询时按照最左匹配将查询条件全部弄上,效率最高

create table `tb_seller` (
	`sellerid` varchar (100),
	`name` varchar (100),
	`nickname` varchar (50),
	`password` varchar (60),
	`status` varchar (1),
	`address` varchar (100),
	`createtime` datetime,
    primary key(`sellerid`)
)engine=innodb default charset=utf8mb4; 
 
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('huawei','华为科技有限公司','华为小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itcast','传智播客教育科技有限公司','传智播客','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itheima','黑马程序员','黑马程序员','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('luoji','罗技科技有限公司','罗技小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('oppo','OPPO科技有限公司','OPPO官方旗舰店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('ourpalm','掌趣科技股份有限公司','掌趣小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('qiandu','千度科技','千度小店','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('sina','新浪科技有限公司','新浪官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('xiaomi','小米科技','小米官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('yijia','宜家家居','宜家家居旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
 
// 如果在创表sql中创建索引还要刷新,插入完成再创省事
create index idx_seller_name_sta_addr on tb_seller(name,status,address);

// 全值匹配,对索引中所有列都指定具体值,执行效率高,避免索引失效
explain select * from tb_seller where name='小米科技' and status='1'
and address='北京市'\G;

        2、最左匹配:根据索引字段顺序查询,合理的使用查询条件避免索引失效。不只是查询,order by、group by指令也能使用索引(using index,避免using filesorts)

最左匹配原则就是指在联合索引中,如果你的 SQL 语句中用到了联合索引中的最左边的索引,那么这条 SQL 语句就可以利用这个联合索引去进行匹配。例如某表现有索引(a,b,c),现在你有如下语句:

1、select * from t where a=1 and b=1 and c =1;     #可以利用到定义的索引(a,b,c),用上a,b,c
​
2、select * from t where a=1 and b=1;     #可以利用到定义的索引(a,b,c),用上a,b
​
3、select * from t where b=1 and a=1;     #可以利用到定义的索引(a,b,c),用上a,b(mysql有查询优化器)
​
4、select * from t where a=1;     #也可以利用到定义的索引(a,b,c),用上a
​
5、select * from t where b=1 and c=1;     #不可以利用到定义的索引(a,b,c),失效
​
6、select * from t where a=1 and c=1;     #可以利用到定义的索引(a,b,c),只用a索引,回表查c

        3、不在索引列上做任何操作(计算、函数、类型转换),会导致索引失效

1、索引列参与计算,不走索引
SELECT `username` FROM `t_user` WHERE age=20;-- 会使用索引
SELECT `username` FROM `t_user` WHERE age+10=30;-- 不会使用索引!!因为所有索引列参与了计算
SELECT `username` FROM `t_user` WHERE age=30-10;-- 会使用索引
2、索引列使用函数,可能不走索引
-- 不会使用索引,因为使用了函数运算,原理与上面相同
SELECT username FROM t_user WHERE concat(username,'1') = 'admin1'; 
-- 会使用索引
SELECT username FROM t_user WHERE username = concat('admin','1'); 

        4、范围查询后的列索引无效

1、select * from t where a=1 and b>1 and c =1; 
a,b可以用到(a,b,c),c索引失效,需要回表。
这个原因可以从联合索引的结构来解释:
在a、b走完索引后,c肯定是无序了,所以c就没法走索引
但是如果是建立(a,c,b)联合索引,则a,b,c都可以使用索引,因为优化器会改写为:
select * from t where a=1 and c=1 and b >1;

2、select * from table where a = '1' and b > '2' and c='3' 这种字符查询也只有a、b走索引。
原理同上

以index (a,b,c)为例建立这样的索引相当于建立了索引a、ab、abc三个索引。一个索引顶三个索引当然是好事,毕竟每多一个索引,都会增加写操作的开销和磁盘空间的开销。

        5、优先使用覆盖索引,防止回表查询

        6、减少select *,防止回表查询

        7、like以通配符开头'%...'会导致索引失效,可以加到中间或者右边,如非要在左边可以使用覆盖索引,虽然type=index,但也比没有强

create table `tb_seller` (
	`sellerid` varchar (100),
	`name` varchar (100),
	`nickname` varchar (50),
	`password` varchar (60),
	`status` varchar (1),
	`address` varchar (100),
	`createtime` datetime,
    primary key(`sellerid`)
    index idx_name_status_address('name','status','address')
)engine=innodb default charset=utf8mb4; 

// 索引列使用 like 语句,可能不走索引,以idx_name_status_address索引为例
SELECT name,status FROM USER WHERE username LIKE 'mysql测试%'   --走索引
SELECT name,status FROM USER WHERE username LIKE 'my%测试%'     --走索引
SELECT name,status FROM USER WHERE username LIKE '%mysql测试'   --不走索引
SELECT name,status FROM USER WHERE username = 'mysql测试' and status like 't%ue' and address = '...'  --走索引

// 想让左匹配有效可以使用覆盖索引,即type=index
// 左匹配需要挨个遍历,因此要用索引扫描,当扫描到关键词节点就可以使用b+树按序查找

// 想让左匹配有效第一个查询必须是like(不区分左中右匹配),因为type要依靠第一个字段建立
SELECT name,status FROM USER WHERE username LIKE '%mysql测试'   --走索引
SELECT name,status FROM USER WHERE status LIKE '%ue'   --走索引

// 前面有等值查询,则左匹配失效
SELECT name,status FROM USER WHERE username = 'mysql测试' and status like '%rue'   --name走索引,status失效

【注:】一个查询语句的查询type是唯一的

        8、is null,is not null导致索引失效,引发全表扫描

SELECT * FROM t_user WHERE username IS NULL -- 不走索引
SELECT * FROM t_user WHERE username IS NOT NULL -- 不走索引

        9、不等号会导致索引失效,引发全表扫描

SELECT * FROM t_user WHERE username <> 'mysql测试'

        10、索引列使用 in 、between语句,可能不走索引

// stock_code数据类型为varchar
SELECT * FROM `stock_data` WHERE `stock_code` IN ('600538')  -- 走索引
SELECT * FROM `stock_data` WHERE `stock_code` IN ('600538','688663','688280')  -- 走索引
SELECT * FROM `stock_data` WHERE `stock_code` IN (>=6)  -- 不走索引
SELECT * FROM `stock_data` WHERE `stock_code` IN (600538)  -- 不走索引

// between也一样,当查到的数据量占比越小越可能走索引

        11、字符串不加单引号会导致索引失效

-- stock_code字符串类型带索引
SELECT * FROM `stock_data` WHERE stock_code = '600538'  --走索引
SELECT * FROM `stock_data` WHERE stock_code = 600538  --不走索引

        12、用or连接操作会导致全局失效

        尽量避免 OR 操作,只要有一个字段没有索引就全局失效!!!

-- stock_code带索引,open不带索引
SELECT * FROM `stock_data` WHERE `stock_code` = '600538' OR `open` = 6.62  -- 不走索引
-- stock_code带索引,up_down_pre带索引
SELECT * FROM `stock_data` WHERE `stock_code` = '600538' OR `up_down_pre` = 5.1  -- 走索引

总结

1、按最左匹配设置好顺序

2、设置好逻辑查询

3、保证查询条件索引有效 ,实际上就是要符合type的查询规则,比如type是index,如果有左匹配查询,就需要第一个字段设置like

  好文推荐

索引调优https://zhuanlan.zhihu.com/p/61687047

MySQL索引失效在MySQL中,并不是你建立了索引,并且你在SQL中使用到了该列,MySQL就肯定会使用到那些索引的,有一些情况很可能在你不知不觉中,你就“成功的避开了”MySQL的所有索引。1、索引列参与计算,不走索引SELECT `username` FROM `t_user` WHERE age=20;-- 会使用索引SELECT `username` FROM `t_user` WHERE age+10=30;-- 不会使用索引!!因为所有索引列参与了计算SELECT `username` FROMhttps://blog.csdn.net/Dxy1239310216/article/details/121679668

MYSQL的最左匹配原则https://blog.csdn.net/Andrew_Chenwq/article/details/125242197#:~:text=%E6%9C%80%E5%B7%A6%E5%8C%B9%E9%85%8D%E5%8E%9F%E5%88%99%E5%B0%B1%E6%98%AF%E6%8C%87%E5%9C%A8%E8%81%94%E5%90%88%E7%B4%A2%E5%BC%95%E4%B8%AD%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%20SQL,%E8%AF%AD%E5%8F%A5%E4%B8%AD%E7%94%A8%E5%88%B0%E4%BA%86%E8%81%94%E5%90%88%E7%B4%A2%E5%BC%95%E4%B8%AD%E7%9A%84%E6%9C%80%E5%B7%A6%E8%BE%B9%E7%9A%84%E7%B4%A2%E5%BC%95%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E6%9D%A1%20SQL%20%E8%AF%AD%E5%8F%A5%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%88%A9%E7%94%A8%E8%BF%99%E4%B8%AA%E8%81%94%E5%90%88%E7%B4%A2%E5%BC%95%E5%8E%BB%E8%BF%9B%E8%A1%8C%E5%8C%B9%E9%85%8D%E3%80%82

explain

1、字段

id        select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。

select_type    表示 SELECT 的类型,常见的取值有 SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、DERIVED (临时查询)、UNION(UNION 中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个 SELECT)等

table    输出结果集的表

type    表示查询算法,性能由好到差的连接类型为( system —> const -----> eq_ref ------> ref -------> index_merge ------> range -----> index ------> all )

possible_keys    表示查询时,可能使用的索引

key    表示实际使用的索引

key_len    索引字段的长度,在保证精度的前提下越少越好

ref        ref指某个表的索引字段“=”号后的值,如果是常量就const,变量就字段名,范围查询是null  

rows    扫描行的数量,越少越好

extra    执行情况的说明和描述        

2、type    

介绍

1、type是查询类型,是一种算法,在表和索引中依据查询条件查询数据;

2、每个查询语句的type是唯一的;

3、type要求查询条件必须符合其规则,不满足就会出现索引失效。以index为例:

       第一个查询是指定type的关键,要么是空要么是like;

       语句中如果有等值查询index也可以基于b+tree查询

type类型

        null    MySQL不访问任何表,索引,直接返回结果

        system    表只有一行记录(等于系统表),这是const类型的特例,一般不会出现

        const    const 用于primary key 或者 unique 索引的常量匹配,如主键查询:where id =1,就是单表精确查询,业务中不可能见到

        eq_ref    类似ref,区别在于使用的是主键、唯一索引的关联查询,关联查询出的记录只有一条。

        ref    和 eq_ref 不同的是使用的是非唯一索引的关联查询。这种索引匹配某个常量值或者关联值的所有行。

        index_merge    查询用到了多个索引时执行数据合并

        range   对索引进行范围匹配,where 之后出现 between , < , > , in 等操作。

        index    index 与 all 的区别是 index 利用了索引高效遍历,而 all 是遍历全表。

        all    非主键字段遍历全表找到匹配的行,优化方法是为指定字段设置index

【注:】eq_ref、ref本质是拿引用来匹配自身记录,而const是值本身来匹配自身记录

3、extra

        1、using filesort    说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取, 称为 “文件排序”, 效率低。

        2、using temporary    使用了内存中的临时数据,常见于对子查询、临时表的查询,效率一般

        3、using index    表示相应的select操作使用了索引, 避免访问表的数据行, 效率不错。

        4、using where   使用了数据行,效率随着数据增加而变弱

        5、impossible where         查询歧义,如 id=1 and id=2,不可能同时满足两个要求

好文推荐

MySQL调优:慢SQL调优https://blog.csdn.net/flycp/article/details/108084388?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165321001516781483780109%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165321001516781483780109&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-108084388-null-null.142%5Ev10%5Econtrol,157%5Ev4%5Econtrol&utm_term=%E6%85%A2SQL%E8%B0%83%E4%BC%98&spm=1018.2226.3001.4187

MySQL调优:调优三步曲(慢查询、explain、profile)https://blog.csdn.net/weixin_36206609/article/details/113895140?ops_request_misc=&request_id=&biz_id=102&utm_term=msyql%E8%B0%83%E4%BC%98&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-113895140.142%5Ev32%5Eexperiment_2_v1,185%5Ev2%5Etag_show&spm=1018.2226.3001.4187

4、总结

分析时主要关注id、type、key、key_len、ref、rows、extra

MySQL核心点笔记_第9张图片

小表驱动大表

        小表做驱动表,即外部for查询,大表做被驱表,即b+树查询;

        优点:降低了连接数,减少了io使用;充分利用了b+树查询优势

        应用:in、exists

                大表 where 大表.id in (select * from 小表);

                小表 exists (大表 where 大表.id=小表.id)

好文推荐
小表驱动大表https://blog.csdn.net/fly_miqiqi/article/details/90348800

调优流程

        slow.log查询慢sql,explain分析,最后show profiles测试

调优案例——分页

准备

// 创建测试表
CREATE TABLE `test_order_copy1` (
  `id` int(11) NOT NULL,
  `platform_sn` varchar(64) DEFAULT NULL,
  `third_sn` varchar(64) DEFAULT NULL,
  `type` tinyint(1) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_type` (`type`),
  KEY `idx_type&platform_sn&third_sn&create_time` (`type`,`platform_sn`,`third_sn`,`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

// 插入200万笔
CREATE DEFINER=`root`@`%` FUNCTION `batchAddOrderData`() RETURNS int(11)
BEGIN
	#Routine body goes here...
	DECLARE num INT DEFAULT 2000000;
	DECLARE i int DEFAULT 1;
	
	while i <= num do
	insert into
	test_order
	VALUES(i,concat('SN',i),UUID(),1,now());
		set i=i+1;
	end while;
	
	return i;
END

直接分页

select * FROM test_order_copy2 where type = 1 limit 1500000,50

执行结果
select * FROM test_order_copy2 where type = 1 limit 1500000,50
> OK
> 时间: 7.154s

分析

        未使用索引;limit耗时

分析列表 

优化方案

1、建立索引

2、SQL

2.1、连接查询

select * from test_order_copy1 o right join (
	select id FROM test_order_copy1 where type = 1 limit 1500000,50
) t on o.id = t.id
执行结果
 select * from test_order_copy1 o right join (
    select id FROM test_order_copy1 where type = 1 limit 1500000,50
) t on o.id = t.id
> OK
> 时间: 1.889s

2.2、嵌套查询 

select * from test_order_copy1 where type = 1 and id >=(
	select id FROM test_order_copy1 where type = 1 limit 1500000,1
) limit 50
执行结果
select * from test_order_copy1 where type = 1 and id >=(
    select id FROM test_order_copy1 where type = 1 limit 1500000,1
) limit 50
> OK
> 时间: 2.261s

2.3、id限定

        利用id关联分页,巧妙借id索引分页,但必须保证id是递增(只要是索引都可使用,以求稳定性最好是唯一索引)

// 分析发现这条SQL都不用走type索引,完全走primary
select * from test_order_copy2 where type = 1 and id >=1500000 limit 50;
执行结果
select * from test_order_copy2 where type = 1 and id >=1500000 limit 50
> OK
> 时间: 0.202s

2.4、索引排序

        是对id限定的补偿,如果不能保证索引是递增,就需要order by做一下重排,注意必须要给重排字段设置索引,order by可以借着索引快排,即using index,否则就是using filesort

// 如果设置了复合索引或者覆盖索引,则该sql的优化逻辑为:
// 利用索引叶子节点是id这点,通过索引做type、id查询;
// 再根据id回表查询,然后再返回索引继续往下查询;
// 这种查询会导致数据id无序,因此要排序,即order by id,然后limit 50
select * from test_order_copy2 where type = 1 and id >=1500000 
ORDER BY id limit 50;
执行结果
select * from test_order_copy2 where type = 1 and id >=1500000 ORDER BY id limit 50;
> OK
> 时间: 0.001s

3、总结

        3.1、id限定最高效,较之原来提升了30倍;做了排序补偿的索引排序也不错

        3.2、大数据量使用滑动分页,因为count查询是实打实的条件查询,速度干不过id限定,具体多大要看机器性能,比如三五百万

存储过程

存储过程https://blog.csdn.net/qq_36777191/article/details/104171953

存储函数

触发器https://blog.csdn.net/qq_36777191/article/details/104176504

触发器

触发器https://blog.csdn.net/qq_36777191/article/details/104190013

三大日志

        即redolog、binlog、undolog

        redolog

        1、是innoDB的日志,物理存储;

        2、任务是宕机重启后保证数据一致性;

        3、记录事务,当事务结束时并不会立即刷新到磁盘,而是通过redo buffer记录到redolog,然后再异步刷进ibd;

        4、redolog写入ibd的那部分数据就相当于过期了,redolog会用新数据覆盖那部分数据,也因此redolog日志是可重复使用的持久化文件

        binlog

        1、是MySQL的日志,逻辑存储;

        2、任务是日志分析,主从同步,数据恢复;

        3、记录数据变动,记录方式有row、statement和miexd

                row:比如某行某个字段变为了***,优点是记录细致,缺点资源大

                statement:就是SQL语句,优点省资源,缺点主从模式下如果有函数容易不一致,比如now(),uuid()

                mixed:自动选择用row还是statement

        redolog和binlog的区别

        1、redo log是在InnoDB存储引擎层产生,而binlog是MySQL数据库的上层产生的,并且二进制日志不仅仅针对INNODB存储引擎,MySQL数据库中的任何存储引擎对于数据库的更改都会产生二进制日志。

        2、两种日志记录的内容形式不同。MySQL的binlog是逻辑日志,其记录是对应的SQL语句。而innodb存储引擎层面的重做日志是物理日志。

        3、两种日志与记录写入磁盘的时间点不同,二进制日志只在事务提交完成后进行一次写入。而innodb存储引擎的重做日志在事务进行中不断地被写入,并且日志不是随事务提交的顺序进行写入的。MySQL核心点笔记_第10张图片

         4、binlog在写满或者重启之后,会新产生binlog文件,而redo log是循环使用。

        5、binlog作为数据分析,数据恢复,主从同步使用,而redo log会参与到ibd的数据持久化流程,目的是异常宕机或者介质故障时恢复数据。 

MySQL核心点笔记_第11张图片

binlog在主从复制中的应用

 MySQL核心点笔记_第12张图片

可以看出redolog参与了ibd的数据持久化,redlolog的地位非常重要 

        undolog 

        1、实现事务的原子性:undo log可以用于实现事务的原子性, 如果事务处理过程出现一些特殊情况,比如sql错误等等情况,就要执行回滚(rollback)操作,mysql就可以利用undo log将数据恢复到事务开始之前

        2、实现多版本并发控制(MVCC):undo log 在 MySQL InnoDB 存储引擎中用来实现多版本并发控制,事务没提交之前,undo日志可以作为高并发情况下,其它并发事务进行快照读MySQL核心点笔记_第13张图片

好文推荐

  binloghttps://blog.csdn.net/Allenzyg/article/details/106446992  redolog的作用和原理https://blog.csdn.net/qq_42773863/article/details/120988441?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165324292716782425142146%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165324292716782425142146&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-4-120988441-null-null.142%5Ev10%5Econtrol,157%5Ev4%5Econtrol&utm_term=redolog+ibd&spm=1018.2226.3001.4187redolog和binlog的区别https://blog.csdn.net/wanbin6470398/article/details/81941586

undologhttps://blog.csdn.net/u014427391/article/details/109022361
三大日志https://javaguide.cn/database/mysql/mysql-logs.html#%E5%89%8D%E8%A8%80        集群

        集群就是n主m从的布局,总的来说主从复制的逻辑在于主机写,从机读。从单体架构往集群架构发展的大概逻辑:

  1. 把单体架构的ibd复制到扩展机器,
  2. 主机设置binlog记录事件,
  3. binlog数据同步到从机,从机记录到relaylog,然后flush到从机磁盘

        relay log

        我们翻译成中文,一般叫做中继日志,一般情况下它在MySQL主从同步读写分离集群的从节点才开启。主节点一般不需要这个日志。

        master主节点的binlog传到slave从节点后,被写道relay log里,从节点的slave sql线程从relaylog里读取日志然后应用到slave从节点本地。从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后SQL线程会读取relay-log日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致。

        它的作用可以参考如下图,从图片中可以看出,它是一个中介临时的日志文件,用于存储从master节点同步过来的binlog日志内容,它里面的内容和master节点的binlog日志里面的内容是一致的。然后slave从节点从这个relaylog日志文件中读取数据应用到数据库中,来实现数据的主从复制。MySQL核心点笔记_第14张图片

 好文推荐

主从复制https://blog.csdn.net/qq_21153619/article/details/81529880

主从复制https://blog.csdn.net/weixin_30539317/article/details/113281081?ops_request_misc=&request_id=&biz_id=102&utm_term=%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%20MySQL%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-113281081.142%5Ev10%5Econtrol,157%5Ev4%5Econtrol&spm=1018.2226.3001.4187relaylog和binlog实现MySQL的主从同步原理https://blog.csdn.net/javaanddonet/article/details/112596148

你可能感兴趣的:(MySQL,数据库,sql)