1.mysql架构与存储引擎

MysqlSlap测试工具


MysqlSlap是MySql的5.1.4版开始官方提供的压力测试工具

参数列表

参数 作用
—create-schema=name 指定测试的数据库名,默认是mysqlslap
—engine=name 创建测试表所使用的存储引擎,可指定多个
—concurrency=N 模拟N个客户端并发执行。可指定多个值,以逗号或者
—number-of-queries=N 总的测试查询次数(并发客户数×每客户查询次数),比如并发

是10,总次数是100,那么10个客户端各执行10个 | | —iterations=N | 迭代执行的次数,即重复的次数(相同的测试进行N次,求一 个平均值),指的是整个步骤的重复次数,包括准备数据、测 试load、清理 | | —commit=N | 执行N条DML后提交一次 | | —auto-generate-sql, -a | # 自动生成测试表和数据,表示用mysqlslap工具自己生成的 SQL脚本来测试并发压力。 | | —auto-generate-sql-loadtype=name | # 测试语句的类型。代表要测试的环境是读操作还是写操作还 是两者混合的。

取值包括:read (scan tables), write (insert into

tables), key (read primary keys), update (update primary keys), or mixed (half inserts, half scanning selects). 默认值是:mixed. | | —auto-generate-sql-addauto-increment | 对生成的表自动添加auto_increment列 | | —number-char-cols=name | 自动生成的测试表中包含N个字符类型的列,默认1 | | —number-int-cols=name | 自动生成的测试表中包含N个数字类型的列,默认1 | | —debug-info | 打印内存和CPU的信息 |

例如:
./mysqlslap -uroot -proot1234% —concurrency=500 —iterations=3 —number-char-cols=5 —numberint-cols=5 —auto-generate-sql —auto-generate-sql-add-autoincrement —engine=myisam,innodb — create-schema= ‘ enjoytest1’ —debug-info
image.png

mysql逻辑架构

image.png

连接层:

当mysql启动(MySQL服务器就是一个进程),等待客户端连接,每一个客户端连接请求,服务器都会新建一个线程
处理(如果是线程池的话,则是分配一个空的线程),每个线程独立,拥有各自的内存处理空间,但是,如果这个请求只是查询,没关系,但若是修改数据,很显然,当两个线程修改同一块内存是会引发数据同步问题的。
image.png

SQL处理层:

连接到服务器,服务器需要对其进行验证,也就是用户名、IP、密码验证,一旦连接成功,还要验证是否具有执行
某个特定查询的权限(例如,是否允许客户端对某个数据库某个表的某个操作)
image.png

缓存

MySQL缓存机制即缓存sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要再去解析、优化、执行sql

查看缓存相关配置
show variables like ‘%query_cache_type%’
设置缓存大小
SET GLOBAL query_cache_size = 4000;

解析查询

image.png
image.png

优化

Explain关键字:
在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。

id:选择标识符
select_type:表示查询的类型。
table:输出结果集的表
partitions:匹配的分区
type:表示表的连接类型
possible_keys:表示查询时,可能使用的索引
key:表示实际使用的索引
key_len:索引字段的长度
ref:列与索引的比较
rows:扫描出的行数(估算的行数)
filtered:按表条件过滤的行百分比
Extra:执行情况的描述和说明

image.png

存储引擎:

看你的mysql现在已经提供什么存储引擎
mysql>show engines
查看你的mysql当前默认的存储引擎
mysql>show variables like ‘%storage_engine%’;

MyISAM

MySql 5.5之前默认的存储引擎
MyISAM存储引擎由MYD和MYI组成

创建MyISAM引擎表语句
CREATE TABLE testmyisam(
name VARCHAR(255) DEFAULT NULL,
age INTEGER
)
engine=MyISAM

MyISAM引擎由MYD(数据文件)和MYI(索引文件)组成
image.png

特性:
并发性与表级锁:表级锁
支持全文检索
支持数据压缩:myisampack -b -f testmysam.MYI(压缩的索引文件)

适用场景:
非事务型应用(数据仓库,报表,日志数据)
只读类应用
空间类应用(空间函数,坐标)

Innodb

Mysql5.5以及以后版本默认存储引擎

表空间
mysql5.6之前默认为系统表空间
查看是独立表空间还是系统表空间:show variables like ‘%per_table%’;
innodb_file_per_table
ON:独立的表空间:tablename.ibd
OFF:系统表空间:ibdataX

系统表空间和独立表空间的区别:
系统表空间:无法简单的收缩文件大小,多个表操作同一个文件会产生IO瓶颈
独立表空间:可以通过optimize table收缩系统文件,独立表空间可以同时向多个文件刷新数据
建议使用独立表空间

Innodb特性:
支持事务
支持事务日志Redo log和Undo Log
Innodb支持行级锁(并发程度高)
适用场景:大多数OLTP应用

Innodb与MyISAM的区别:
image.png
1、MyISAM是非事务安全的,而InnoDB是事务安全的
2、MyISAM锁的粒度是表级的,而InnoDB支持行级锁
3、MyISAM不支持主外键,而InnoDB支持主外键
4、MyISAM支持全文类型索引,而InnoDB不支持全文索引
5、MyISAM相对简单,效率上要优于InnoDB,小型应用可以考虑使用MyISAM
6、MyISAM表保存成文件形式,跨平台使用更加方便


CVS

基本结构:
数据以文本方式存储在文件
.csv文件存储内容
.csm文件存储表的元数据如表状态和数据量
.frm表结构
image.png
特点:
以csv格式进行数据存储
所有列都不能为null的
不支持索引(不适合大表,不适合在线处理)
可以对数据文件直接进行编辑(保存文本文件内容)
image.png

Archive

组成
以zlib对表数据进行压缩,磁盘I/O更少数据存储在ARZ为后缀的文件中
image.png
特点:
只支持insert和select操作
只允许在自增ID列上加索引
image.png
适用场景:日志和数据采集应用

Memory

文件系统存储特点:也成为HEAP存储引擎,所以数据保存在内存中
支持HASH索引和BTree索引
所有字段都是固定长度varchar(10)=char(10)
不支持Blog和Text等大字段
Memory存储引擎使用表级锁
最大大小由max_heap_table_size参数决定

image.png
使用场景:hash索引用于查找或是映射表(邮编和地区的对应表)
用于保存数据分析中产生的中间表
用于缓存周期性聚合数据的结果表

memory数据易丢失,所以要求数据可再生

Ferderated

特点:
提供了访问远程MySql服务器上表的方法
本地不存储数据,数据全部放到远程服务器上
本地需要保存表结构和远程服务器的连接信息

使用:默认是禁止的,启用需要再启动时增加federated参数
image.png
使用场景
偶尔的统计分析以及手工分析

2.mysql锁

Mysql的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制
比如:
MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking)
innoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下采用行级锁

mysql中的锁
表级锁:开销小,加锁快;不会出现死锁;锁定颗粒度大,发生锁冲突的概率最高
行级锁:开销大,加锁慢;会出现死锁;锁定颗粒度最小,发生锁冲突的概率最低,并发度也最高
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

仅从锁的角度来说:
表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如OLAP系统

行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线
事务处理(OLTP)系统
很难笼统地说哪种锁更好,只能就具体的特点来说哪种锁更适合

MyISAM的表锁

Mysql的表级锁有两种模式:
表共享读锁(Table Read Lock)
表独占写锁(Table Write Lock)

请求锁模式是否兼容

当前锁模式 None 读锁 写锁
读锁
写锁

MyISAM共享读锁

给表加共享读锁语法:lock table 表名 read

1.lock table testmysam READ
启动另外一个session select * from testmysam 可以查询

2.insert into testmysam value(2);
update testmysam set id=2 where id=1;报错

3.在另外一个session中
insert into testmysam value(2); 等待

4.在同一个session中
insert into testdemo value(2,’2’,’3’); 报错
select * from testdemo ; 报错

5.在另外一个session中
insert into testdemo value(2,’2’,’3’); 成功
6.加索在同一个session 中
select s.* from testmysam s 报错 lock table 表名 as 别名 read;
查看 show status LIKE ‘table_locks_waited’ 表被锁过几次

MyISAM独占写锁
**
独占写锁语法:lock table 表名 write

1.lock table testmysam WRITE 在同一个session中 insert testmysam value(3);
delete from testmysam where id = 3 select * from testmysam

2.对不同的表操作(报错) select s.* from testmysam s insert into testdemo value(2,’2’,’3’);

3.在其他session中 (等待) select * from testmysam

总结:对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写的请求

对MyISAM表的读操作,不会阻塞当前session对表读,当对表进行修改会保存

  1. * 一个session使用LOCK TABLE命令给表f加了读锁,这个session可以查询锁定表中的记录,<br /> 但更新或者访问其他表都会提示错误;
  2. *另一个session可以查询表中的记录,但更新就会出现锁等待
  3. *对MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作
  4. *对MyISAM表的写操作,当前session可以对本表做CRUD,但对其他表进行操作都会报错

Innodb行锁

数据库的增删改操作默认都会加排他锁,而查询不会加任何锁
在mysql的InnoDB引擎支持行锁
行锁:
共享锁又称:又称读锁,对某一资源加共享锁,自身可以读该资源,其他人也可以读该资源(也可以再继续加共享锁,即 共享锁可多个共存),但无法修改。要想修改就必须等所有共享锁都释放完之后

排他锁又称:又称写锁。对某一资源加排他锁,自身可以进行增删改查,其他人无法进行任何操作

语法:
1.上共享锁的写法:lock in share mode
例如:select from 表 where 条件 lock in share mode;
2.上排他锁的写法:for update
例如:select
from 表 where 条件 for update;

注意:1.两个事务不能锁同一个索引。
2.insert,delete,update在事务中都会自动默认加上排它锁。
3.行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁

例子:
1. BEGIN select * from testdemo where id =1 for update 在另外一个session中 update testdemo set c1 = ‘1’ where id = 2 成功 update testdemo set c1 = ‘1’ where id = 1 等待

2.BEGIN update testdemo set c1 = ‘1’ where id = 1 在另外一个session中 update testdemo set c1 = ‘1’

  1. BEGIN update testdemo set c1 = ‘1’ where c1 = ‘1’ 在另外一个session中 update testdemo set c1 = ‘2’ where c1 = ‘2’ 等待

InnoDb表锁

和MyISAM差别不大
注意:开启一个新事务的时候会解锁表

1.先来看下行锁
第一个session中 select from testdemo where id =1 for update
第二个session select
from testdemo where id =1 lock in share mode
回到第一个session UNLOCK TABLES 并不会解锁
使用commit 或者 begin或者ROLLBACK 才会解锁

2.再来看下表锁 lock table testdemo WRITE 使用commit,
ROLLBACK 并不会解锁 使用UNLOCK TABLES

mysql锁的演示:

1.排他锁行锁的演示:
如图user表,使用innodb存储引擎
image.png
2.开启一个session,开启事务(注意MySQL中默认是一条sql就是一个事务)给id=1这一行加行锁,事务未提交,锁不会释放
image.png
3.开启另一个session,修改该条数据
image.png
出现如下情况,锁未释放,造成阻塞
image.png
4.第一个session提交事务,第二个session立即修改成功
image.png
image.png

物理结构修改

面试题:系统运行一段时间,数据量已经很大,这个时候系统升级,有张表A需要增加个字段
并发量白天晚上都很大,请问怎么修改表结构

面试考点
(修改表结构会导致表锁,数据量大量修改数据很长,导致大量用户阻塞,无法访问!)

操作步骤:
1.首先创建一个和你要执行的alter操作的表一样的空的表结构。
2.执行我们赋予的表结构的修改,然后copy原表中的数据到新表里面
3.在原表上创建一个触发器在数据copy的过程中,将原表的更新数据的操作全部更新到
新的表中来
4.copy完成之后,用rename table新表代替原表,默认删除原表

image.png

-pt-online-schema-change
下载安装perl环境 http://www.perl.org/get.html
下载percona-toolkit工具合集 https://www.percona.com/doc/percona-toolkit
ppm install DBI
ppm install DBD::mysql 安装mysql驱动依赖

perl F:\BaiduNetdiskDownload\vip\pt-online-schema-change h=127.0.0.1,p=root1234%,u=root,D=mysqldemo,t=product_info —alter “modify product_name varchar(150) not null default ‘’ “ —execute

3.事务

mysql为什么需要事务?

现在很多软件都是多用户,多程序,多线程的,对于同一个表可能同时有很多人在用,
为保持数据的一致性,所以提出了事务的概念。

A要B划钱,A的账户-1000元,B的账户就要+1000元,这两个update语句必须作为一个整体来执行
,不然A扣钱了,B没有加钱这种情况就很难处理。

什么存储引擎支持事务

1.查看数据库下面是否支持事务(innoDB支持)?
show engines;
2.查看mysql当前默认的存储引擎?
show variables like ‘%storage_engine%’;
3.查看某张表的存储引擎?
show create table 表名;
4.对于表的存储结构的修改?
建立innoDB表:Create table ……type=innoDB;Alter table table_name type=innoDB;

事务的特性

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性

原子性(acomicity):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做

一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关。

隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。

持久性(durability):持久性也成为永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就
应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

事务的隔离级别

脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需
锁住满足条件的行,解决幻读需要锁表

Mysql事务隔离级别表

事务隔离级别 脏读 不可重复读 幻读
读未提交
不可重复读
可重复读
串行化

mysql默认的事务隔离级别为(可重复读) repeatable-read

查看数据库的隔离级别
show variables like ‘%tx_isolation%’;

事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁、行锁、页面锁,从而锁住一些行;如果没有索引,更新数据时会锁住整张表

事务隔离级别为串行化时,读写都会锁住整张表

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,对于多数应用程序,优先考虑把数据库系统隔离级别设为Read Commited,它能够避免脏读取,而且具有较好的并发性能。

事务的语法

开启事务:
1.begin
2.SATRT TRANSACTION(推荐)
3.begin work

事务回滚:rollback

事务提交:commit

还原点:savepoint

查看是否自动提交事务
show variables like ‘%autocommit%’;

4.业务设计

三大范式

数据库设计的第一大范式:
数据库表中的所有字段都只具有单一属性
单一属性的列是由基本数据类型所构成的
设计出来的表都是简单的二维表

image.png
image.png

数据库设计的第二大范式:
主键的依赖关系要求表中只具有一个业务主键,也就是说符合第二范式的表不能存在非主键列只对部分

错误设计:
image.png
正确设计:
image.png
数据库设计的第三大范式:
指每一个非非主属性既不部分依赖于也不传递依赖于业务主键,也就是在第二范式的基础上相处了非主键对主键的传递依赖
错误设计:
image.png

客户编号 和订单编号管理 关联
客户姓名 和订单编号管理 关联
客户编号 和 客户姓名 关联
把客户姓名这列删除,只放到客户表中

例如:按要求设计一个电子商务网站的数据库结构

本网站只销售图书类产品
需要具备以下功能
用户登陆 商品展示 供应商管理
用户管理 商品管理 订单销售
image.png

统计分析

编写SQL查询出每一个用户的订单总金额
SELECT
a.单用户名,
sum(d.商品价格 * b.商品数量)
FROM
订单表 a
JOIN 订单分类关联表 b ON a.订单编号 = b.订单编号
JOIN 商品分类关联表 c ON c.商品分类ID = b.商品分类ID
JOIN 商品信息表 d ON d.商品名称 = c.商品名称
GROUP BY
a.下单用户名

编写SQL查询出下单用户和订单详情
SELECT
a.订单编号,
e.用户名,
e.手机号,
d.商品名称,
c.商品数量,
d.商品价格
FROM
订单表 a
JOIN 订单分类关联表 b ON a.订单编号 = b.订单编号
JOIN 商品分类关联表 c ON c.商品分类ID = b.商品分类ID
JOIN 商品信息表 d ON d.商品名称 = c.商品名称
JOIN 用户信息表 e ON e.用户名 = a.下单用户

问题:
大量的表关联非常影响查询的性能
完全符合范式化的设计有时并不能得到良好得SQL查询性能

反范式化设计

反范式化是针对范式化而言得,在前面介绍了数据库设计得范式
所谓得反范式化就是为了性能和读取效率得考虑而适当得对数据库设计范式得要求进行违反
允许存在少量得冗余,换句话来说反范式化就是使用空间来换取时间

范式化设计优缺点
优点:
Ø 可以尽量得减少数据冗余
Ø 范式化的更新操作比反范式化更快
Ø 范式化的表通常比反范式化的表更小
缺点:
Ø 对于查询需要对多个表进行关联
Ø 更难进行索引优化

反范式化设计优缺点
优点:
Ø 可以减少表的关联
Ø可以更好的进行索引优化
缺点:
Ø 存在数据冗余及数据维护异常
Ø 对数据的修改需要更多的成本


物理设计

根据所选择的关系型数据库的特点对逻辑模型进行存储结构的设计
物理设计
Ø定义数据库、表及字段的命名规范
Ø选择合适的存储引擎
Ø为表中的字段选择合适的数据类型
Ø建立数据库结构

定义数据库、表及字段的命名规范
Ø
Ø数据库、表、字段的命名要遵守可读性原则
使用大小写来格式化的库对象名字以获得良好的可读性
例如:使用custAddress而不是custaddress来提高可读性。
Ø数据库、表、字段的命名要遵守表意性原则
对象的名字应该能够描述它所表示的对象
例如:
对于表,表的名称应该能够体现表中存储的数据内容;对于存储过程
存储过程应该能够体现存储过程的功能。
数据库、表、字段的命名要遵守长名原则
尽可能少使用或者不使用缩写

选择合适的存储引擎

对比项 MyISAM InnoDB
主外键 不支持 支持
事务 不支持 支持
行表锁 表锁,即使操作一条记录也会锁住整个表
不适合高并发的操作
行锁,操作时只锁某一行,不对其它行有影响
适合高并发的操作
缓存 只缓存索引,不缓存真实数据 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响
表空间
关注点 性能 事务
默认安装 Y Y

为表中的字段选择合适的数据类型
Ø当一个列可以选择多种数据类型时
1.优先考虑数字类型
2.其次是日期、时间类型
3.最后是字符类型
4.对于相同级别的数据类型,应该优先选择占用空间小的数据类型

浮点类型

列类型 存储空间 是否精确类型
FlOAT 4个字节
DOUBLE 8个字节
DECIMAL 每4个字节存9个数字,小数点占1个字节

日期类型
timestamp 类型 与 datetime区别
image.png

timestamp 和时区有关,而datetime无关

image.png
set time_zone=”-10:00”
image.png
image.png

5.慢查询

什么是慢查询

慢查询日志,顾名思义,就是查询慢的日志,是指mysql记录所有执行超过long_query_time参数设定的时间阈值的SQL语句的日志。该日志能为SQL语句的优化带来很好的帮助。默认情况下,慢查询日志是关闭的,要使用慢查询日志功能,首先要开启慢查询日志功能。

默认情况下,MySQL数据库并不启动慢查询日志,需要手动来设置这个参数。
当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。

查看是否开启慢查询
可以查看是否开启以及慢查询日志的地址
show variables like ‘%slow_query_log%’;
image.png
set global slow_query_log=1 设置慢查询开启

set global slow_query_log=0 设置慢查询关闭

注意:此设置只对当前数据库生效,MySQL重启后则会失效

如果要永久生效,就必须修改配置文件my.cnf文件
image.png

慢查询时间
show variables like ‘%long_query_time%’;

默认情况下long_query_time的值为10秒,可以使用命令修改,也可以在my.cnf参数里面修改。
show variables like ‘long_query_time%’;

指定日志的存储方式
show variables like ‘%log_output%’;

log_output='FILE'表示将日志存入文件,默认值也是'FILE'
log_output='TABLE'表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中。
同时也支持两种日志存储方式,配置的时候以逗号隔开即可,如:log_output='FILE,TABLE'
日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源。
因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件

指定未使用索引的查询**也被记录到慢查询日志中**
show variables like ‘%log_queries_not_using_indexes%’;

**
如果调优的话,建议开启这个选项。

是否将慢管理语句例如**ANALYZE TABLEALTER TABLE**等记入慢查询日志
**
show variables like ‘log_slow_admin_statements’;

查询有多少条慢查询记录
**
show global status like ‘%Slow_queries%’;

慢查询分析工具mysqldumpslow

汇总除查询条件外其他完全相同的SQL,并将分析结果按照参数中所指定的顺序输出
在命令行中输入mysqldumpslow —help即可得到提示信息

image.png

例如:
1.得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/bogon-slow.log
image.png
2.得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 /database/mysql/mysql06_slow.log
3.得到按照时间排序的前10条里面含有左连接的查询语句。
mysqldumpslow -s t -t 10 -g “left join” /database/mysql/mysql06_slow.log

慢查询分析工具pt_query_digest

需要先

6.索引与执行计划

索引定义

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。
可以得到索引的本质:索引是数据结构。
最简单的索引:
image.png

MySQL中的索引:
右侧是数据表,一共有两列七条记录,最左边的是数据记录的物理地址
mysql默认存储引擎innodb只显式支持B-Tree( 从技术上来说是B+Tree)索引

image.png

索引分类

普通索引:即一个索引只包含单个列,一个表可以有多个单列索引

唯一索引:索引列的值必须唯一,但允许有空值

复合索引:即一个索引包含多个列

聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。

非聚簇索引:不是聚簇索引,就是非聚簇索引
show global variables like “%datadir%”;

基础语法
查看索引
SHOW INDEX FROM table_name\G
创建索引
CREATE [UNIQUE ] INDEX indexName ON mytable(columnname(length));
ALTER TABLE 表名 ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))
删除索引
DROP INDEX [indexName] ON mytable;
查看索引
SHOW INDEX FROM table_name\G
创建索引
CREATE [UNIQUE ] INDEX indexName ON mytable(columnname(length));
ALTER TABLE 表名 ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))
删除索引
DROP INDEX [indexName] ON mytable;

执行计划

什么是执行计划
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈

语法:
Explain + SQL语句

执行计划的作用

表的读取顺序
数据读取操作的操作类型
哪些索引可以使用
哪些索引被实际使用
表之间的引用
每张表有多少行被优化器查询

执行计划包含的信息:
image.png
执行计划-ID:

select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
三种情况
id相同,执行顺序由上至下
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
id相同不同,同时存在

Id相同
image.png

Id不同
image.png
如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

Id相同又不同
image.png
id如果相同,可以认为是一组,从上往下顺序执行;
在所有组中,id值越大,优先级越高,越先执行

执行计划-select_type(查询的类型):

查询的类型,主要是用于区别
普通查询、联合查询、子查询等的复杂查询
image.png

类型 描述
SIMPLE 简单的

select 查询,查询中不包含子查询或者UNION | | PRIMARY | 查询中若包含任何复杂的子部分,最外层查询则被标记为 | | SUBQUERY | 在SELECT或WHERE列表中包含了子查询 | | DERIVED | 在FROM列表中包含的子查询被标记为DERIVED(衍生)
MySQL会递归执行这些子查询, 把结果放在临时表里。 | | UNION | 若第二个SELECT出现在UNION之后,则被标记为UNION;
若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED | | UNION RESULT | 从UNION表获取结果的SELECT |

执行计划-table:

显示这一行的数据是关于哪张表的
image.png
执行计划-type:
type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
需要记忆的
system>const>eq_ref>ref>range>index>ALL

system
表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计
const
表示通过索引一次就找到了
const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快
如将主键置于where列表中,MySQL就能将该查询转换为一个常量

image.png
eq_ref
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
image.png
ref
非唯一性索引扫描,返回匹配某个单独值的所有行.
本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体

image.png
range
只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引
一般就是在你的where语句中出现了between、<、>、in等的查询
这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。
image.png
image.png
all
Full Table Scan,将遍历全表以找到匹配的行
image.png
执行计划-possible_keys:

实际使用的索引。如果为NULL,则没有使用索引
查询中若使用了覆盖索引,则该索引和查询的select字段重叠
image.png
image.png
执行计划-key_len:
image.png

image.png
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的
image.png
key_len表示索引使用的字节数,
根据这个值,就可以判断索引使用情况,特别是在组合索引的时候,判断所有的索引字段是否都被查询用到。
char和varchar跟字符编码也有密切的联系,
latin1占用1个字节,gbk占用2个字节,utf8占用3个字节。(不同字符编码占用的存储空间不同)

字符类型
image.png

字符类型-索引字段为char类型+不可为Null时
image.png
字符类型-索引字段为char类型+允许为Null时
image.png
索引字段为varchar类型+不可为Null时
image.png
varchar(n)变长字段+不允许Null=n*(utf8=3,gbk=2,latin1=1)+2

索引字段为varchar类型+允许为Null时
image.png
varchar(n)变长字段+允许Null=n*(utf8=3,gbk=2,latin1=1)+1(NULL)+2

数值类型
image.png

日期和时间
image.png
datetime类型在5.6中字段长度是5个字节,
datetime类型在5.5中字段长度是8个字节

整数/浮点数/时间类型的索引长度

NOT NULL=字段本身的字段长度
NULL=字段本身的字段长度+1(因为需要有是否为空的标记,这个标记需要占用1个字节)

datetime类型在5.6中字段长度是5个字节,datetime类型在5.5中字段长度是8个字节

key_len 总结
变长字段需要额外的2个字节(VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节),所以VARCAHR索引长度计算时候要加2),固定长度字段不需要额外的字节。

而NULL都需要1个字节的额外空间,所以索引字段最好不要为NULL,因为NULL让统计更加复杂并且需要额外的存储空间。

复合索引有最左前缀的特性,如果复合索引能全部使用上,则是复合索引字段的索引长度之和,这也可以用来判定复合索引是否部分使用,还是全部使用。

执行计划-ref:

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值
image.png
由key_len可知t1表的idx_col1_col2被充分使用,col1匹配t2表的col1,col2匹配了一个常量,即 ‘ac’

执行计划-rows:
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
image.png

执行计划-Extra:
包含不适合在其他列中显示但十分重要的额外信息

描述
Using filesort 说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
MySQL中无法利用索引完成的排序操作称为“文件排序”
Using temporary 使了用临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序

order by 和分组查询 group by。 | | USING index | 是否用了覆盖索引 | | Using where | 表明使用了where过滤 | | Using join buffer | 使用了连接缓存: | | Impossible where | where子句的值总是false,不能用来获取任何元组 |

Using filesort
说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
MySQL中无法利用索引完成的排序操作称为“文件排序”
image.png
image.png

7.sql优化