mysql索引、事务、存储引擎
一、索引:
索引是一个排序的列表,在列表当中存储索引的值以及索引值对应数据所在的物理行。
索引值和数据是一个映射关系 通过索引值可以定位到数据所在的位置
1.1索引的作用
加快查询速度
使用索引之后,就不需要扫描全表来定位某行的数据
索引可以是表中的一列,也可以是多个列
1、设置了索引之后,数据库可以利用索引快速定位,大大提高查询速度。这也是索引的主要原因
2、尤其是表的数据很大,以及涉及多个表查询时,索引可以大大的提高查询速度
3、建立索引不仅能够提高查询速度,在恢复数据库数据时也能提高性能
4、可以加快表与表之间 连接查询的速度
1.2索引的副作用(缺点)
1、创建的索引也需要占用额外的磁盘空间 INNODB存储引擎表数据和索引文件在一块。一体 。想对来说占的空间小一点。
2、更新一个包含索引的表比没有索引的表花费更多时间,表需要更新,索引也需要更新,所以速度要慢很多
1.3如何创建索引
创建索引的原则和依据:
1、表的主键和外键必须有索引,主键是唯一的,外键的关联主表的,查询时可以快速定位
2、一张表有超过300行的数据,应该要创建索引。
3、经常与其他表进行连接的表在连接字段上应当创建索引。
4、更新太频繁的字段不适合创建索引
5、经常被wher语句的条件列应该创建索引
6、经常进行group by(分组)order by(排序)的字段要建立索引
7、选择一个性能高的字段 数值相同最低 唯一性最高
8、索引要建立在小字段上(字符串小的字段),长文本的字段不适合建立索引
1.4索引的类型
查看表的索引:
show index from 表名;
B-树索引 BTREE:默认就是Btree
树型结构的索引,也是大部分数据库的默认索引类型
索引的左边列开始 从左到右按顺序进行排列
哈希索引 hash
索引对应的哈市值得方法获取表得记录,速度较慢,几乎不用
1.5创建索引
主键即索引
创建时添加索引
后期添加索引
explain 查询当前语句所使用索引得情况
二、创建索引
2.1 普通索引
*表中直接创建索引:*
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);
*2.2唯一索引:和unique相关*
与普通索引类似,唯一索引的每个值都是为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);
*2.3主键索引:*
创建表的时候指定的主键就是索引。添加主键自动就是主键索引
主键:值唯一 一个表只能有一个主键,不允许有空值,创建主键,自动主键索引
命令方式创建主键索引:
alter table 表名 add primary key(字段);
2.4删除主键索引
删除主键索引不能用drop直接删除索引,只能删除主键约束,然后主键索引自动删除
alter table 表名 drop index id_index;
drop index phone_index on 表名;
2.5组合索引
组合索引 一次性给多个列创建索引。形成一个组合
alter table 表名 add constraint uc_name_cardid_phone unique (name,cardid,phone);
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;
组合索引,从左到右侧开始,不能跳过索引,否则索引会失效
范围查询时有可能右侧的索引会失效
2.6全文索引
适用于模糊查询 检索大文本使用
建表时创建全文索引:
create FULLTEXT index remark_index on member (remark);
建表时创建:
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)
);
使用全文索引查询:
like不能检测全文索引,要用WHERE MATCH(列名) AGAINST(‘查询内容’);
SELECT * FROM 表名 WHERE MATCH(列名) AGAINST(‘查询内容’);
检测全文索引:
explain select * from 表名 where match(列名) against(查询对象);
创建索引时,注意索引失效的情况
explain 加载查询语句前面可以查看索引的使用情况
2.7练习
需求:
三、mysql的事务:
事务是一种机制,一个操作序列。包含了一组数据库的操作命令,所有命令都是一个整体,向系统提交或者撤销的操作,要么都执行,要么都不执行。
他是一个不可分割的单位 数据的一致性非常重要
事务是一个不可分割的工作逻辑单元,在数据库上执行并发操作时,事务是最小的控制单元事务的控制和事务的整体性保证数据的一致性。
3.1事务的特点:ACID
A:原子性 , ATOMICITY 最小单位,事务里的所有单位都是一个整体,不可分割,要么都成功,要么都失败
C:一致性,consistency 事务开始之前和事务结束之后数据库的完整性约束没有被破坏。
事务完成时,数据必须属于一致状态
事务开始前,数据库中的存储数据处于一致状态
进行中的事务,数据可能处于不一致的状态
当事务最终完成时,必须再次回到已知的一致状态
可能导致脏读
I:隔离性,lsolation 指在并发环境中不同事物同事操纵相同的数据时,每个事务都有各自的完整的数据空间对数据进行修改的所有并发事务是彼此隔离的,表明事务必须是独立的
修改数据的事务,可在另一个使用相同数据的事务开始之前。或者在另一个相同事务结束之后访问这些数据
D:持久性,durablility 事务一旦被提则不可逆,被持久化到数据库中,接下来即使数据库发生故障也不应该对其有任何影响
3.2MySQL支持的隔离级别(4种):
-
未提交读, read uncommitted RU
允许脏读,允许一个事务可以看到其他事务未提交的修改
-
提交读, read committed RC
事务只能查看只能提交的修改,未提交的修改是不可见的。他可以防止脏读
orcale sql-server 都是提交读
-
可重复读: repetable read RR 也是MySQL的默认隔离级别。确保如果在一个事务中执行两次相同的select语句时,都能得到相同的结果,不管其他事务是否提交修改。可以防止脏读以及不可重复读
-
串行读:锁表,完全串行化,完全隔离。每一个事务都隔离,读写之间都会堵塞。会降低数据库的效率
3.3、事务并发导致的问题:
脏读:指一个事务读取了另外一个事务未提交的数据
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同
虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致
丢失更新: 两个事务同时读取同一条记录,导致修改结果覆盖
3.4、事务隔离的作用范围:
- 全局级:对所有的会话有效
- 会话级:
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提交为主
持久性:数据一旦提交,事务的效果将会被永久的保留在数据库中,而且不会被回滚。
实际生活中会主从复制、高可用、备份、权限控制多层保险
总结:在事务管理中,原子性是基础,隔离性是手段,一致性是目的持久性是最终的结果。
3.5、事务的控制语句:
开始事务:
begin开始
start transaction 显示的开启事务
提交事务:
commit
commit work
回滚:能撤销正在进行的所有未提交的修改
rollback
rollback work
回滚点:
savepoint s1(自定义名):创建回滚点,一个事务可以有多个回滚点
回到回滚点:
rollback to s1:回滚到s1还原点
rollback to savepoint s1
一旦提交所有的还原点全部消失,不能还原
- 多点还原 s1 s2
如果说还原到s1,s2则消失
如果提交所有还原点全部消失
mysql 提交事务默认是自动提交(不begin 就是默认提价命令,不能rollback)
四、存储引擎
存储引擎:MySQL中数据用各种不同的技术存储在文件中,每一种技术都使用不同的存储机制,索引技巧,锁定水平以及最终提供的不同的功能和能力,这些就是我们说的存储引
4.1、存储引擎的功能:
- MySQL将数据存储在文件系统的一种方式和格式
- 存储引擎负责执行实际的数据I/O操作(读写操作)
- 存储引擎介于数据和文件系统之间,数据会先保存到存储引擎,再按照存储引擎的格式保存到文件系统(硬盘)
4.2、MySQL的存储引擎分类:
- INNODB:5.5版本之后MySQL的默认存储引擎。事务性速记引擎。支持ACID事务。支持锁行,锁表。写入和查询性能比较好
- MYISAM:5.5版本之前的默认存储引擎。有较高的插入数据性能,查询速度也很优秀,但是他不支持事务(ACID)
- memory:所有数据都保存在内存的存储引擎。插入数据更新数据、查询数据速度比较快,到那时占用空间比较大。他会占用和数据量成正比的内存空间。MySQL一旦重启内容丢失
- csv:由逗号分割数据的存储引擎。他会在数据库子目录里为每一个数据表创建一个.csv的文件。就是一种普通的文本文件。每个数据行占用一个文本行。csv不支持索引
- Archive:他非常适合存储大量的独立的,而且是历史数据的引擎。不需要被经常读取。插入的速度很快,查询的效率比较低。
- blackhole:黑洞引擎,写入的任何数据都会消失。
4.3 INNODB
- 支持事务,支持四个事务的隔离级别。5.5版本之后是MySQL的默认存储引擎
- 读写阻塞和隔离级别相关。
- 支持高效的缓存索引以及缓存数据。
- 表与主键以簇的方式存储Btree
- 支持外键约束,5.5之后INNODB也可以支持全文索引
- 对硬件资源的要求较高
- 支持行锁定,也可以支持表锁定(全表扫描)
注意点:
- 使用like模糊查询,会进行全表扫描,锁定整个表
- 对没有创建索引的字段进行增 删 改,也会进行全表扫描。锁定整个表。
- 使用索引,进行增 删 改,则是行级索引
INNODB的特点:
1、不保存表的行数,统计表的行数,会扫描一遍整个表来计算有多少行
2、自增长字段,INNODB中必须包含只有该字段的索引
- delete清空表,一行一行删速度比较慢,推荐用truncate
show engines;查看存储引擎
切换存储引擎就是改配置文件
4.4、INNODB的行锁和索引的关系,以及表锁 排他锁 死锁
行锁是通过索引来实现的
如果没有索引,innodb会使用默认的隐藏索引来对记录进行加速
加了索引就是锁行
不加索引就是锁表
使用隔离级别:默认的可重复读
****锁行:****对索引键操作
两边begin 操作索引时,会形成行锁,一个发送另一个同一行改不掉
如果说使用的id的字段是主键,INNODB对主键使用聚簇索引,锁定整行的记录
解决方法:commit之后立即生效
设置id为主键索引,name为普通索引:
前一个的修改没有结束,后面的操作不能进行
解决方法:commit提交操作。行锁取消
操纵索引对行进行过滤,锁定整行,其他行不影响。必须行的前一个操作结束,才能进行行的另一个操作
*锁表*:**锁定表,要对一个非索引行操作(没有索引要全表扫描,以至于锁定整个表)**不是索引锁全表,是索引锁一列
解决方法:commit之后立即生效
对非索引参数进行操作:
*解决方式也是对上一个操作进行commit提交,提交之后才能进行下一个操作:*
当一个事务对非索引列进行操作,因为要全表扫描过滤,所以整张表都会被锁定,另一个事务只能查询操作
排它锁:
又叫悲观锁。一个事务在操作,另一个事务的操作无法执行,只能查。排它锁只能加一个。
for update 排他锁
select * from test where id = 2 for update;
死锁:(基于排它锁)
事务之间相互等待对方资源,最后会形成一个环路造成的。
死锁基于排它锁形成
死锁形成时:
- 发生死锁的时候,数据库会自动选择一个事务作为受害者,然后先接触死锁,在回滚
- mysql默认的死锁机制,一旦发生死锁,会选择一个事务作为死锁的牺牲品,直接终止其中一个事务,但是不会自动回滚
总结:
索引只会锁行
非索引锁表
排它锁
死锁,会自动选择一个事务作为牺牲品,结束死锁。
乐观锁:不会有任何提示,只是数据不能写入而已。数据提交更新时,他会进行校验,发生冲突,数据不生效而已,没有其他的报错或者是卡停
一般来说,我们会在表中配置version字段,通过自增校验来查看数据是否冲突
除了version 也可以用时间戳timestreap
存储引擎只能是INNODB
mysql默认隔离级别即可
4.5、如何尽可能的避免死锁:
mysql自动提交写入 ocale运行了还要点确认才能写入
- 业务的逻辑要合理,以固定的顺序访问表和行
- 如果事务的类型比较复杂,要进行拆分,在业务允许的情况下,把大事务拆小,分次执行
- 在同一事物中,尽可能的一次锁定所有需要的资源。可以减少死锁的概率
- 隔离级别,read committed可以避免死锁
- 添加合理的索引(操作索引只锁行),减少死锁的概率
核心内容:
索引和行锁之间的关系
非索引的锁表以及死锁
排它锁
INNODB的机制和存储文件的格式。
-kmJnRtZv-1721356986290)]
[外链图片转存中…(img-4Kc3APUy-1721356986290)]
总结:
索引只会锁行
非索引锁表
排它锁
死锁,会自动选择一个事务作为牺牲品,结束死锁。
乐观锁:不会有任何提示,只是数据不能写入而已。数据提交更新时,他会进行校验,发生冲突,数据不生效而已,没有其他的报错或者是卡停
一般来说,我们会在表中配置version字段,通过自增校验来查看数据是否冲突
除了version 也可以用时间戳timestreap
存储引擎只能是INNODB
mysql默认隔离级别即可
4.5、如何尽可能的避免死锁:
mysql自动提交写入 ocale运行了还要点确认才能写入
- 业务的逻辑要合理,以固定的顺序访问表和行
- 如果事务的类型比较复杂,要进行拆分,在业务允许的情况下,把大事务拆小,分次执行
- 在同一事物中,尽可能的一次锁定所有需要的资源。可以减少死锁的概率
- 隔离级别,read committed可以避免死锁
- 添加合理的索引(操作索引只锁行),减少死锁的概率
核心内容:
索引和行锁之间的关系
非索引的锁表以及死锁
排它锁
INNODB的机制和存储文件的格式。