MySQL进阶 面试速记
存储过程,自定义函数在现在的数据库使用中,就很少使用了
MySQL 架构
authentication 认证 身份认证 账号密码验证-->token
authorisation 授权 -->分配权限菜单
连接层
在mysql服务中,负责客户端连接,进行身份认证,授权
服务层
在服务层进行sql分析,优化,各种逻辑的处理等.
引擎层
引擎层是实际负责数据存储和提取操作. mysql提供了不同的引擎(处理方式),可以根据需要进行选择
物理文件存储层
实际的文件存储, 包括存储数据的文件,还有各种日志文件
mysql引擎
引擎就是实际的负责数据存储和提取操作的一种实现方式,不同引擎实际处理方式不同,
mysql中提供多种引擎.
mysql中有以下引擎:
InnoDB: 支持事务(安全可靠),支持行级锁(锁的粒度小,并发量高),支持外键约束,支持全文索引,
支持数据缓存,提高查询的效率, 不存储总行数( select count(*) from table 统计总行数 逐行统计)
MyISAM :
myisam不支持事务,不支持外检,不支持行级锁, 支持表锁(并发量低), 适合写少,查询多的场景.
支持全文索引, 存储表的总行数
索引
什么是索引
索引是一种有序的数据结构,可以帮助mysql快速的查找到数据.
如果数据库中的数据量非常大,那么逐页,逐行查询效率就很低.
索引类似于书的目录,可以帮助我们快速的定位到具体的页数.
索引优势/劣势
优点: 可以快速的定位到数据,减少于硬盘的IO成本
由于索引已经排好序了,减少排序成本.
缺点: 索引信息也是需要占用空间的, 当数据发生改变时(新增,删除)那么索引信息也要发生改变.索引虽好,不能乱用.
索引创建原则
哪些情况需要创建索引
主键自动建立唯一(主键)索引
作为查询条件的列 列如姓名,电话
尽量使用联合索引(几个列添加一个索引),减少单列索引
数据量较大的表,
排序和分组使用的字段
哪些情况不要创建索引
如果数据量很小,没必须加索引(例如新闻类型, 数据量很少)
频繁修改的表,不仅要修改数据,还要修改索引
不是查询条件的列就不要加索引了
重复出现很多的数据,例如性别
索引分类
如何在表中加索引
主键索引
把某个列设置为主键后,自动创建主键索引,
-- 创建表时添加注解索引 CREATE TABLE test( id INT PRIMARY KEY ) -- 修改表结构,添加主键 ALTER TABLE test ADD PRIMARY KEY test(id) -- 删除主键 ALTER TABLE test DROP PRIMARY KEY ;
唯一索引
CREATE UNIQUE INDEX 索引名 ON 表名(列名); DROP INDEX 索引名 ON test;
单值索引
一般的列多数添加的都是单值索引,用的最多的.
CREATE INDEX 索引名 ON 表名(列名); DROP INDEX 索引名 ON 表名;
组合索引(复合索引):
一个索引中包含多个列,降低索引开销(推荐)
CREATE INDEX 索引名 ON 表名(列 1,列 2...); DROP INDEX 索引名 ON 表名;
组合索引使用时,需要满足组合索引最左前缀原则,
ALTER TABLE test ADD COLUMN a VARCHAR(8); ALTER TABLE test ADD COLUMN b VARCHAR(8); ALTER TABLE test ADD COLUMN c VARCHAR(8); CREATE INDEX test_a_b_index ON test(a,b); EXPLAIN SELECT * FROM test WHERE a='1' AND b='1' 索引生效 EXPLAIN SELECT * FROM test WHERE a='1' AND c='1' 索引生效 EXPLAIN SELECT * FROM test WHERE b='1' AND c='1' 没有使用最左列,索引失效 通过EXPLAIN关键字查看sql执行计划 EXPLAIN SELECT * FROM test WHERE NAME = '1' EXPLAIN SELECT * FROM test WHERE NAME LIKE '%1%'
前缀索引
有的列中的内容比较长(新闻摘要,内容),如果给该列建立索引,对索引开销就很大,
给指定长度的区间内容建立索引
create index 索引名 on 表名(列名(长度))
全文索引
解决了mysql中模糊查询索引失效的问题
CREATE FULLTEXT INDEX 索引名 ON test(列) WITH PARSER ngram; SELECT * FROM 表名 WHERE MATCH(列) AGAINST('搜索词') EXPLAIN SELECT * FROM 表名 WHERE MATCH(列) AGAINST('搜索词')
索引数据结构
索引结构使用的是B+树.
首先b+树也是有序的,而且一个节点可以存储多个数据,非叶子节点只存储索引数据,
所以每个节点可以存储更多的索引数据,
数据存储在叶子节点,叶子节点直接还有指针指向,更方便范围查询 例如 id>2
聚簇索引和非聚簇索引
聚簇索引:
找到了索引就找到了需要的数据,那么就是聚簇索引.
mysql中innodb引擎中的主键索引就是聚簇索引,
因为数据和索引都在一个文件中存储,主键索引是一级索引,直接与数据绑定
还有像name等其他索引是属于二级索引,如果通过name进行查询学生信息,先在name二级索引树上查找,找到了然后再通过name对应的主键去主键索引树上找到数据,那么这些二级索引属于非聚簇索引.
非聚簇索引:
找打了索引但是还没找到数据,需要再次回表查询,才能找到数据.
innodb中的二级索引属于非聚簇索引.
myisam中索引和数据分别存储在不同的文件中,所以是非聚簇的.
回表查询
回表查询就是查询时,一次并没有查询到我们需要的数据,而是需要再次进行查询.
例如学生信息有id(主键),学号(唯一索引 二级索引),姓名(没有加任何索引),
如果我们通过主键查询学生所有信息,那么是直接可以找到数据的,不需要二次回表查询
如果我们通过学号查询学生所有信息,先在学号索引树上找到学号,以及主键,然后再二次上主键索引树上查找,才能找到数据,就是发生了两次查询,称为回表查询了.
如果我们通过学号只查询学号,可以直接在学号索引树上找到数据,不会二次回表.
索引下推
索引下推是mysql中的一项优化技术,尽量在条件查询时,减少回表查询数量.
将部分条件(有索引的条件)查询 下推到索引扫描阶段.
如果我们查询条件添加了索引,使用索引下推,可以直接在索引树上进行条件筛选,把满足条件的数据进行回表查询,
减少了回表查询的条数.
注意索引下推,查询条件必须是有索引的.
数据库事务
什么是事务?
数据库事务就是对一次数据库操作过程的管理.保证一次与数据库交互过程中执行的多条sql要么都成功执行,要么都不执行,保证原子性.
例如转账,一次转账操作有两个sql,一个给A账号减钱, 一个给B账号加钱,保证两个操作都没有问题
例如购物下订单, 一个是卖家下订单,一个付款.
事务的特征
原子性:保证一次操作中的多条sql在没有问题时,提交事务,多条sql都执行,一旦有问题,事务回滚,回滚到事务开始前的状态.
隔离性:数据库为提高读写的并发性,提供4种隔离级别: 读 未提交,读 已提交,可重复 读,串行化(一个一个来)
持久性:当事务一旦提交后,保证数据的持久化.
一致性: 是事务的终极目标, 以上三点都是为了保证一致性,当多个事务同时对一条数据多次操作时,最终结果与我们预期结一致.
隔离级别
读 未提交: A事务可以读取到B事务还未提交的数据. 并发访问量是最高的
产生问题: 脏读,不可重复读,幻读
脏读,读到的是垃圾数据, A查询到了 B事务还未提交的数据,此时一旦B事务撤消回滚了,数据是无效的.
读 已提交: A事务只能读到B事务已提交的数据,
解决了脏读问题, 但是还存在不可重复读问题,幻读
不可重复读问题: A事务在同一个事务中,读取相同的内容两次,而两次的结果不同.
例如: A事务第一次读id=1,拿到的结果是10,
继续还在这次事务中,又读了一次id=1,结果读到是20,两次结果不同,
可重复 读: A事务在同一个事务中,读取相同的数据两次,两次读到的结果是一致的,即使期间其他的事务修改了数据,并提交了,同一个事务读到了同一个数据的结果是一样的.
解决了 不可重复读问题, 一般的查询也解决了幻读问题.
在查询语句后面,如果添加了for update 这样查询语句,拥有了与新增,修改,删除同等的权利,还是会出现幻读问题.
幻读问题: 同一个事务中,读取了两次,而两次读到数量不一致
串行化: 和加锁一样的,不管是查询也好,还是新增,修改,删除也好,一次只能允许一个事务操作.
两个事务都是读,不互斥
读写,写写都是互斥的.
保证数据安全可靠,但是效率也是最低的.
事务实现原理
持久性: 在事务提交后,先把数据写到redo log日志文件中,再向库中去持久化,一旦期间断电宕机,那么服务恢复后,会将redo log文件中的数据再次写入到库中.
原子性:当执行insert操作时,在undo log日志文件中存储一个相反的delete操作,当事务回滚撤消时,执行相反的操作.
隔离性:
MVCC(多版本并发控制 Multi-Version Concurrent Control)
实现不同的事务在写-读,读写操作时,可以同时进行,提高并发访问能力
每次事务在对数据操作 后,都会在表中的隐式字段中记录当前操作者的id,和上一个记录的回滚指针,从而形成一个版本链.
读视图(readView),从版本链上进行的一个快照.
读 已提交: 称为当前读, 每次读取时,都会获取一个最新的快照, 即使是在同一个事务中的两次读取.都是读到最新内容.
可重复 读:称为快照读,在同一个事务中,第一次查询时,生成一个版本快照(readview),下一次再读取时,还是从快照中读,这样就保证可重复读.
一致性: 由其他三个特性来保障
锁机制
锁机制保证了进行数据操作时,保证写操作安全可靠.
锁按照粒度分:
全局锁: 对数据库进行备份时,锁住整个库
FLUSH TABLES WITH READ LOCK mysqldump --single-TRANSACTION -uroot -proot test> E:/文件名.sql UNLOCK TABLES;
表级锁: 表级锁,就在操作时,会锁住整张表,加锁开销小,但是并发量低.
myisam引擎只支持表锁 myiam适合读多写少的场景
行级锁: 行级锁就是只锁住操作的那一行数据
间隙锁: 对与范围操作的 id>1 and id<10 对此区间间隙进行加锁
按照锁的行为分:
排他锁: (写锁)新增,修改,删除操作时,默认加的就是排他锁,锁住操作的那行数据
查询语句如果执行时,需要添加排他锁,需要在查询语句末尾添加for update
共享锁:(读锁) 是用于给查询语句添加的,如果事务1给行1添加了共享锁,那么其他事务只能给行1添加共享锁
其他事务不能给行1添加排他锁
select ... lock in share mode
Sql 优化
目前讲的只是写sql基本的一些注意事项.
物理删除(真删), delete 操作
逻辑删除(假删),update操作 在表中会有一个列,表示删除状态 0-未删除,1-已删除
1.查询时,只查询需要的列
尽量不使用 select *
2.能使用整数的列,不要使用字符
例如mysql主键 使用int 自增
性别, 可以用0/1表示,
还有各种状态 0- 1- 2- 3-
3.
varchar : 变长字符串 varchar(5) 表示最大上限是5个字符, 实际存储2字符,只占两个字符大小
char: 定长 char(5) 固定存储5个字符, 实际存储2个字符,还是占用5个空间
char一般存储的长度固定的内容,varchar用于存储长度不固定的内容
4.清空表数据
truncate table 比 delete 速度快,且使用的系统和事务日志资源少.
delete 语句每次删除一行,并在事务日志中为所删除的每行记录一项。
truncate table 通过释放存储表数据所用的数据页来删除数据.
5.建立索引
where order by group by 涉及的列添加索引, 提高效率 避免全表扫描
注意创建索引原则
6.避免索引失效
模糊查询, 在条件上使用函数, in,not in or 这些语句导致索引失效
-
order by写法 先条件筛选,再分组 切勿先分组,再条件筛选
-
减少表关联查询的数量, 阿里建议3张表. 索引也不宜过多
-
避免深度分页问题
分页是为了减少每次查询过多数据
selelct * from table limit 1000000,10 深度分页
select id,name FROM account where id > 100000 order by id limit 10; 先条件过滤,然后再取值
10.使用explain关键字查看sql执行计划
explain select * from test where a = 10
possible_keys : 查询中可以使用的索引
key: 本次查询实际使用到的索引 (查看索引是否有效)