目录
一、索引:
1、索引的作用:
2、索引的缺点
3、创建表的时候需要考虑的因素:
4、如何创建索引:
5、索引的类型:
6、索引的使用
6.1、普通索引
6.2、唯一索引:和unique相关
6.3、主键索引:
6.4全文索引:
6.5、联合索引:指定一个索引名,一个索引名对应多个列名
二、MySQL的事务:
1、事务的特点:ACID
2、MySQL支持的隔离级别(4种):
3、事务并发导致的问题:
4、事务的隔离级别:
5、事务隔离的作用范围:
6、以上情况如何避免:脏读、幻读、不可重复读、丢失更新
7、事务的控制语句:
三、存储引擎
1、存储引擎的功能:
2、MySQL的存储引擎分类:
3、MYISAM和INNODB分析和对比:
3.1、MYISAM:
3.2、INNODB:
4、语句:
4.1、查看支持的存储引擎:
4.2、查看表使用的存储引擎:
4.3、改存储引擎:
5、INNODB的行锁和索引的关系,以及表锁 排他锁 死锁
6、如何尽可能的避免死锁:
是一个排序的列表,列表中存储的是索引的值和包含这个值的数据所在行的物理地址。
加快查询速度
·会额外占用磁盘空间;
·更新包含索引的表会花费更多时间,效率会更慢。
索引创建的原则:
如果有索引,数据库会进行索引查询,然后定位数据,索引如果使用不当,反而会增加数据库的负担。
正确创建:
·主键外键必须要有索引(创建好主键和外键自动就是索引,不需要额外声明了)
·如果一个表超过300行的记录,必须要有索引,否则数据库会遍历表的所有数据。
·互相之间有关联得表,在这个关联字段应该设置索引
·唯一性太差的字段,不适合创建索引
·更新太频繁的字段,不适合做索引
·经常被where条件匹配的字段,尤其是表数据比较多的,应该创建索引
·经常进行group by(分组) order by(排序)的字段要建立索引
·索引的列的字段越小越好,长文本的字段不适合建立索引
查看表的索引:
show index from 表名;
B-树索引 BTREE:默认就是Btree
树型结构的索引,也是大部分数据库的默认索引类型
根节点:输的最顶端的分支节点
分支节点:指向索引里其他的分支节点,也可以是叶子节点
叶子结点:直接指向表里的数据行
mysql的默认引擎:INNODB默认的索引类型就是Btree
哈希hash索引:散列索引 把任意长度的输入,通过散列算法变换成固定长度的输出。新成散列值——分别对应数据里的列和行
MEMORY引擎可以支持hash,也是他的默认索引
先算散列值,然后再对应,速度比较慢,比Btree慢
hash的索引匹配:= in () <=>
hash索引排序时,索引是无效的
将默认的Btree改成hash索引:
alter table 表名 engine=memory;
将表的引擎改为memory,索引就变成hash了
查看表的索引信息
show index from 表名;
查看表的结构信息(包含索引名和外键名)
show create table 表名;
练习:
1、创建用户,声明网段 test 网段任选 123456
create user 'test'@'20.0.0.0/24' identified by '123456';
2、创建一个库,库名:test1
create database test1;
3、在库中创建两个表
table1
ID 主键
name 不能为空
sex 不能为空
table2
id 主键
address 可以为空,默认地址不详
phone 可以为空不能重复
test 可以对test1的库进行 select INSERT
把 test的用户名改成 test_123
rename user 'test'@'20.0.0.0/24' to 'test_123'@'20.0.0.0/24';
把密码修改 abc123
删除权限:INSERT
table1的索引是hash类型,sex列做索引
table2的索引是btree, phone做索引
6.1、创建索引:
普通索引、唯一索引、主键索引、全文索引、联合索引
查看索引信息
show index from 表名;
查看索引类型
show create table 表名;
能在建表时创建好的条件,尽量在创建把条件约束好。不要创完之后再添加
最好不要事后添加
表中直接创建索引:
create table member (
id int(4) PRIMARY KEY,
name varchar(10),
card_id int(18),
phone int(11),
index name_index (name)
);
index name_index (name)
name_index:自定义索引名
(name):索引对象
show index from member;
查看索引
通过命令添加索引:
alter table test add index name_index(name);
与普通索引类似,唯一索引的每个值都是为1,唯一索引允许空值的。只有添加唯一键,才会创建唯一索引。
unique最好是不要为空。所以一般unique和not null一起使用。
创建唯一索引:
先插入新的列:
alter table member add COLUMN address varchar(40) not null;
在创建unique唯一索引:
alter table member add UNIQUE address_index(address);
创建唯一索引,而且不能为空,就算不给unique,他也自带unique,值是唯一的不能为空
create table test1 (
id int(4) PRIMARY KEY,
name varchar(10),
card_id int(18) not null,
phone int(11) not null,
unique cardid_index (card_id),
UNIQUE phone_index (phone)
);
创建唯一索引之后,接相当于给列加上了一个unique约束,插入值不能重复
命令方式创建唯一索引:
create UNIQUE index phone_index on member (phone);
创建表的时候指定的主键就是索引。添加主键自动就是主键索引
主键:值唯一 一个表只能有一个主键,不允许有空值,创建主键,自动主键索引
命令方式创建主键索引:
alter table 表名 add primary key(字段);
删除主键索引:
删除主键索引不能用drop直接删除索引,只能删除主键约束,然后主键索引自动删除
alter table 表名 drop primary key;
text
建表时创建:
create table test3 (
id int(4) PRIMARY KEY,
name varchar(10),
card_id int(18) not null,
phone int(11) not null,
notes text,
FULLTEXT notes_index (notes)
);
建表时创建全文索引:
create FULLTEXT index notes_index on test3 (notes);
使用全文索引查询:
like不能检测全文索引,要用WHERE MATCH(列名) AGAINST('查询内容');
SELECT * FROM 表名 WHERE MATCH(列名) AGAINST('查询内容');
创建联合索引:
create index index_union on test3 (card_id,phone);
联合索引,查询时必须按照创建时的顺序来进行查询
explain select * from test3 where card_id = 322 and phone = 333;
联合索引,从左到右侧开始,不能跳过索引,否则索引会失效
范围查询时有可能右侧的索引会失效
mysql机制:默认会找最短的索引列。最优索引选择
如果索引是字符串,到那会是不加引号,索引也会失效
使用or作为条件的时候,MySQL无法同时使用多个索引
explain select * from test5 where id =8 or phone='111';
使用where is null 或where is not null时,有可能索引会失效
where is null:如果数据绝大多数都是空值,索引一定失效
where is not null:如果数据多数不为null,索引失效
删除索引:
drop index索引名 on 表名;
drop index notes_index on test3;
模糊查询:
select * from 表名 where 列名 like '%';
1%:查询1开头的
%1:查询1结尾的
查看索引是否生效:在select查询命令之前加上explain,查看key那一列,有则生效
EXPLAIN select * from 表名 where 列名 like '%';
检测全文索引:
explain select * from 表名 where match(列名) against(查询对象);
创建索引时,注意索引失效的情况
explain 加载查询语句前面可以查看索引的使用情况
现在一张表的查询速度是7.62s
你该如何解决?
答:
首先查缓存,看是不是直接请求到后端MySQL数据库了(缓存击穿)
再看索引,请求的列值不是默认的索引,添加一下即可
explain 查询命令
事务是一种机制,一个操作序列。包含了一组数据库的操作命令,所有命令都是一个整体,向系统提交或者撤销的操作,要么都执行,要么都不执行。
他是一个不可分割的单位
A:原子性,最小单位,事务里的所有单位都是一个整体,不可分割,要么都成功,要么都失败
C:一致性,事务开始之前和事务结束之后数据库的完整性约束没有被破坏。
事务完成时,数据必须属于一致状态
事务开始前,数据库中的存储数据处于一致状态
进行中的事务,数据可能处于不一致的状态
当事务最终完成时,必须再次回到已知的一致状态
可能导致脏读
I:隔离性,指在并发环境中不同事物同事操纵相同的数据时,每个事务都有各自的完整的数据空间
对数据进行修改的所有并发事务是彼此隔离的,表明事务必须是独立的
修改数据的事务,可在另一个使用相同数据的事务开始之前。或者在另一个相同事务结束之后访问这些数据
D:持久性,事务一旦被提则不可逆,被持久化到数据库中,接下来即使数据库发生故障也不应该对其有任何影响
orcale sql-server
脏读:指一个事务读取了另外一个事务未提交的数据
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同
虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致
丢失更新: 两个事务同时读取同一条记录,导致修改结果覆盖
允许脏读,即允许一个事务可以看到其他事务未提交的修改
允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的,防止脏读
确保如果实在一个事务中执行两次相同的select语句,都能得到相同的结果,不管其他事务是否提交这些修改。可以防止脏读和不可重复读
完全串行化的读,将一个事务与其他事务完全地隔离。每次读都需要获得表级共享锁,读写相互都会阻塞。可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的执行效率
show global variables like '%isolation';
查询全局事务的隔离级别
select @@global.tx_isolation;
查询全局事务的隔离级别
查询会话事务的隔离级别
show session variables like'%isolation';
查询会话事务的隔离级别
select @@session.tx_isolation;
全局隔离级别修改:未提交读
set global TRANSACTION ISOLATION level read UNCOMMITTED;
修改全局的隔离级别
set @@global.tx_isolation='read UNCOMMITTED';
临时修改全局隔离,重启失效
修改会话隔离级别
set session TRANSACTION ISOLATION level read UNCOMMITTED;
set @@session.tx_isolation='read UNCOMMITTED';
脏读:
不可重复读:一个事务内,多次读同一数据
前一个事务还没有结束,另一个事务也访问该数据
在一个事务之内,两次查询到的结果不一致。读不到相同的数据内容
幻读:一个事务对一个表中的数据进行了修改,可能会涉及到表中的全部数据。另一个事务也修改了这个表的数据。前一个事务会发现表中还有数据还没有修改,类似于幻觉。
丢失更新:两个事务同时修改一条记录,A先记录B也修改记录,B一旦提交,会覆盖A的结果
不管如何操作,都以最后commit提交为主
根据情况来使用隔离级别
测试环境——无所谓
持久性:数据一旦提交,事务的效果将会被永久的保留在数据库中,而且不会被回滚。
实际生活中会主从复制、高可用、备份、权限控制多层保险
总结:在事务管理中,原子性是基础,隔离性是手段,一致性是目的持久性是最终的结果。
开始事务:
begin开始
start transaction 显示的开启事务
提交事务:
commit
commit work
回滚:能撤销正在进行的所有未提交的修改
rollback
rollback work
回滚点:
savepoint s1(自定义名):创建回滚点,一个事务可以有多个回滚点
回到回滚点:
rollback to s1:回滚到s1还原点
一旦提交所有的还原点全部消失,不能还原
如果说还原到s1,s2则消失
如果提交所有还原点全部消失
mysql 提交事务默认是自动提交(不begin 就是默认提价命令,不能rollback)
练习:
可以用set来设置MySQL提交方式:
set autocommit=0;
关闭自动提交
show variables like 'autocommit';
查看自动提交情况
关闭自动提交就相当于开启了,未提交读,也就是允许脏读,必须手动commit提交修改,才能同步数据,不然会脏读
存储引擎:MySQL中数据用各种不同的技术存储在文件中,每一种技术都使用不同的存储机制,索引技巧,锁定水平以及最终提供的不同的功能和能力,这些就是我们说的存储引擎
不支持事务,也不支持外键,只支持全文索引,数据文件和索引文件是分开的,
访问速度快
适用场景:查询和插入数据为主的应用。
在磁盘上有三个文件:
文件名和表名相同。但是扩展名不同:
.frm:存储的表结构
.MYD:存储的数据文件
.MYI:索引文件
MYISAM的特点:
支持的存储格式:
优点:存储快,方便缓存,有了故障容易恢复
缺点:占用的空间比较大
定期清理命令:myisamchk -r 出现故障恢复比较困难
注意点:
INNODB的特点:
1、不保存表的行数,统计表的行数,会扫描一遍整个表来计算有多少行
2、自增长字段,INNODB中必须包含只有该字段的索引
适用场景:
INNODB三个文件:
表名.frm(表结构文件)
表名.idb(即使数据文件,也是索引文件)
dp.opt:(表的属性文件)
show engines;
show engines\G;
方法一:
show table status from 库名 where name='表名'\G
show table status from ku where name='test'\G;
方法二:
use 库名;
show create table 表名;
方法一:alter table修改:
alter table 表名 engine=存储引擎名;
alter table test engine=MyISAM;
方法二:修改配置文件
通过修改/etc/my.cnf配置文件,指定默认存储引擎并重启服务。
此方法只对修改了配置文件并重启mysql服务后 新创建的表有效已经存在的表不会更改。
重启mysqld
systemctl restart mysqld.service
方法三:通过create table创建表时指定存储引擎
表结构文件所在目录:(编译安装)
使用隔离级别:默认的可重复读
锁行:对索引键操作
两边begin 操作索引时,会形成行锁,一个发送另一个同一行改不掉
如果说使用的id的字段是主键,INNODB对主键使用聚簇索引,锁定整行的记录
解决方法:commit之后立即生效
设置id为主键索引,name为普通索引:
前一个的修改没有结束,后面的操作不能进行
解决方法:commit提交操作。行锁取消
操纵索引对行进行过滤,锁定整行,其他行不影响。必须行的前一个操作结束,才能进行行的另一个操作
锁表:锁定表,要对一个非索引行操作(没有索引要全表扫描,以至于锁定整个表)
解决方法:commit之后立即生效
对非索引参数进行操作:
解决方式也是对上一个操作进行commit提交,提交之后才能进行下一个操作:
当一个事务对非索引列进行操作,因为要全表扫描过滤,所以整张表都会被锁定,另一个事务只能查询操作
排它锁:
又叫悲观锁。一个事务在操作,另一个事务的操作无法执行,只能查。排它锁只能加一个。
for update 排他锁
select * from test where id = 2 for update;
死锁:(基于排它锁)
事务之间相互等待对方资源,最后会形成一个环路造成的。
死锁基于排它锁形成
死锁形成时:
总结:
索引只会锁行
非索引锁表
排它锁
死锁,会自动选择一个事务作为牺牲品,结束死锁。
乐观锁:不会有任何提示,只是数据不能写入而已。数据提交更新时,他会进行校验,发生冲突,数据不生效而已,没有其他的报错或者是卡停
一般来说,我们会在表中配置version字段,通过自增校验来查看数据是否冲突
除了version 也可以用时间戳timestreap
存储引擎只能是INNODB
mysql默认隔离级别即可
核心内容:
索引和行锁之间的关系
非索引的锁表以及死锁
排它锁
INNODB的机制和存储文件的格式。