• mysql索引、事务、存储引擎


    目录

    一、索引:

    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、如何尽可能的避免死锁:


    一、索引:

    是一个排序的列表,列表中存储的是索引的值和包含这个值的数据所在行的物理地址。

    1、索引的作用:

    加快查询速度

    1. 利用索引数据库可以快速定位,大大加快查询速度
    2. 标的数据很多,查询需要关联多个表,这个时候索引也可以提高查询速度
    3. 加快表与表之间的连接速度
    4. 使用分组和排序时,可以大大减少时间
    5. 可以提高数据库恢复数据时的速度

    2、索引的缺点

    ·会额外占用磁盘空间;

    ·更新包含索引的表会花费更多时间,效率会更慢。

    3、创建表的时候需要考虑的因素:
    1. 关联程度(最多三张),选好关联字段
    2. 每个字段的长度,也要考虑
    3. 设计合理的索引列
    4. 表数据,要控制在合理的范围之内。可以在牺牲一定性能的条件下满足需求。5秒以上就要考虑优化了,10秒以上一般是出问题了(前端缓存失效,缓存击穿。缓存雪崩。)

    4、如何创建索引:

    索引创建的原则:

    如果有索引,数据库会进行索引查询,然后定位数据,索引如果使用不当,反而会增加数据库的负担。

    正确创建:

    ·主键外键必须要有索引(创建好主键和外键自动就是索引,不需要额外声明了)

    ·如果一个表超过300行的记录,必须要有索引,否则数据库会遍历表的所有数据。

    ·互相之间有关联得表,在这个关联字段应该设置索引

    ·唯一性太差的字段,不适合创建索引

    ·更新太频繁的字段,不适合做索引

    ·经常被where条件匹配的字段,尤其是表数据比较多的,应该创建索引

    ·经常进行group by(分组) order by(排序)的字段要建立索引

    ·索引的列的字段越小越好,长文本的字段不适合建立索引

    5、索引的类型:

    查看表的索引:

    show index from 表名;

    B-树索引 BTREE:默认就是Btree

    树型结构的索引,也是大部分数据库的默认索引类型

    根节点:输的最顶端的分支节点

    分支节点:指向索引里其他的分支节点,也可以是叶子节点

    叶子结点:直接指向表里的数据行

    mysql的默认引擎:INNODB默认的索引类型就是Btree

    哈希hash索引:散列索引 把任意长度的输入,通过散列算法变换成固定长度的输出。新成散列值——分别对应数据里的列和行

    MEMORY引擎可以支持hash,也是他的默认索引

    先算散列值,然后再对应,速度比较慢,比Btree慢

    hash的索引匹配:= in () <=>

    hash索引排序时,索引是无效的

    将默认的Btree改成hash索引:

    alter table 表名 engine=memory;

    将表的引擎改为memory,索引就变成hash了

    6、索引的使用

    查看表的索引信息

    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 表名;

    能在建表时创建好的条件,尽量在创建把条件约束好。不要创完之后再添加

    最好不要事后添加


    6.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);

    6.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);

    6.3、主键索引:

    创建表的时候指定的主键就是索引。添加主键自动就是主键索引

    主键:值唯一 一个表只能有一个主键,不允许有空值,创建主键,自动主键索引

    命令方式创建主键索引:

    alter table 表名 add primary key(字段);

    删除主键索引:

    删除主键索引不能用drop直接删除索引,只能删除主键约束,然后主键索引自动删除

    alter table 表名 drop primary key;

    6.4全文索引:
    • 适合在进行模糊查询的时候使用,可以在一边文章中检索文本信息

    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('查询内容');

    6.5、联合索引:
    指定一个索引名,一个索引名对应多个列名

    创建联合索引:

    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 查询命令

    二、MySQL的事务:

    事务是一种机制,一个操作序列。包含了一组数据库的操作命令,所有命令都是一个整体,向系统提交或者撤销的操作,要么都执行,要么都不执行。

    他是一个不可分割的单位

    1、事务的特点:ACID

    A:原子性,最小单位,事务里的所有单位都是一个整体,不可分割,要么都成功,要么都失败

    C:一致性,事务开始之前和事务结束之后数据库的完整性约束没有被破坏。

    事务完成时,数据必须属于一致状态

    事务开始前,数据库中的存储数据处于一致状态

    进行中的事务,数据可能处于不一致的状态

    当事务最终完成时,必须再次回到已知的一致状态

    可能导致脏读

    I:隔离性,指在并发环境中不同事物同事操纵相同的数据时,每个事务都有各自的完整的数据空间

    对数据进行修改的所有并发事务是彼此隔离的,表明事务必须是独立的

    修改数据的事务,可在另一个使用相同数据的事务开始之前。或者在另一个相同事务结束之后访问这些数据

    D:持久性,事务一旦被提则不可逆,被持久化到数据库中,接下来即使数据库发生故障也不应该对其有任何影响

    2、MySQL支持的隔离级别(4种):
    1. 未提交读,允许脏读,允许一个事务可以看到其他事务未提交的修改
    2. 提交读:事务只能查看只能提交的修改,未提交的修改是不可见的。他可以防止脏读

    orcale sql-server

    1. 可重复读:也是MySQL的默认隔离级别。确保如果在一个事务中执行两次相同的select语句时,都能得到相同的结果,不管其他事务是否提交修改。可以防止脏读以及不可重复读
    2. 串行读:锁表,完全串行化,完全隔离。每一个事务都隔离,读写之间都会堵塞。会降低数据库的效率

    3、事务并发导致的问题:

    脏读:指一个事务读取了另外一个事务未提交的数据

    不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同

    虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致

    丢失更新: 两个事务同时读取同一条记录,导致修改结果覆盖

    4、事务的隔离级别:
    1. 未提交读:Read Uncommitted

    允许脏读,即允许一个事务可以看到其他事务未提交的修改

    1. 提交读:Read Committed

    允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的,防止脏读

    1. 可重复读:Repeatable Read——MySQL默认的隔离级别

    确保如果实在一个事务中执行两次相同的select语句,都能得到相同的结果,不管其他事务是否提交这些修改。可以防止脏读和不可重复读

    1. 串行读:serializable——相当于锁表

    完全串行化的读,将一个事务与其他事务完全地隔离。每次读都需要获得表级共享锁,读写相互都会阻塞。可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的执行效率

    5、事务隔离的作用范围:
    1. 全局级:对所有的会话有效
    2. 会话级:

    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提交为主

    6、以上情况如何避免:脏读、幻读、不可重复读、丢失更新
    1. 权限控制(核心)

    根据情况来使用隔离级别

    1. 生产环境——最好是提交读和可重复读

    测试环境——无所谓

    1. 生产环境只能允许一个人对一个事务进行操作。其他人不允许操作。

    持久性:数据一旦提交,事务的效果将会被永久的保留在数据库中,而且不会被回滚。

    实际生活中会主从复制、高可用、备份、权限控制多层保险

    总结:在事务管理中,原子性是基础,隔离性是手段,一致性是目的持久性是最终的结果。

    7、事务的控制语句:

    开始事务:

    begin开始

    start transaction 显示的开启事务

    提交事务:

    commit

    commit work

    回滚:能撤销正在进行的所有未提交的修改

    rollback

    rollback work

    回滚点:

    savepoint s1(自定义名):创建回滚点,一个事务可以有多个回滚点

    回到回滚点:

    rollback to s1:回滚到s1还原点

    一旦提交所有的还原点全部消失,不能还原

    1. 多点还原 s1 s2

    如果说还原到s1,s2则消失

    如果提交所有还原点全部消失

    mysql 提交事务默认是自动提交(不begin 就是默认提价命令,不能rollback)

    练习:

    可以用set来设置MySQL提交方式:

    set autocommit=0;

    关闭自动提交

    show variables like 'autocommit';

    查看自动提交情况

    关闭自动提交就相当于开启了,未提交读,也就是允许脏读,必须手动commit提交修改,才能同步数据,不然会脏读

    三、存储引擎

    存储引擎:MySQL中数据用各种不同的技术存储在文件中,每一种技术都使用不同的存储机制,索引技巧,锁定水平以及最终提供的不同的功能和能力,这些就是我们说的存储引擎

    1、存储引擎的功能:
    1. MySQL将数据存储在文件系统的一种方式和格式
    2. 存储引擎负责执行实际的数据I/O操作(读写操作)
    3. 存储引擎介于数据和文件系统之间,数据会先保存到存储引擎,再按照存储引擎的格式保存到文件系统(硬盘)

    2、MySQL的存储引擎分类:
    1. INNODB:5.5版本之后MySQL的默认存储引擎。事务性速记引擎。支持ACID事务。支持锁行,锁表。写入和查询性能比较好
    2. MYISAM:5.5版本之前的默认存储引擎。有较高的插入数据性能,查询速度也很优秀,但是他不支持事务(ACID)
    3. memory:所有数据都保存在内存的存储引擎。插入数据更新数据、查询数据速度比较快,到那时占用空间比较大。他会占用和数据量成正比的内存空间。MySQL一旦重启内容丢失
    4. csv:由逗号分割数据的存储引擎。他会在数据库子目录里为每一个数据表创建一个.csv的文件。就是一种普通的文本文件。每个数据行占用一个文本行。csv不支持索引
    5. Archive:他非常适合存储大量的独立的,而且是历史数据的引擎。不需要被经常读取。插入的速度很快,查询的效率比较低。
    6. blackhole:黑洞引擎,写入的任何数据都会消失。

    3、MYISAM和INNODB分析和对比:
    3.1、MYISAM:

    不支持事务,也不支持外键,只支持全文索引,数据文件和索引文件是分开的,

    访问速度快

    适用场景:查询和插入数据为主的应用。

    在磁盘上有三个文件:

    文件名和表名相同。但是扩展名不同:

    .frm:存储的表结构

    .MYD:存储的数据文件

    .MYI:索引文件

    MYISAM的特点:

    1. 表级锁定:更新数据时,整个都将锁定
    2. 数据库在读写过程中相互堵塞

    支持的存储格式:

    1. 静态表,固定长度表,静态表是MYISAM的默认存储格式。静态表中字段都是非可变字段。每个记录哦度黑丝固定长度。

    优点:存储快,方便缓存,有了故障容易恢复

    缺点:占用的空间比较大

    1. 动态表:动态表可以包含可变字段,记录的长度是不固定的。优点是占用空间少。频繁更新数据、删除记录,会产生记录碎片,需要定期清理。

    定期清理命令:myisamchk -r 出现故障恢复比较困难

    1. 压缩表:myisamchk工具创建的表,占据的空间非常小,每条记录都是单独压缩的。

    3.2、INNODB:
    1. 支持事务,支持四个事务的隔离级别。5.5版本之后是MySQL的默认存储引擎
    2. 读写阻塞和隔离级别相关。
    3. 支持高效的缓存索引以及缓存数据。
    4. 表与主键以簇的方式存储Btree
    5. 支持外键约束,5.5之后INNODB也可以支持全文索引
    6. 对硬件资源的要求较高
    7. 支持行锁定,也可以支持表锁定(全表扫描)

    注意点:

    1. 使用like模糊查询,会进行全表扫描,锁定整个表
    2. 对没有创建索引的字段进行增 删 改,也会进行全表扫描。锁定整个表。
    3. 使用索引,进行增 删 改,则是行级索引

    INNODB的特点:
    1、不保存表的行数,统计表的行数,会扫描一遍整个表来计算有多少行

    2、自增长字段,INNODB中必须包含只有该字段的索引

    1. delete清空表,一行一行删速度比较慢,推荐用truncate

    适用场景:

    1. 业务需要事务的支持
    2. 论坛、微博,对数据一致性比较高的场景适用
    3. 访问量和并发量比较高的场景,INNODB可以支持缓存,减少后台服务器的压力

    INNODB三个文件:

    表名.frm(表结构文件)

    表名.idb(即使数据文件,也是索引文件)

    dp.opt:(表的属性文件)

    4、语句:
    4.1、查看支持的存储引擎:

    show engines;

    show engines\G;

    4.2、查看表使用的存储引擎:

    方法一:

    show table status from 库名 where name='表名'\G

    show table status from ku where name='test'\G;

    方法二:

    use 库名;

    show create table 表名;

    4.3、改存储引擎:

    方法一:alter table修改:

    alter table 表名 engine=存储引擎名;

    alter table test engine=MyISAM;

    方法二:修改配置文件

    通过修改/etc/my.cnf配置文件,指定默认存储引擎并重启服务。

    此方法只对修改了配置文件并重启mysql服务后 新创建的表有效已经存在的表不会更改。

    重启mysqld

    systemctl restart mysqld.service

    方法三:通过create table创建表时指定存储引擎

    表结构文件所在目录:(编译安装)

    5、INNODB的行锁和索引的关系,以及表锁 排他锁 死锁

    使用隔离级别:默认的可重复读

    锁行:对索引键操作

    两边begin 操作索引时,会形成行锁,一个发送另一个同一行改不掉

    如果说使用的id的字段是主键,INNODB对主键使用聚簇索引,锁定整行的记录

    解决方法:commit之后立即生效

    设置id为主键索引,name为普通索引:

    前一个的修改没有结束,后面的操作不能进行

    解决方法:commit提交操作。行锁取消

    操纵索引对行进行过滤,锁定整行,其他行不影响。必须行的前一个操作结束,才能进行行的另一个操作

    锁表:锁定表,要对一个非索引行操作(没有索引要全表扫描,以至于锁定整个表)

    解决方法:commit之后立即生效

    对非索引参数进行操作:

    解决方式也是对上一个操作进行commit提交,提交之后才能进行下一个操作:

    当一个事务对非索引列进行操作,因为要全表扫描过滤,所以整张表都会被锁定,另一个事务只能查询操作

    排它锁:

    又叫悲观锁。一个事务在操作,另一个事务的操作无法执行,只能查。排它锁只能加一个。

    for update 排他锁

    select * from test where id = 2 for update;

    死锁:(基于排它锁)

    事务之间相互等待对方资源,最后会形成一个环路造成的。

    死锁基于排它锁形成

    死锁形成时:

    1. 发生死锁的时候,数据库会自动选择一个事务作为受害者,然后先接触死锁,在回滚
    2. mysql默认的死锁机制,一旦发生死锁,会选择一个事务作为死锁的牺牲品,直接终止其中一个事务,但是不会自动回滚

    总结:

    索引只会锁行

    非索引锁表

    排它锁

    死锁,会自动选择一个事务作为牺牲品,结束死锁。

    乐观锁:不会有任何提示,只是数据不能写入而已。数据提交更新时,他会进行校验,发生冲突,数据不生效而已,没有其他的报错或者是卡停

    一般来说,我们会在表中配置version字段,通过自增校验来查看数据是否冲突

    除了version 也可以用时间戳timestreap

    存储引擎只能是INNODB

    mysql默认隔离级别即可

    6、如何尽可能的避免死锁:
    1. 业务的逻辑要合理,以固定的顺序访问表和行
    2. 如果事务的类型比较复杂,要进行拆分,在业务允许的情况下,把大事务拆小,分次执行
    3. 在同一事物中,尽可能的一次锁定所有需要的资源。可以减少死锁的概率
    4. 隔离级别,read committed可以避免死锁
    5. 添加合理的索引(操作索引只锁行),减少死锁的概率

    核心内容:

    索引和行锁之间的关系

    非索引的锁表以及死锁

    排它锁

    INNODB的机制和存储文件的格式。

  • 相关阅读:
    IP rDNS(PTR)信息从理解到情报挖掘
    独享IP是原生IP吗?二者有何区别?
    pytorch中.to(device) 和.cuda()的区别
    学校介绍静态HTML网页设计作品 DIV布局学校官网模板代码 DW大学网站制作成品下载 HTML5期末大作业
    PCL 点云镜像变换
    11.MySQL多表查询简介
    GIS实战应用案例100篇(十四)-ArcGIS属性连接和使用Excel的问题
    sql小技巧:日期区间和格式化操作
    Leetcode Top 100 Liked Questions(序号198~234)
    三、静态路由实验
  • 原文地址:https://blog.csdn.net/koeda1/article/details/134255957