mysql 之优化
# ### part1 : sql语句优化
# (1) mysql 执行流程
客户端:
发送链接请求,然后发送sql语句
服务端:
1.连接层: 提供和客户端链接的服务
show processlist;查看所有登录到mysql的用户0
2.服务器:
(1)提供各种用户使用的接口(增删改查)
(2)提供sql优化器(mysql query optimizer)
(发现sql语句执行效率非常慢,会经过优化器优化,然后把优化的结果进行执行)
3.存储引擎:
把得到的数据进行保存,
innodb : 支持事务处理,支持行锁,支持高并发
myisam : 支持表锁,不支持并发.
把数据存储在文件或者内存当中
"""
create table ceshi_table(
id int primary key auto_increment,
name varchar(255)
)engine = myisam auto_increment=2 charset = utf8;
"""
4.文件和日志
产生日志文件 binlog 二进制文件
# (2) sql 卡顿原因
硬盘读写数据,io延迟高,sql语句性能低,索引失效,导致sql执行时间长
编写过程:
select .. from .. join on where .. group by .. having .. order by limit
解析过程:
from .. join on where group by having select distinct order by limit ..
# (3) 索引
# 索引(index)概念:
是一个树状的数据结构,即(B树结构,分支节点>2)
相当于字典的目录,功效是加快查询速度;
常用树: B树(balance-tree) , 二叉树,红黑树,hash树
# 树节点:
根节点(最顶级节点)
分支节点(父节点,子节点)
叶子节点(最后一层存储数据的节点)
树的高度(树的层级,理想是三层)
[b+] : 在相邻的叶子节点上,加入了双向链表(指针),当前叶子节点不但保存当前值,还保存了下一个叶子节点的地址[小范围数据,查询速度很快]
[b*] : 在相恋的分支节点上,加入了双向链表(指针),当前分支节点不但保存当前值,还保存了下一个分支节点的地址[在大范围里,找数据速度加快]
# (4) innodb 和 myisam 的索引结构
(1) 聚集索引(聚簇索引) [innodb存储引擎的特点,myisam没有]
如果有主键,自动以主键作为聚集索引列(字段)
如果没有主键,选择唯一键
都没有,自动生成隐藏聚集索引,该字段是6个字节,类型为长整型;
分支节点是存储下一层节点的最小值,用来划分范围,追求的矮胖的数据结构
在数据量变大的时候,尽量在树层级高度不变的情况下,横向发展,好处:可以减少io次数,提升查询效率
真实的数据,直接在叶子节点上存储,所以速度快.
(2) 辅助索引(非聚簇索引,二级索引,普通索引)
对这一列的数据先排序,划分区间,把索引值分布到叶子节点上
辅助索引存储的是加了索引的字段值和对应映射的主键id(primary key=>pk),没有存储真实的数据
通过找出这个主键id,再去聚集索引树状结构中查询真实数据;
辅助索引辅助聚集索引找数据的,辅助索引叶子节点重复值过多,会导致回表的次数增多,随机产生的io减慢查询效率
如果想要解决重复问题,使用联合索引,更加精确找出对应唯一的那个id.
(3) 两者区别:
myisam 和 innodb 使用的索引数据结构都是B+树,但是在叶子节点上存储的数据不同
innodb的文件结构中只有.frm 和 .ibd , 直接把数据存在了叶子节点上
myisam的文件结构中有.frm .myd .myi , 叶子节点上存储的索引列,通过索引列映射对应的地址,在去通过这个地址找到实际的数据
innodb 一个表只有一个聚集索引,和多个辅助索引,排序速度更快
myisam 只能有多个辅助索引,没有聚集索引
(4) 性能优化:
利用索引查询时,速度很快,相反,增删改速度会变慢,会改变树状结构;
追求:让每一个分支节点存储的数据尽量小,减少树状结构纵向值高度上的增加
# ### part2 : 索引
# 1.常用索引种类:
普通索引(index)
-提高查询的效率
唯一索引:
-主键索引 primary key : 在创建主键约束的同时,创建索引(不为空,唯一)
-唯一索引 unique : 在创建唯一约束的同时,创建索引(允许为空,唯一)
联合索引:
-primary key() : 联合主键索引
-unique() : 联合唯一索引
-index() : 联合普通索引
# 2.常用索引的应用场景
编号int,
姓名varchar(255),
身份证号char(18),
电话char(11),
住址varchar(255),
备注信息: text,
姓:char(10)
名:char(10)
编号int, 主键
姓名varchar,可以使用普通索引
身份证号char, 唯一索引unique
电话char,唯一索引
备注信息:text 全文索引 , 可使用fulltext(全文索引) 多数情况下使用第三方软件Sphinx来运行
姓和名 ,通过来说一起查询,可以使用联合索引
# 3.常用的索引数据结构 hash树 与 B-Tree
hash类型的索引: 数据在内存中,通过键来获取值,查询单条数据最快,一个范围的数据慢
B-Tree类型的索引: b+数(理想层级三级),三层B树,理论上存放的数据量可以支撑百万条数据;
# 不同的存储引擎支持的索引种类
innodb : 支持事务,行级锁, 支持 B-Tree ,fulltext ,不支持hash类型索引结构
myisam : 支持表级锁,不支持事务 支持 B-Tree , fulltext ,不支持hash类型索引结构
memory : 不支持事务,支持表级锁 支持 B-Tree ,hash类型 ,不支持fulltext索引结构
# 4.建立索引
# (1) 方法1,建表的时候,创建索引 index 索引名(索引字段)
create table t1(
id int primary key,
name char(100),
index index_name(name)
);
# (2) 方法2.建表之后,创建索引 create index 索引名 on 表名(索引字段)
create table t2(
id int primary key,
name char(100)
);
create index index_name on t2(name);
# (3) 方法3.建表之后,创建索引 alter table 表名 add index 索引名(索引字段)
create table t3(
id int primary key,
email char(100)
);
alter table t3 add index index_email(email)
# (4) 删除索引
drop index index_email on t3
# 5.正确使用索引
alter table s1 add index index_id(id) / create index index_id on s1(id)
select count(*) from s1 where id = 5;
# 发现加了索引和不加索引时间差距较大
# 注意加了索引之后,ibd文件会表达
# (1) 把频繁作为搜索条件的字段作为索引,查单条数据,如果查询的是一个范围内的数据,不能命中索引
# 范围小的数据 表达范围的符号: id > < >= <= != like "xboy" between and in...
# (2) 选一个字段作为索引,这个列(字段)必须是区分度较高的字段
"""这个字段对应的值,如果出现了大量重复,在通过辅助索引查询的时候,会出现大量的随机id,增加聚集索引中的查询量,影响速度"""
"""区分度高的字段,推荐加上索引 ,必须系统会自动给primary key 和 unique 两个约束自动加索引"""
create index index_name on s1(name);
select count(*) from s1 where name = "xxxx"
select count(*) from s1 where name = "xboyww" # 不推荐使用区分度不高的字段加索引
# (3) 条件中,不能让索引字段参与计算,不能命中索引
select * from s1 where id = 1000
select * from s1 where id*3 = 3000
# (4) 条件中含有and , sql语句会经过优化器优化.
# 1.如果有and 相连,找到第一个有索引的并且树的高度最矮的字段进行优化
select count(*) from s1 where email = "xboyww1000@oldboy"
select count(*) from s1 where email = "xboyww1000@oldboy" and id = 1000
select count(*) from s1 where name = "xboyww" and email = "xboyww1000@oldboy" and id = 1000
# 2.如果有or相连,没有优化,所有语句从左到右执行,索引会失去意义
select count(*) from s1 where id = 1000 or email = "xboyww1000@oldboy";
# (5) 联合索引 最左前缀原则 index(字段1,字段2 .... )
drop index index_id on s1;
drop index index_name on s1;
create index union_index on s1(first_name,last_name);
select count(*) from s1 where first_name="王6" and last_name="文6" # 命中索引
select count(*) from s1 where last_name="文6" and first_name="王6" # 命中索引
# select count(*) from s1 where last_name="文6"; 不会命中索引,被标记的first_name不存在
select count(*) from s1 where first_name="王6" and gender = "man";
select count(*) from s1 where first_name="王6" and gender = "man" and name = "xboyw11w";
# 最左前缀原则: 被标记的MUL这个字段存在,就命中索引
first_name + name + gender + ... (该字段存在即可)
# (6) 其他
使用了函数不能命中索引
select count(*) from s1 where reverse(first_name) = "文2";
类型不匹配不能命中索引
select count(*) from s1 where first_name = 90;
# ### part1 索引树高度
# 1.表的数据行
数据量越大,树的高度就会变高,理论上3层索引树高度可以支持百万级别数据量
解决:可以使用分表,分库,数据库缓存,解决数据过大问题
# 2.索引键值过长
该索引字段存储数据太大,每个叶子节点默认可以存储16k,超过范围增加叶子节点,
解决:前缀索引 (截取前10个长度)
# 3.数据类型
char(定长,多余数据用空格补位) varchar(变长) 从数据类型角度,char比varchar快
从数据结构这个角度上看,varchar更加合理
选择合理的类型;
# ### part2 执行计划分析
""" desc/explain + sql """
# 执行计划:在一条sql执行之前,制定执行的方案
desc select * from s1;
# 1. select_type
SIMPLE 代表的是简单查询(不包括子查询,union)
primary sql嵌套中的主查询(最外层)
subquery sql嵌套中的子查询(非最外层)
derived 衍生查询(把子查询结果作为一张临时表)
# 2.table
在多表,子查询的时候,关注出现问题的那张表是谁
# 3.type
# 把执行计划的类型,优化级别从低到高,前提都有索引,至少达到range ,ref;
all < index < range < ref < eq_ref < const < system
# 1.all 全表扫描 (不走索引)
(1)在大范围内查询 > < >= <= != between .. and in not in like "%a%"
(2)where条件中有计算,有函数
(3)数据类型不匹配(隐式转换)
(4)索引失效,数据信息过旧,在发生树状结构变更的时候,可能产生索引对不上实际数据的情况,没有命中索引.
# 2.index 全索引扫描
"""扫描整个索引树,才能获取到数据,失去索引意义"""
desc select count(*) from s1; # index
desc select * from s1 where email = "xboyww2@oldboy"; # all
# 3.range 索引范围扫描(注意点:如果范围过大,不能命中索引)
desc select * from s1 where id < 10; # type => range
desc select * from s1 where id < 1000000; # type => ALL
desc select * from s1 where id between 1 and 10; # type => range
desc select * from s1 where id between 1 and 1000000; # type => all
desc select * from s1 where email like "%w%"; # type => all
desc select * from s1 where email like "w%"; # type => range
"""
注意:where条件中,索引列和如下符号配合
> < >= <= != between .. and in not in like "%a%"
如果范围过大,不能命中索引
如果范围适当,可以命中索引
"""
# or 和 in 语句可以进行优化的,
desc select * from s1 where id in (1,2);
"""优化:union all比 union速度快,union在合并数据之后,多了一步去重操作 """
desc select * from s1 where id = 1
union all
select * from s1 where id = 2;
desc select * from s1 where id = 1
union
select * from s1 where id = 2;
# 4.ref 普通索引查询(非唯一)
desc select * from s1 where email = 'xboyww2@oldboy';
# 5.eq_ref 唯一性索引(联表)
"""要求:应用在多表联查中,关联字段只能是主键或者唯一索引,表之间是1对1的关系并且数据条数相同,查询具体的某个带索引的字段"""
desc select student1.class_id from student1,class1 where student1.class_id = class1.id
alter table student1 add unique(class_id) ; # 为student1的关联字段 添加唯一索引
alter table class1 add primary key(id); # 为关联表的id添加主键
delete from student1 where id = 3 # 让两个表之间的数据等长
desc select student1.class_id from student1,class1 where student1.class_id = class1.id # 搜索的字段,必须是索引字段
# 6.const:主键或者唯一索引(单表)
""" 针对primary key 和 unique 索引等值查询"""
desc select * from s1 where id = 1 # type => const
desc select * from s1 where id > 1 # type => range
# 7.system(了解):
"""只有一条数据的系统表 或 衍生表(子查询出来的临时表)只有一条数据主查询"""
# create table ceshi111(id int , name varchar(10));
# insert into ceshi111 values(1,"a");
# alter table ceshi111 add primary key(id);
# desc select * from ceshi111;
# desc select id from (select id from ceshi111) as t where id = 1
# 4.possible_keys : 可能用到的索引是谁
show index from s1;
# 5.key : 实际用到的索引是谁
# 6.key_len : 判断联合索引覆盖长度
预留一个字节,在没有not null 约束的时候,加上一个字节,标记是空还是非空
utf8 预留的最大字节数是4个字节,通常情况下,一个中文3个字节,一些个别生僻词4个字节存储
varchar 每次数据存储的时候,系统底层要额外预留2个字节
有not null 没有not null
tinyint 1 1+1
int 4 4+1
char(5) 5*4 5*4+1
varchar(5) 5*4+2 5*4+2+1
create table t100(
n1 int,
n2 int not null,
n3 char(5),
n4 char(5) not null,
n5 varchar(5),
n6 varchar(5) not null,
index index_n1(n1,n2,n3),
index index_n4(n4,n5,n6)
);
insert into t100 values(1,2,"a","b","aa","bb");
insert into t100 values(1,2,"a","b","aa","bb");
insert into t100 values(1,2,"a","b","aa","bb");
insert into t100 values(2,2,"a","b","cc","dd");
desc select * from t100 where n1=2 and n2=2 and n3="a";
n1=>5 n2=>4 n3=>21 => 30
# 没有命中索引
desc select * from t100 where n1=1 and n2=2 and n3="a";
# index(a,b,c) -> a, ab , abc 创建三个索引.
# 在创建联合索引的时候 实际是根据参数的不同,创建了不同的索引树,命中一个即可,符合最左前缀原则
# ### part2 事务处理的四项特征 ACID
A.原子性 :
同一个十五中可能有多条sql语句,要么全部成功,要么直接回滚,作为一个完整的整体,不能再分割的最小个体
C.一致性 :
a,i,d 都是为了保证数据的一致性才提出来的,比如约束,键,在插入数据时,必须按照约定条件才能插入,保证插入数据规则上的一致性
上升到事务中,防止意外情况导致数据不统一,比如脏读,幻读,不可重复读,最终要决定数据的同步一致
在上升到主从数据库,主数据库执行这条插入数据,从数据库一定执行,保证数据一致性
I.隔离性 :
lock+isolation锁,来处理事务的隔离界别,
一个事务和另外一个事务在工作过程中彼此独立,
如果同时更改同一个数据,因为锁机制的存在,先执行的先改,其他事务需要等待
D.持久性 :
把数据写到磁盘上,保证数据的持久化存储
# 隔离性: 隔离级别
begin;
执行SQL
commit;
rollback;
脏读: 没提交的数据被读出来了
不可重读: 前后多次读取,数据内容不一样(同一个会话中,在不进行修改的时候,永远只看到同样的一套数据)
幻读 : 前后多次读取,数据总量不一样
RU : 读未提交 : 脏读,不可重读,幻读
RC : 读已提交 : 防止脏读,会出现 不可重读和幻读
RR : 可重复读 : 防止脏读,不可重复读,可能会出幻读 (默认级别)
SR : 可串行化 : 什么都能防止(多个会话窗口同步,不能并发,性能差)
# 查询默认的隔离级别
select @@tx_isolation;
# 查询是否自动提交数据
select @@autocommit;
# [mysqld]
/etc/mysql/mysql.conf.d
nano mysqld.cnf
# 更改隔离级别
transaction_isolation = READ-COMMITTED
# 重启
service mysql restart
# 创建一张表
create table t1(id int , k1 char(10),k2 int);
insert into t1 values(1,"x",10);
insert into t1 values(1,"x",10);
insert into t1 values(2,"a",20);
insert into t1 values(2,"b",20);
insert into t1 values(3,"a",30);
insert into t1 values(3,"b",30);
# 1.脏读
# 2.不可重复读
"""针对于当前mysql会话窗口,不应该每次发生的结果都不一样,这破坏一致性原则,叫不可重读;"""
begin;
update t1 set k2 = 11 where id = 1;
select * from t1;
commit;
begin;
update t1 set k2 = 21 where id = 1;
select * from t1;
commit;
# 3.幻读
# 会话窗口1
begin;
update t1 set k2=100 where id>=1
# 会话窗口2
insert into t1 values(4,'c',40)
# 会话窗口1
commit 发现数据不一致,多出了很多数据
+------+------+------+
| id | k1 | k2 |
+------+------+------+
| 1 | x | 100 |
| 1 | x | 100 |
| 2 | a | 100 |
| 2 | b | 100 |
| 3 | a | 100 |
| 3 | b | 100 |
| 4 | c | 40 |
# 如何在RR级别下,彻底避免脏读,幻读,不可重读
在配置文件中 , 加入
autocommit=0 把rc隔离级别注释掉
service mysql restart
# 4.事务应用的技术(了解)
(1) RR级别下,解决不可重读
MVCC技术:多版本并发时,防止不可重复现象;
每次事务窗口开启时,都会生成一个最新版本的快照,然后去读取快照
(2) RR级别下,解决幻读(除了行级锁,表级锁,在记住下面两把锁,解决事务处理问题)
gap 间隙锁
next-lock 下一键锁
mysql 之优化的更多相关文章
- Mysql - 性能优化之子查询
记得在做项目的时候, 听到过一句话, 尽量不要使用子查询, 那么这一篇就来看一下, 这句话是否是正确的. 那在这之前, 需要介绍一些概念性东西和mysql对语句的大致处理. 当Mysql Server ...
- Mysql性能优化三(分表、增量备份、还原)
接上篇Mysql性能优化二 对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了.如果我拆成100个表,那么每个表只有10万条记录.当然这需要数据在逻 ...
- Mysql性能优化一
下一篇:Mysql性能优化二 mysql的性能优化无法一蹴而就,必须一步一步慢慢来,从各个方面进行优化,最终性能就会有大的提升. Mysql数据库的优化技术 对mysql优化是一个综合性的技术,主要包 ...
- 关于MySQL数据库优化的部分整理
在之前我写过一篇关于这个方面的文章 <[原创]为什么使用数据索引能提高效率?(本文针对mysql进行概述)(更新)> 这次,主要侧重点讲下两种常用存储引擎. 我们一般从两个方面进行MySQ ...
- [MySQL性能优化系列]提高缓存命中率
1. 背景 通常情况下,能用一条sql语句完成的查询,我们尽量不用多次查询完成.因为,查询次数越多,通信开销越大.但是,分多次查询,有可能提高缓存命中率.到底使用一个复合查询还是多个独立查询,需要根据 ...
- [MySQL性能优化系列]巧用索引
1. 普通青年的索引使用方式 假设我们有一个用户表 tb_user,内容如下: name age sex jack 22 男 rose 21 女 tom 20 男 ... ... ... 执行SQL语 ...
- 【MySQL】花10分钟阅读下MySQL数据库优化总结
1.花10分钟阅读下MySQL数据库优化总结http://www.kuqin.com2.扩展阅读:数据库三范式http://www.cnblogs.com3.my.ini--->C:\Progr ...
- MySQL性能优化:索引
MySQL性能优化:索引 索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序.数据库使用索引以找到特定值,然后顺指针找到包含该值的行.这样可以使对应于表的SQL语句执 ...
- 30多条mysql数据库优化方法,千万级数据库记录查询轻松解决(转载)
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- mysql 性能优化方向
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
随机推荐
- 7天教你精通变大神,学CAD关键还要掌握方法,纯干货新手要看
接触CAD初期是“痛苦”的,“煎熬”的,也是充满“成就”的. 痛苦是初学者怎么都不懂,需要学习的东西很多,整个过程是有些痛苦的. 煎熬也是每个求学阶段都会遇到的状态,眼睛会了,手不会,这个状态很难受. ...
- selinux disable
临时关闭: [root@localhost ~]# getenforceEnforcing [root@localhost ~]# setenforce 0[root@localhost ~]# ge ...
- 转载:关于STM32硬件I2C读写EEPROM代码实现原理的理解与总结
http://home.eeworld.com.cn/my/space-uid-716241-blogid-655190.html 一.I2C协议简介 I2C是两线式串行总线,用于连接微控制器及其外围 ...
- Error creating bean with name 'sqlSessionFactory' defined in class path resource [config/spring/applicationContext.xml]: Invocation of init method failed;
我报的错: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSes ...
- 使用EA将源码转化为类图
EA简介: EA 全名 Enterprise Architect,是一款著名的 UML 建模软件.在软件架构设计与逆向工程中具有重要作用.软件十分小巧(< 60MB ),并且有汉化破解版.推荐大 ...
- Redux使用
思想 应用中所有的state都以一个对象树的形式储存在一个单一的store中.唯一能改变state的办法是触发action,一个描述发生什么的对象.为了描述action如何改变state树,需要编写r ...
- 给Java0基础的五个学习的思路?
关于Java初学者来说,想学习Java教程,需求了解,根底打好才干学得更好,Java教程之学习Java的路线图的五个必经阶段,希望能对Java学习者有所帮忙. 第一个阶段-java根底阶段 1.jav ...
- WindowsOS下Nginx+PHP环境配置
Nginx 配置虚拟主机 在conf目录中的nginx.conf中最后一行前面加上 include vhost/*.conf; 在conf目录中添加一个文件夹vhost(此文件夹用来保存Nginx虚拟 ...
- angular6 升级到 angular7+ 最新Ng-zorro
angular7 出来有一段时间了,然后我们项目一直用的是angular6, 看到一直再用的Ng-Zorro 更新版本了,然后就觉得把目前的项目也升级一下把. 目前我本地cli版本是6.0.8我要把他 ...
- 前端优化,包括css,jss,img,cookie
前端优化,来自某懒观看麦子学院视频的笔记. 尽可能减少HTTP的请求数 使用CDN 添加Expirs头,或者Cache-control Gzip组件压缩文件内容 将CSS放在页面上方 将脚本放到页面下 ...