0.mysql | 02优化

目录

    • SQL优化
  • **分析SQL性能执行计划EXPLAIN**
      • type
      • posible_keys、key
      • key_len索引的长度
      • ref
      • rows
      • Extra
    • 优化案例
      • 单表优化
      • 双表优化
      • 多表优化
    • 索引失效原则
    • 优化方法
    • SQL排查---->慢查询日志
    • 分析海量数据
    • 锁机制
    • 主从复制

DDL自动提交

DML提交

MYSQL Query Opiimizer优化器

MYSQL逻辑分层

连接层–>提供与客户端连接的服务

服务层–>提供各种用户使用的接口、=提供SQL优化器

引擎层–>提供·各种存储数据的方式(InnoDB、MyISAM)

存储层–>存储数据

InnoDB(MYSQL默认):事务优先(适合高并发操作:行锁)

MyISAM:性能优先(表锁)

# 查询数据支持的引擎
show engines \g;
# 查看当前使用的引擎
show variables like '%storage_engine%';
# 指定数据库表的引擎
CREATE TABLE test(
id int(4) AUTO_INCREMENT,
name varchar(5),
dept varchar(5),
primary key(id)
)ENGINE=MyISAM AUTO_INCREMENT=2 
# 设置表引擎为MyISAM,自增长为2
DEFAULT CHARSET=utf8;

SQL优化

优化原因:性能低、执行时间太长、等待时间太长,SQL语句欠佳(连接查询)、索引失效、服务器参数设置不佳

SQL编写过程:

SELECT … FROM … JOIN … ON … WHERE … GROUP BY …HAVING …ORDER BY … LIMIT…

SQL解析过程

FROM … ON … JOIN … WHERE … GROUP BY … HAVING … . SELECT DISTINCT … ORDER BY … HAVING … SELECT …ORDER BY … LIMIT

SQL优化主要是优化索引

索引是帮助MYSQL高效获取数据的*数据结构*。

(树:B树、B+树、Hash树)

索引弊端:

  1. 索引本身很大(占存很大),可以存放在内存/硬盘(默认硬盘)
  2. 索引会降低增删改的效率(对表内容进行增删改、也要对索引进行增删改)用空间换时间

索引优势:

1.提高查询效率(降低I/O使用率)

2.降低CPU使用率(ORDER BY age DESC,因为B树索引本身就是一个排好序的结构,因此就可以直接使用)

索引不适合场景:

数据量比较少的字段

频繁更新的字段

很少使用的字段

B+树中,数据全部存放在叶节点中。

B+树中查询任意数据的次数:n次(B+树的高度)

索引分类:

主键索引: 不能重复+NOT NULL

单值索引: 单列,一个表可以有多个单值索引

唯一索引: 唯一索引不能重复

复合索引: 多个列构成(相当于二级目录)

创建索引:

方式一:

CREATE 索引类型 索引名 ON 表(字段)

单值:

​ CREATE INDEX dept_index ON tb(dept);

唯一:

​ CREATE unique INDEX name_index ON tb(name);

复合:

​ CREATE INDEX dept_name_index ON tb(dept,name);

方式二

alter table 表名 索引类型 索引名(字段)

单值:

​ ALTER TABLE tb ADD INDEX dept_index(dept);

唯一:

​ ALTER TABLE tb ADD UNIQUE INDEX name_index(name);

复合:

​ ALTER TABLE tb ADD index dept_name_index(dept,name);

注意:如果一个字段是primary key,则字段默认是主键索引

查询索引

show index from 表名; #行的形式显示索引

show index from 表名 \G #列的形式显示索引

SHOW INDEX FROM tb;

删除索引:

drop index 索引名 on 表名

DROP INDEX name_index on tb;

SQL性能问题:

MYSQL查询优化其会干扰我们的优化

分析SQL性能执行计划EXPLAIN

explain可以模拟SQL优化器执行SQL语句,从而知道SQL状况

explain + SQL 语句

EXPLAIN SELECT * FROM tb;

id:查询编号

select_type 查询类型

table类型

partitions

type

possible_keys 预测使用的索引

key 实际使用的索引

key_len 实际使用索引的长度

ref 表与表之间的引用关系

rows 通过索引查到的数据个数

filtered

Extra 额外的信息

# 成绩表
CREATE TABLE cource(
cid int(3),
cname varchar(20),
tid int(3)
);
# 老师表
CREATE TABLE teacher(
tid int(3),
tname varchar(20),
tcid int(30)
);
# 老师证表
CREATE TABLE teacherCard(
tcid int(3),
tcdesc varchar(200)
);
INSERT INTO cource values(1,'java',1);
INSERT INTO cource values(1,'html',1);
INSERT INTO cource values(1,'sql',1);
INSERT INTO cource values(1,'web',1);

INSERT INTO teacher values(1,'tz',1);
INSERT INTO teacher values(1,'tw',2);
INSERT INTO teacher values(1,'tl',3);

INSERT INTO teacherCard values(1,'tzdesc');
INSERT INTO teacherCard values(2,'twdesc');
INSERT INTO teacherCard values(3,'tldesc');
# 查询课程编号为2或教师证件编号为3的老师信息
EXPLAIN SELECT * FROM teacher t  ,course c, teacherCard tc
WHERE t.tid = c.tid and t.tcid = tc.tcid
and (c.cid = 2 or tc.tcid=3);

ID值相同

  1. id值相同,从上往下 顺序执行。

  2. 表的执行顺序,跟着数据量变化,原理是笛卡尔积 t3-tc3-c4 tc3-c4-t6

  3. 数据量小的表优先查询

# 查询教授SQL课程的老师描述desc
# 1.多表连接形式,ID值是相同的
EXPLAIN SELECT tc.tcdesc FROM teacherCard tc, course c, teacher t 
WHERE c.tid = t.tid AND t.tcid = tc.tcid
AND c.cname='sql'
# 2.子查询形式,ID值是不相同的
EXPLAIN SELECT tc.tcdesc FROM teacherCard tc WHERE tc.tcid =(SELECT t.tcid FROM teacher t WHERE t.tid 
=(SELECT c.tid FROM course c WHERE c.cname = 'sql')
);
# 3. 子查询+多表
SELECT t.tname, tc.tcdesc FROM teacher t, teacherCard tc
WHERE t.tcid = tc.tcid AND t.tid = 
(SELECT c.tid FROM course c WHERE cname = 'sql');

ID值不同

ID值不同,ID值大的优先查询

本质:在嵌套查询时,先查内层,再查外层

ID值相同+ID不相同

ID值越大越优先

ID值相同,从上往下 顺序执行

select_type

PRIMARY :包含子查询SQL中的子查询(最外层)

SUBQUERY : 包含子查询SQL中的子查询(非最外层)

simple : 简单查询(不包含子查询、union)

union result: 哪些表之间存在union查询

union: from 子查询中出现table1 union table2,table2就是union

derived : 衍生查询(使用到了临时表 from)

​ a. 在FROM子查询中只有一张表

SELECT cr.cname FROM (SELECT * FROM course where tid in (1,2)) cr;

​ b.在FROM子查询中,如果有 table1 union table2,则table1就是derived,table就是union

EXPLAIN SELECT cr.cname FROM (SELECT * FROM course WHERE tid=1 UNION SELECT * FROM course WHERE tid =2 ) cr;

type

type索引类型、类型

对type进行优化的前提是:有索引

system>const>eq_ref>ref>range>index>all

其中system、const只是理想情况,实际上能达到ref>range

system(忽略):只有一条数据的系统表或衍生表只有一条数据的主查询–>只有一条数据的表或衍生表里只有一条数据

const :仅仅只能查到一条数据的SQL,用于Primary key或unique索引(查询类型与索引类型有关)

eq_ref :唯一性索引:对于每个索引键的查询,返回匹配唯一行数据(有且只能有一个,不能多、不能少),常见于唯一索引和主键索引

ref : 非唯一性索引,对于每个索引键,返回匹配的所有行(0行,多行)

range : 检索指定范围的行,where后面是一个范围查询(between and, <, >, >=, <=, in有时候会失效,转为all)

index :查询全部索引的数据

​ explain select tid from teacher; tid是索引,只需要扫描索引表,不需要所有表中所有的数据

all : 查询全部表中的数据

​ explain select cid from course; cid不是索引,需要全表所有,既需要所有表中的所有数据

posible_keys、key

posible_keys 可能用到的索引,是一种预测

key实际使用到的索引

key_len索引的长度

用于判断复合索引是否被完全使用

create table test_kl(
	name char(20) not null default ''
);
# 添加索引
alter table test_kl add index index_name(name);
explain select * from test_kl where name = '';
在mysql中utf8一个字符占三个字节,所有key_len=60=20*3;
alter table test_kl add column name1 char(20); # 可以为空
alter table test_kl add index index_name1(name1);

此时key_len=61,如果索引字段可以为空null,则会使用1个字节用于标识。

drop index index_name on test_kl;
drop index index_name1 on test_kl;

#增加一个复合索引
alter table test_kl add index name_name1_index(name,name1);
explain select * from test_kl where name1=''; # key_len=121
explain select * from test_kl where name=''; # key_len=60


alter table test_kl add column name2 varchar(20); #变长字段
alter table test_kl add index name2_inex(name2);
explain select * from test_kl where name2='';
# 此时key_len=63= 20*3 + 1(null) + 2 (标识可变长度)

utf8:1个字符3个字节

gbk:一个字符2个字节

latin:1个字符1个字节

ref

作用:指明当前表所参照的字段。

select … where a.c = b.x;

若:b.x是常亮,const

若:b.x是其他,引用

rows

被索引优化查询的数据个数

select * from course c, teacher t where c.tid = t.tid
and t.tname='tz';

Extra

常见值:

​ 1. using fileSort:性能消耗大,需要‘额外’的一次排序(查询)

对于单索引:

​ 如果排序和查找是同一字段,不会出现using filesort

​ 如果排序和查找不是同一个字段就会出现using filesort

复合索引:不能跨列(最佳左前缀)

​ where和order by 按照复合索引的顺序使用,不能跨列或无序使用

  1. using temporary:性能消耗大,用到了临时表,常见于order by语句中

  2. using index:性能提升,索引覆盖(此SQL查询,不读取源文件,只从索引文件中获取数据(不需要回表查询))

    用到的列,全部都在索引中,就是索引覆盖

    ​ 会对possible_keys和key造成影响。

    ​ a.如果没有where,则索引只出现在key中

    ​ b.如果有where,则索引出现在key和possible_keys中

  3. using where:需要回表查询

    age是索引列,但name不是,select age,name from user where age > 18;SQL语句必须回表查Name

  4. using impossible where:where子句永远为false

    select * from test02 where a1=‘x’ and a1=‘y’;

  5. using join buffer : MYSQL引擎使用了连接缓存

using filesort样例

create table test02(
  a1 char(3),
  a2 char(3),
  a3 char(3),
  index idx_a1(a1),
  index idx_a2(a2),
  index idx_a3(a3)
);
# 1. 单索引情况
# Extra值 : using where
explain select * from test02 where a1='' order by a1;

# Extra值 : using where;using filesort
explain select * from test02 where a1='' order by a2;

drop index indx_a1 on test02;
drop index indx_a2 on test02;
drop index indx_a3 on test02;

# 复合索引
alter table test02 add index idx_a1_a2_a3(a1,a2,a3);
# a1 a3跨列了
explain select * from test02 where a1='' order by a3;
# a2 a3 也跨列了
explain select * from test02 where a2='' order by a3;
# a1,a2不跨列
explain select * from test02 where a1='' order by a2;

using temporary样例

# 没有临时表的情况
select a1 from test02 where a1 in ('1','2','3') group by a1;
# 有临时表的情况,就会出现 using temporary
select a1 from test02 where a1 in ('1','2','3') group by a2;

解析过程
from ...on ... join... where... group by... having... select distinct... order by... limit

select * from test03 where a2=2 and a4=4 group by a2,a4; # 没有出现using temporary
select * from test03 where a2=2 and a4=4 group by a3;# 出现了using temporary,因为出现了临时表

using index样例

# 用到的列都在索引中,就是索引覆盖
select id from user where id > 10;



create table test03(
  a1 int(4) not null,
  a2 int(4) not null,
  a3 int(4) not null
);
alter table test03 add index idx_a1_a2_a3_a4(a1,a2,a3,a4);
# 索引得到使用(WHERE)顺序与复合索引顺序一致、推荐写法
explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a3=3 and a4=4;
# 虽然编写的顺序和索引顺序不一致,但SQL在真正执行前,经历过了SQL优化器的调整,结果与上条SQL一致
explain select a1,a2,a3,a4 from test03 where a4=4 and a1=1 and a2=2 and a3=3;


# using index,用到了a1和a2索引,不需要回表查询
# using where a4跨列使用,造成索引失效,需要回表查询
通过key_len=8=4+4校验,使用了a1和a2索引
索引顺序为 a1,a2,a3,(a4失效)
explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a4=4 order by a3;

# filesort 多了额外的排序,不要跨列使用(where和order拼起来不要跨列使用)
索引顺序是a1,a3(跨列了)(a4失效)
explain select a1,a2,a3,a4 from test03 where a1=1 a4=4 order by a3;

explain select a1,a2,a3,a4 from test03 where a1=1 a4=4 order by a2,a3; # where和order by拼接起来,是按顺序的

1.如果(a,b,c,d)复合索引和使用顺序全部一致,则复合索引全部使用

2.<如果部分一致(且不跨列使用),则在使用时部分使用

优化案例

单表优化

create table book(
  bid int(4) primary key,
  name varchar(20) not null,
  authorid int(4) not null,
  pulibcid int(4) not null,
  typeid int(4) not null
);
insert into book values(1,'tjava',1,1,2);
insert into book values(2,'tc',2,1,2);
insert into book values(3,'wx',3,2,1);
insert into book values(4,'math',4,2,3);
commit;


# 查询authorid=1且typeid为2或3的bid
explain select bid from book where typeid in(2,3) and authorid =1 order by typeid desc;
# type=all、Extra=using where,using filesort

优化:加索引
alter table book add index idx_bta(bid,typeid,authorid);
再查询
# type=index、	Extra=using where,using filesort,using index

根据SQL实际解析的顺序,调整索引顺序(fromselect),所以索引顺序为(typeid,authorid,bid)合适
drop index idx_bta on book;
alter table book add index_idx_bta(typeid,authorid,bid);
再查询
# type= index、	Extra=using where,using index

再优化(in查询容易失效,所以type放在最后)
drop index idx_bta on book;
alter table book add index_idx_bta(authorid,typeid,bid);
再查询
# type= ref、	Extra=using where,using index                                                                                

a.索引不能跨列使用(最佳左前缀),保持索引的定义和使用的顺序一致性

b.索引需要逐步优化

c.讲含in的范围查询放到where条件的最后,防止失效

双表优化

create table teacher2(
	tid int(4) primary key,
  cid int(4) not null
);
insert into teacher2 values(1,2);
insert into teacher2 values(2,1);
insert into teacher2 values(3,3);
commit;
create table course2(
	cid int(4) ,
  cname varchar(20)
);
insert into course2 values(1,'java');
insert into course2 values(2,'python');
insert into course2 values(3,'kotlin');
commit;

select * from teacher2 t left outer join course2 c on t.cid = c.id where c.cname = ‘java’;

如何对这条SQL语句进行优化呢?索引往哪张表加?

小表驱动大表|索引要建立再经常使用的字段

数据量小的放外层,数据量大的放内层

一般情况对于左外连接,给左表加索引,右外连接,给右表加索引

编写where … on t.cid=c.cid时,将数据量小的表放在左边(假设此时t表数据量小),SQL语句中,t.cid字段使用频繁,因此给该字段加索引

explain select * from teacher2 t left outer join course2 c on t.cid = c.id where c.cname = 'java';

table t type= all、	Extra=
table t type= all、	Extra=using where,using join buffer
-------------------------------
# 给t.cid加索引
alter table teacher2 add index index_teacher2_cid(cid);
再执行SQL
table t type= index、	Extra=using index 
table c type= all、	Extra=using where,using join buffer
-------------------------------
alter table course2 add index index_course2_cname(cname);
再执行SQL
table c type= ref、	Extra=using where
table t type= ref、	Extra=using index

多表优化

a.小表驱动大表
b.索引建立在经常查询的字段

索引失效原则

  1. 复合索引

    a. 复合索引,不要跨列或无序使用(最佳左前缀)

    b. 尽量使用全索引匹配(对复合索引按顺序完完全全匹配)

    c. 使用in 进行查询时,也可能回导致索引失效

  2. 不要在索引上进行任何操作

    a.计算、函数、类型转换,都会导致索引失效

    b.对于复合索引

    ​ 左侧失效,右侧全部失效

    ​ 右侧失效,左侧任然有效

    c.复合索引不能使用不等于(!=)或is null(is not null),否则自身及其右侧全部失效。

    d.复合索引中有(> ),则自身和右侧索引全部失效

一般而言:范围查询( > < in)之后的索引失效,所以要尽量使用索引覆盖(using index)

3.SQL优化是一种概率层面上的优化,至于是否实际使用了优化,需要通过explain进行推测。

​ 原因是:服务层中有SQL优化器,会影响优化

  1. like尽量以‘‘常量’开头,不要以’%'开头,否则索引失效,如果必须使用like ‘%’,可以使用索引覆盖,挽救一部分。

  2. 尽量不要使用类型转换(显示、隐示),否则索引失效

  3. 尽量不要使用or,否则索引失效

    explain select * from teacher where tname=’’ or tcid>1;将or左侧的tname失效了。

优化方法

exist、in、order by 优化

select … from table where exist/in(子查询);

1.如果主查询的数据量大,用IN

2.如果子查询的数据量大,用exist

exist语法:将子查询结果,放到子查询结果中进行条件校验(是否有数据),如果复合校验,保留数据。

​ select tname from teacher where exists (select * from teacher);

​ 等价于

​ select tname from teacher;

in

select … from table where tid in (1,3,5);

select * from A where id in (select id form B);

order by

using filesort有两种算法:双路排序、单路排序(根据I/O次数)

​ MYSQL4.1之前,默认使用 双路排序扫描两次磁盘,第一次:从磁盘读取排序字段(order by的字段,buff缓冲区中进行排序)),第二次,扫描其他字段(select后的字段)

​ MYSQL4.1之后,默认使用 单路排序(只读取一次(全部字段),在buffer中进行排序),单路排序不一定真的一次I/O,也可能是多次I/O,因为数据量特别大,无法将所有字段的数据一次性读取完毕,需要‘‘分片读取、多次读取’’

注:单路排序比双路排序,比双路排序占用更多的buffer,单路排序时,如果数据大,可以调大buffer容量大小

---------设置buffer容量大小-------------

set max_length_for_sort_data = 1024; #单位是byte

如果max_length_for_sort_data值太低,会自动从单路–>双路排序(太低:需要排序的列的总大小超过了max_length_for_sort_data )

提高order by 查询策略

a.提高使用单路、双路,调整buffer容量大小

b.避免使用select *…

c.复合索引不要跨列使用,避免using filesort

d.保证全部的排序字段:排序一致性(都是升序、降序)

SQL排查---->慢查询日志

MYSQL 提供的一种日志记录,用于记录MYSQL中响应时间超过阀值的SQL语句(long_query_time,默认10秒)

慢查询日志默认是关闭的: 开发调优时打开,最终部署时关闭

检查是否开启了慢查询日志

show variables like ‘%slow_query_log’

临时开启慢查询日志

set global slow_query_log=1;

永久开启慢查询日志

/etc/my.cnf˙的mysqld中追加

set global slow_query_log=1;

set global slow_query_log_file=/日志文件路径;

查看慢查询阀值

show variables like ‘%long_query_time%’

临时设置阀值

set global long_query_time=5; #修改完毕后,重新登录生效(重启MYSQL服务后失效)

永久设置阀值

/etc/my.cnf˙的mysqld中追加

long_query_time=3

查询超过阀值的SQL

show global status like ‘%slow_queries%’;

(1)慢查询的SQL被记录在了日志中,因此可以通过查看日志文件,查看具体的慢SQL

(2)通过mysqldumpslow工具查看SQL

s:排序方式 r:逆序 l:锁定时间 g:正则表达式

—获取返回记录组最多得的3个SQL

​ mysqldumpslow -s -r -t 3 /日志文件路径

—获取访问次数最多得的3个SQL

​ mysqldumpslow -s c -t /日志文件路径

—按时间排序,前10条包含left join 查询语句

​ mysqldumpslow -s t -t 10 -g ‘left join’ /日志文件路径

分析海量数据

模拟海量数据

# 模拟海量数据
create table dept(
	dno int(5) primary key default 0,
  dname varchar(20) not null default '',
  loc varchar(30) default ''
)engine=innodb default charset=utf8;
create table emp(
	eid int(5) primary key,
  ename varchar(20) not null default '',
  job varchar(20) not null default '',
  deptno int(5) not null default 0
)engine=innodb default charset=utf8;
# 存储函数插入海量数据
	#1.创建存储函数 randstring(6)随机产生6个长度字符串
	delimiter $ #规定结束符,防止;造成语义中断
	create function randstring(n int) returns varchar(255)
	begin
		declare all_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(all_str,FLOOR(rand()*52+1),1)  );
			set i=i+1;
		end while;
		return return_str;
	end $
#查看慢日志与创建存储过程/函数是否冲突
show variables like '%log_bin_trust_function_createors%'
# 临时解决
set global log_bin_trust_function_createors=1;
# 2.产生随机整数
create function ran_num() retuns int(5)
begin 
	declare i int default 0;
	set i = floor(rand()*100);
	return i;
end $
# 3插入海量数据
# 3.1通过存储过程插入 emp表
create procedure insert_emp(in eid_start int(10) ,in data_times int(10))
begin 
	declare i int default 0 ;
	set autocommit = 0; # 关闭自动提交
	repeat 
		insert into emp values(eid_start+i,randstring(5),'other',ran_num());
		set i = i+1;
		until i=data_times
	end repeat;
	commit;
end $
# 3.2 通过存储过程插入 dept表
create procedure insert_dept(in dno_start int(10),in data_times int(10))
begin 
declare i int default 0;
set autocommit = 0; # 关闭自动提交
	repeat 
		insert into dept values(dno_start+i,randstring(6),randstring(8));
		set i = i+1;
		until i=data_times
	end repeat;
	commit;
end$
# 将终结符定义为;
delimiter ;
# 3.3开始插入
call insert_emp(1000,800000);
cal insert_dept(10,30);

分析海量数据

show profiles;   # 默认关闭
show variables like '%profiling%'; # 查看是否关闭
set profiling = on;  # 打开,会记录所有profiling 打开之后,全部SQL查询所花费的时间
show profile all for query上一步查询的SQL的id,Query_ID
#查看cpu,io相关
show profile cup,block io for query上一步查询的SQL

全局查询日志

记录开启之后的全部SQL语句(调优、开发过程打开,最终部署要关闭)

show variables like '%general_log%'; # 查看是否打开
set global general_log=1; # 打开全局查询日志
---------将执行的所有SQL记录在表中
# 开启全局日志,开启后,记录所有SQL,会被记录到mysql.general_log表中
set global log_output='table'
select * from mysql.general_log;

---------将执行的所有SQL记录在文件中
# 设置将全部的SQL记录到文件中
set global log_output='file' ;
set global general_log_file=/路径;

锁机制

解决因资源共享,而造成的并发问题

分类:

​ 操作类型:

​ a.读锁(共享锁):对同一个数据,多个读操作可以同时进行,互不干扰

​ b.写锁(互斥锁):当前写操作没有完毕,则无法进行其他的读锁、写锁

​ 操作范围:

​ a.表锁:一次性对一张表整体加锁,MyISAM存储引擎用表锁,开销小、加锁快、无死锁,但锁的范围大,容易锁冲突,并发度低

​ b.行锁:一次性对一条数据加锁,InnoDB存储引擎使用行锁,开销小,加锁慢,容易发生死锁,所得范围小,不易发生锁冲突,并发度高(很少见概率高并发问题:脏读、幻读、不可重复读、丢失更新)

​ c.页锁:

示例:表锁

#表锁
create table tablelock(
	id int primary key auto_increment,
  name varchar(20)
)engine myisam;   #表锁
insert into tablelock (name) values('a1');
insert into tablelock (name) values('a2');
insert into tablelock (name) values('a3');
insert into tablelock (name) values('a4');
insert into tablelock (name) values('a5');
commit;
--增加锁
# lock table 表 read/write , 表2 read/write....
# show open tables; # 查看加锁的表
--释放锁
unlock table 表名;


--读锁
# 会话session0  # 会话:每一个访问数据的dos命令行,数据库客户端工具,都是一个会话
lock table tablelock read;
select * from tablelock;  -- 读OK
delet from tablelock where id = 1;  -- 不能写(增删改)

select * from emp;  --读,不可以
delete from emp where eno = 1; ---写,不可以
---------------------------------
如果一个会话,对A表加了read锁,则该回话跨域对A表进行读操作,不能进行写操作,且该回话不能对其他表进行读、写操作
既:如果给A表加了读锁,则当前会话只能对A表进行读操作
---------------------------------
# 会话session1
select * from tablelock; --读可以
delete from tablelock where id=1; ---写,会等待,只到读锁解锁

select * from emp; --可以读
delete from emp where eno = 1; --可以写
---------------------------------
会话0对A表加了锁,其他会话的操作:
	a.可以对其他表(A表以外的表)可以进行读、写操作
	b.对A表可以读,但是写的话需要等待释放锁
---------------------------------




--写锁
会话0
	lock table tablelock write;
	当前会话0,可以对加了写锁的表进行任何操作(CRUD),但是不能操作(CRUD)其他表
会话1
	其他会话0可以对加写锁的表,进行增删改查的前提是:等待会话0释放写锁

MyISAM表级锁的锁模式

MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁

在执行更新操作(DML)前,会自动给涉及的表加写锁

所有对MyISAM表进行操作有,如下情况

a.对MyISAM表进行读操作(加读锁),不会阻塞其他进程(会话)对同一个表的读请求,但会阻塞对同一个表的写操作(加写锁),只有当读锁释放后,才会执行其他进行的写操作

b.对MyISAM表的写操作(加写锁),会阻塞其他进程(会话)对同一个表的读和写操作,只有当写操作释放后,才会执行其他进程的读写操作。

分析表锁定

show open tables; 查看那些表加了锁,1代表被加了锁

show status like ‘table%’; 分析表锁定的严重程度

​ Table_locks_immediate即可能获取到的锁

​ Table_locks_waited需要等待的表锁数(如果值越大,说明存在越大的锁竞争)

一般建议:Table_locks_immediate/Table_locks_waited>5000,建议采用InnoDB引擎,否则MyISAM引擎

示例:行锁

create table linelock(
	id int(5) primary key auto_increment,
  name varchar(20)
)engine=innodb;
insert into linelock(name) values('1');
insert into linelock(name) values('2');
insert into linelock(name) values('3');
insert into linelock(name) values('4');
insert into linelock(name) values('5');
set autocommit;

会话0  写操作
	insert into linelock values('6');  --会话没有提交,时间点:1
会话1  写操作,相同的数据
	update linelock set name='ax' where id = 6; --时间点:2,更新时发现此数据被加锁了,直到其它会话将该锁释放后(commit、rollback),才能操作
	
	
对行锁情况
		1.如果会话x对某条数据a进行DML操作(研究是:关闭了自动commit情况下),则其他会话必须等待会话x结束事务后,才能对数据a进行操作
		2.表锁通过unlock tables;解锁 或通过事务解锁
			行锁通过事务解锁
			
行锁,操作不同数据
会话0		写操作
	insert into linelock values('8'); --会话没有提交,时间点:1
会话1 	写操作,不同的数据
	update linelock set name='ax' where id = 5;  --时间点:2
行锁,一次锁一行数据,因此操作不同的数据,互不干扰。

行锁变表锁

行锁注意事项:

a.如果没有索引,则行锁会转为表锁

​ show index from linelock;

​ alter table linelock add index idx_linelock_name(name);

会话0 写操作

​ update linelock set name=‘ai’ where name = ‘3’; --时间点:1

会话1 写操作,不同的数据

​ update linelock set name=‘aiX’ where name = ‘4’; --时间点:2

--------------------------单引号去掉之后—>没有索引

会话0 写操作

​ update linelock set name=‘ai’ where name = 3; --时间点:1

会话1 写操作,不同的数据

​ update linelock set name=‘aiX’ where name = 4; --时间点:2

可以发现,数据被阻塞了(加锁)

—原因:发生类型转换,则索引失效,因此此次操作,从2行锁转为表锁

行锁一种特殊情况:间隙锁,值在范围内,但却不存在

select * from linelock;
-- 如果在(1,9)中没有id=7的数据
update linelock set name='x' where id > 1 and id <9; --自动给id为7加一个间隙锁
此时另一个会话insert into linelock value(7,'7');
间隙:mysql会自动给间隙加锁--->间隙锁(行锁)

行锁:如果有WHERE,则实际加锁的范围,就是where后面的范围,(不是实际的值)

行锁:

InnoDB默认采用行锁

缺点:比表锁性能消耗大

有点:并发能力强,效率高

因此,高并发用InnoDB,否则用MyISAM

行锁分析

show status like '%innodb_row_lock%'
    Innodb_row_lock_current_waits当前正在等待的锁的数量
    Innodb_row_lock_time等待总时长,从系统启动到现在一共等待的时间
    Innodb_row_lock_time_avg平均等待时长,从系统启动到现在平均等待的时间
    Innodb_row_lock_waits等待次数,从系统启动到现在一共等待的次数

通过for update对Query语句进行枷锁

for update进行加锁

select * from linelock where id = ‘2’; --自动提交

select * from linelock where id = ‘2’ for update; —将select语句进行加锁

关闭自动提交方式

set autocommit=0;

begin;

start

type= index、 Extra=using where,using index

普通索引index、unique索引

MYSQL编码格式

查看编码格式

​ show variables like ‘%char%’;

发现编码为latin,需要统一设置为utf-8

etc/my.cnf文件

​ [mysql]内 (服务端MYSQL)

​ 添加 default-character=utf8

​ [client] (客户端MYSQL)

​ 添加 default-character=utf8

​ [mysqld]

​ character_set_server-utf8

​ character_set_client=utf8

​ collation_server=utf8_general_ci

x修改编码,只对之后的数据库生效

MYSQL清屏

​ system clear;

主从复制

集群:

​ 1.负载均衡

​ 2.失败迁移

如果要远程连接数据库,则需要授权远程访问

A远程访问B,则在B计算机的MYSQL下执行命令

GANT ALL PRIVILEGES ON *.* TO ‘root’@’%’ IDENTIFIED BY ‘root’ WITH GRANT OPTION;

FLUSH PRIVILEGES;

实现主从同步(主从复制)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IyQ9EIqM-1626490742618)(/Users/wujiewei/Desktop/wcw/01.03.主从同步.png)]

-- 同步核心   二进制日志binlog
1. master将改变的数据,九记录在本地的二进制日志文件(binary log) 
2.slaver将master的binary log拷贝到自己的relay log(中继日志文件)中
3.中继日志事件,将数据读取到自己的数据库之中。

MYSQL主从复制是异步的,串行化、有延迟
	master:slave=1:n

配置
	windows(mysql: my.ini)
			my.ini
				server-id标识
				log-bin=".../mysql-bin"路径		二进制日志文件路径
				log-error=".../mysql-error"路径		错误记录文件
				binlog-ignore-db=数据库名称		主从同步忽略的数据库
				binlog=do-db=数据库名称				主从同步-同步的数据库名称
				
				主机授权哪台计算机,是自己从计算机
				GANT PRIVILEGES slave,reload,super ON *.* TO 'root'@'从计算机IP地址' IDENTIFIED BY 'root';
        查看主数据库的状态
        show master status;
	linux(mysql: etc/my.cof)

MYSQL优化官网

https://dev.mysql.com/doc/refman/8.0/en/optimization.html

show index from book;

explain select * from book authorid = 1 and typeid =2;

你可能感兴趣的:(JAVA实习,mysql,mysql优化)