主从复制原理、作用和实现
主从复制的类型 : 基于语句的复制、基于行的复制。MySQL默认使用基于语句的复制,当基于语句的复制会引发问题的时候就会使用基于行的复制,MySQL会自动进行选择。
主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。
- binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
- I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
- SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。
就是从库同步主库数据的过程是串行化的,也就是说主库上并行的操作,在从库上会串行执行。
问题: 主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,有些数据可能就丢失了。
解决方案:
- 半同步复制 :主库写入binlog日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的relay log之后,接着会返回一个ack给主库,主库接收到至少一个从库的ack之后才会认为写操作完成了。
- 并行复制:从库开启多个线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。
总体概览
-
Connectors 指的是不同语言中与SQL的交互
-
Management Serveices & Utilities: 系统管理和控制工具
-
Connection Pool 连接池
管理缓冲用户连接,线程处理需要缓存的需求。负责监听对MySQL Server的各种请求,接收连接请求,转发所有连接到线程管理模块。每一个连接上 MySQL Server 的客户端请求都会被分配(或创建)一个连接线程为其单独服务。而连接线程的主要工作就是负责 MySQL Server 与客户端的通信,接受客户端的命令请求,传递 Server 端的结果信息等。线程管理模块则负责管理维护这些连接线程。包括线程的创建,线程的 cache 等。
-
SQL Interface: SQL接口
接受用户的SQL命令,并且返回用户需要查询的结果。
-
Parser: 解析器
SQL命令传递到解析器的时候会被解析器验证和解析。解析器是由Lex和YACC实现的,是一个很长的脚本。
-
Optimizer: 查询优化器
SQL语句在查询之前会使用查询优化器对查询进行优化。就是优化客户端请求的 query(sql语句) ,根据客户端请求的 query 语句,和数据库中的一些统计信息,在一系列算法的基础上进行分析,得出一个最优的策略,告诉后面的程序如何取得这个 query 语句的结果
-
Cache和Buffer: 查询缓存
是将客户端提交 给MySQL 的 Select 类 query 请求的返回结果集 cache 到内存中,与该 query 的一个 hash 值 做一个对应。
-
存储引擎接口
- 实现其底层数据存储引擎的插件式管理
SQL语句执行得很慢的原因
偶尔很慢的原因
1、在刷新脏页
更新字段时不会马上同步持久化,而是把更新的记录会写入到redo log
中。再等到空闲时由redo log
把最新的数据同步到磁盘中。
redo log
写满了- 内存不够了
2、获取不到锁(表锁或者行锁)
如果要判断是否真的在等待锁,我们可以用 show processlist
这个命令来查看当前的状态。
一直很慢的原因
1、Explain查看下
- 没有则建立索引;
- 是否查询中使用到了索引,利用覆盖索引和最左匹配原则,查询列和索引列一致;
- 是否在索引列上做了任何计算;
- 使用了模糊查询中的左模糊和全模糊;
!=
、<>
或者is not null
- 字符串不加单引号索引失效
- 少用or,用它连接时会索引失效
Explain性能分析
使用Explain可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理SQL语句的。分析查询语句或是表结构的性能瓶颈。
- id : 查询的序列号
- id相同,执行顺序由上至下
- id不同,id越大优先级越高
- select_type
- table
- type
- system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
- possible_keys
- key
- key_len
- ref
- rows
- Extra
查询优化
- 永远小表驱动大表
- ORDER BY关键字优化
- ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序
- 尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀
- GROUP BY关键字优化
- groupby实质是先排序后进行分组,遵照索引建的最佳左前缀
往表里插入1000W数据
建表
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`deptName` varchar(30) DEFAULT NULL,
`address` varchar(40) DEFAULT NULL,
`ceo` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `emp`;
create table `emp` (
`id` int(11) not null auto_increment,
`empno` int not null,
`name` VARCHAR(20) default null,
`age` int(3) default null,
`deptId` int(11) default null,
primary key(`id`)
)engine=InnoDB auto_increment= 1 default charset = utf8;
设置参数log_bin_trust_function_creators
show variables like 'log_bin_trust_function_creators';
set global log_bin_trust_function_creators = 1;
创建函数保证每条数据都不同
- 随机产生字符串
Delimiter $$
create function rand_string(n INT) returns varchar(255)
begin
declare chars_str varchar(100) default
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
declare return_str varchar(255) default '';
declare i INT default 0;
while i < n do
set return_str = concat(return_str, substring(chars_str, floor(1+rand()*52),1));
set i = i + 1;
end while;
return return_str;
end $$
# 删除用 drop function
- 随机产生部门编号
delimiter $$
create function rand_num(from_num int, to_num int) returns int(11)
begin
declare i int default 0;
set i = floor(from_num + RAND() * (to_num - from_num + 1));
return i;
end $$
创建存储过程
-
创建往emp表中插入数据的存储过程
delimiter $$ create procedure insert_emp(start int, max_num int) begin declare i int default 0; set autocommit = 0; repeat set i = i + 1; insert into emp (empno, name, age, deptid) values ((start+i), rand_string(6), rand_num(30,50), rand_num(1,10000) ); until i = max_num end repeat; commit; end $$
-
创建往dept表中插入数据的存储过程
delimiter $$
create procedure `insert_dept`(max_num int)
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i +1;
insert into dept(deptname, address,ceo) values(rand_string(8), rand_string(10),rand_num(1,500000));
until i = max_num
end repeat;
commit;
end $$
调用存储过程
delimiter ;
call insert_dept(10000);
call insert_emp(100000,500000);
批量删除某个表上的所有索引
#查询索引
select index_name from information_schema.STATISTICS where table_name = 't_emp' and table_schema='mydb' and index_name <> 'PRIMARY' and seq_in_index = 1;
DELIMITER $$
CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE ct INT DEFAULT 0;
DECLARE _index VARCHAR(200) DEFAULT '';
DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY' ;
DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2 ;
OPEN _cur;
FETCH _cur INTO _index;
WHILE _index<>'' DO
SET @str = CONCAT("drop index ",_index," on ",tablename );
PREPARE sql_str FROM @str ;
EXECUTE sql_str;
DEALLOCATE PREPARE sql_str;
SET _index='';
FETCH _cur INTO _index;
END WHILE;
CLOSE _cur;
END$$