索引:是一个排序的列表 列表中存储的是索引的值和包含这个值数据所在行的物理地址
索引的作用
- 利用索引数据库可以快速定位 大大加快查询速度
- 表的数据很大 或查询需要关联多个表 使用索引也可以查询速度
- 加快表与表之间的连接速度
- 使用分组和排序时可以大大减少时间
- 提高数据库恢复数据时的速度
索引创建的原则:
- 有索引 数据库会先进行索引查询 然后定位数据 索引使用不当 反而会增加数据库负担
- 主键 外键 必须有索引(创建好的主键和外键自动就是索引 不需要额外声明)
- 一个表超过了300行记录 必须有索引 否则数据库会遍历表中所有数据
- 互相之间有关联的表 在这个关键字段设置索引
- 唯一性太差的字段 不适合做索引
- 更新频繁的字段不适合做索引
- 经常被where条件匹配的字段 尤其是数据比较多的 应该创建索引
- 在经常进行group by(分组语句)order by(排序语句) 上要建立索引
- 索引列的字段越小越好 长文本字段不适合建立索引
索引的类型:
排序时 索引是失效的
常用类型:
B-树索引 BTREE索引 树行结构索引 也是大部分数据库的默认索引类型
叶子节点:直接指向表里的数据
分支节点:指向索引里其他的分支节点 也可以是叶子节点
根节点:指向分支节点
哈希索引:
把任意长度的输入 通过散列算法变成固定的长度的输出 散列值分别对应数据里的列和行
MySQL的默认引擎是innodb
Memory引擎可以支持哈希 默认索引就是哈希索引
先算散列值 然后对应 速度较慢
哈希索引匹配方式 = in() <= >
查看表的索引:
Show index from 表名;
创建btree索引
Create index name_index on 表名 (name);
创建索引需要考虑因素:
索引的副作用:索引也需要占用额外的磁盘空间innodb表数据文件本身也是索引,myisam:索引和数据文件是分离的。更新一个包含索引的表,要比更新一个没有索引表花费的时间更多。更新值了值,也就是更新索引。
创建索引:
普通索引 唯一索引
Index name_index(name):创建普通索引
唯一索引:
Unique 与普通索引类似 唯一索引的每个值都是唯一 唯一索引允许空值 添加唯一键才会创建唯一索引 最好不要为空 not null
以添加方式创建唯一索引
Alter table 表名 add unique 索引名(表名);
能在建表时创建好的条件 尽量在创建时把条件约束好 不要创完之后再添加
主键索引 创建表的指定的主键就是索引 添加主键自动就是主键索引
主键:值唯一 一个表只能有一个主键 不允许有空值 创建主键自动创建主键索引
全文索引 一般用于长文本列 text 适合在进行模糊查询的时候使用 可以在一边文章中检索文本信息
在建表中写:fulltext 索引名(列名);
通过修改添加:Create fulltext index 索引名 on 表名(列名);
删除索引
Drop index 索引名 on 表名
模糊查询
Select * from 表名 where 列名 like ‘%’
Explanin加select 查询索引是否生效
如何创建联合索引 指定一个索引名 一个索引名对应多个列名
Create index 索引名 on 表名 (列名,列名);
Explain select * from 表名 where 列名 like ‘%’;
联合索引查询时 必须按照创建时的顺序查询 否则索引会失效
MySQL机制默认会找最短的索引列 最优索引选择
范围查询 有可能右侧的索引会失效
如果索引是字符串 但是不加引号也会失效
使用or语句 索引一定失效 MySQL无法同时使用多个索引
Is not null 有时索引会失效 where is null 如果数据绝大多数都是空值 索引失效
Where is not null 如果数据多数不为空 索引也会失效
In 和 not in
全文索引要用
索引总结
类型:普通索引 主键索引 唯一索引 全文索引 联合索引
创建索引时 注意索引失效情况 explain加在查询语句前 可以查看索引使用情况
面试题:一张表的查询速度是7.62s 该如何解决
首先检查缓存 看是不是请求直接到后端数据库
再看索引 请求的列值不是默认的索引 添加一下即可 用explain查看
MySQL事务:
事务是一种机制 一个操作序列 包含了一组数据库的操作命令 所有命令都是一个整体 想系统提交或撤销的操作 要么都执行 要么都不执行
不可分割的单位
事务的特点ACID:
A 原子性 最小单位 事务里的所有条件都是一个整体 不可分割 要么都成功 要么都失败
C 一致性 事务开始前和事务开始后 数据库的完整性约束没有被破坏 事务完成时 数据必须属于一致状态 事务开始时 数据库中的存储数据属于一致状态 进行中的事务 数据可能处于不一致的状态 在事务最终处理完后 必须再次回到已知的一种状态
I 隔离性 指在并发环境中 不同事务同时操作相同的数据时 每个事务都有各自完整的数据空间 对数据修改的所有并发事务是彼此隔离的 表明事务必须是独立的 修改数据的事务可以在另一个使用相同数据的事务开始之前访问这些数据 或者在另一个使用相同数据的事务结束只会访问这些数据
MySQL支持的四种隔离级别:
- 未提交读 允许脏读 允许一个事务可以看到其他事务未提交的修改
- 提交读 事务只能查看已经提交的修改 未提交的修改不可见 防止脏读 oracle SQL sever
- 可重复读 是MySQL默认隔离级别 确保如果在一个事务中执行两次相同的查询语句时 都能得到相同的结果 不管其他事务是否提交修改 可以防止脏读以及不可重复读
- 串行读 锁表 完全串行化 每一个事务都隔离 读写都会堵塞 降低数据库效率
脏读:另外一个事务可以看到另外一个事务未提交的修改结果
事务隔离级别的作用范围:
- 全局级 对所有的会话有效
- 会话级 只对当前会话有效
SELECT * FROM vip_member;
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';
临时修改会话隔离级别
FLUSH PRIVILEGES;
刷新
不可重复读:一个事务内 多次读同一数据 前一个事务还没有结束 另一个事务也访问该数据 在一个事务
内 两次查询到的结果不一致 读不到相同的数据内容
先把全局和会话改成提交读
FLUSH PRIVILEGES;
幻读:一个事务对一个表中的数据进行了修改 可能会涉及到全部数据
另一个事务也修改了这个表的数据 插入了一行新的数据 前一个事务会发现
表中还有数据没修改 类似幻觉
丢失更新:两个事务同时修改一条记录 a先记录b也修改了记录 b提交会覆盖a的结果
如何避免 :
权限控制
根据情况使用隔离级别
生产环境允许一个人对一个事务进行操作 其他人不允许操作
D:持久性 数据一旦提交 事务效果将会永久保留在数据库中 而且不会被回滚
总结:
在事务管理中 原子性是基础 隔离性是手段 一致性是目的 持久性是最终结果
事务的控制语句:
Begin
Start transaction 都可以作为显示的开启事务
Commit
Commit work 都可以作为提交事务
Rollback
Rollback work 都可以作为回滚事务 撤销正在进行的所有未提交的修改
Cavepoint 自定义名 创建还原 一个事务可以有多个回滚点
Rollback to 自定义名 回滚到哪个还原点
多点还原时 注意顺序
MySQL提交事务默认是自动提交
一旦提交 还原点全部消失
Set设置mysql的提交方式
Show variables like ‘autocommit’
关闭自动提交
Set autocommit = 0 如果不自动提交会怎么样
存储引擎
在MySQL中 数据用各种不同技术存储在文件中 每一种技术都使用一种不同的存储机制 索引技巧 锁定水平以及最终提供的不同的功能和能力
功能:
- MySQL将数据存储在文件系统中的一种方式和格式
- 存储引擎负责执行实际的数据I/O操作
- 存储引擎介于数据和文件系统之间 数据会先保存到存储引擎 再按照存储引擎的格式保存到文件系统
MySQL存储引擎的分类:
- INNODB 5..5后MySQL的默认存储引擎 事务性速记引擎 支持ACID事务 支持行锁 锁表 写入和查询性能比较好
- MYISAM 5.5之前默认存储引擎 有较高的插入性能 查询速度也很优秀 不支持事务
- MEMORY 所有数据保存在内存的存储引擎 插入数据 更新数据 查询数据 速度都很快 占用内存空间较大 会占用和数据量成正比的内存空间 MySQL一旦重启 内容丢失
- CSV 由逗号分割数据的存储引擎 会在数据库子目录里为每一个数据表创建一个.csv文件 就是一种文本文件 每个数据行占用一个文本行 csv不支持索引
- ARCHIVE 适合存储大量的独立的历史数据的引擎 不需要被经常读取 插入的速度高 查询速度低
- Blackhole 黑洞引擎 写入的任何数据都会消失
Myisam和INNODB对比:
Myiam:不支持事务 不支持外键 只支持全文索引 数据文件和索引文件分开的 访问速度快 适用场景:查询和插入数据为主的应用
在磁盘上会有三个文件 文件名和表名相同 扩展名不同
.frm 存储表结构 .myd 存储数据文件 .myi 索引文件
Myisam的特点
- 表级锁定 更新数据时 整个表都将锁定
- 数据库在读写过程中相互阻塞
支持的存储格式
- 静态表
- 动态表 包含可变字段
Innodb:
支持事务 支持四个事务的隔离级别 是MySQL的默认存储引擎 读写阻塞和隔离级别相关
支持高效的缓存索引和缓存数据
表与主键以簇方式存储btree
支持外键约束 5.5后可以支持全文索引
对硬件要求比较高 支持行锁定(全表扫描)
- 使用like模糊查询会进行全表扫描 锁定整个表
- 对没有创建索引的字段进行查询也会进行全表扫描 锁定整个表
- 使用索引 进行查询 则是行级锁定
特点:
不保存表的行数 统计表的行数 会扫描全表来计算有多少行
自增长字段 innodb中必须包含只有改字段的索引
Delect清空表 一行一行删
适用场景:
- 业务需要事务的支持
- 论坛 微博 对数据一致性要求高的场景
- 访问量和并发量比较高的场景 可以支持缓存 减少磁盘压力
三个文件:
表名.frm(表结构文件)
表名.idb(既是数据文件 又是索引文件)
表名.opt(表的属性文件)
Innodb行锁和索引的关系以及表锁 排他锁 死锁
CREATE TABLE IF NOT EXISTS test(
id INT(5) PRIMARY KEY,
name CHAR(8),
age INT(3),
sex CHAR(2)
);
ALTER TABLE test ADD INDEX name_index(name);
SHOW INDEX FROM test;
INSERT INTO test VALUES (1,'张三',90,'男');
INSERT INTO test VALUES (2,'张四',11,'男');
INSERT INTO test VALUES (3,'张五',12,'男');
INSERT INTO test VALUES (4,'张六',19,'男');
INSERT INTO test VALUES (5,'张七',17,'男');
INSERT INTO test VALUES (6,'张八',18,'男');
SELECT * FROM test;
begin;
UPDATE test SET age=90 WHERE id = 1;
UPDATE test SET sex='女' WHERE name='张三';
如果name字段是一个普通索引 会所著索引行 对应的主键一并锁住 实际上就是行锁
SELECT * from test where id = 1 ;
UPDATE test SET sex='女' WHERE name='张四';
commit;
如果使用的id的字段是主键 innodb对主键适用聚簇索引 直接锁定整行记录
锁定表 要对一个非索引键进行操作
begin;
UPDATE test set name='张八十' WHERE age = '18';
当一个事务对非索引列进行操作 因为要全表扫描过滤 整张表都会被锁定 另一个事务只能查
死锁 事务相互等待对方资源 最后形成环路
FOR UPDATE 排他锁 悲观锁
1、当死锁发生时 数据库会自动选择一个事务作为受害者 然后先解除死锁 再回滚事务
2、MySQL默认的死锁机制 一旦发生死锁 会选择一个事务作为死锁的牺牲品 直接终止
其中一个事务 但是不会自动回滚
存储引擎只能是innodb MySQL默认隔离级别即可
如何尽可能避免死锁
业务逻辑要合理以固定的顺序访问表和行
如果事务的类型比较复杂 要进行拆分 在业务允许的情况下 把大事务拆小
在同一事务中 尽可能一次性锁定所有需要的资源 减少死锁的概率
隔离级别 避免死锁可以使用read commit
添加合理的索引可以减少死锁的概率
乐观锁 不会有任何提示 只是数据不能写入 数据提交更新时 进行校验 发生冲突 数据不生效 没用其他的报错或卡停
在表中配置一个version字段 可以自增 通过自增校验查看数据是否冲突 通过时间戳查看是否冲突