mysql搜索引擎
MyISAM:不支持事务、外键,非聚簇索引(B+数 根据主键索引查到到物理地址,根据物理地址查对应数据)、支持全文索引,最小锁粒度是表锁(这也是Mysql常用Innodo的关键原因) 存储文件: .frm(表的定义) .myd(数据扩展文件) myi(索引文件)
Innodb:支持事务、外键,聚簇索引(索引和数据存储在一起)、不支持全文索引(但是可以使用插件来支持全文索引sphinx),最小锁粒度是行锁。 存储文件: frm(表定义文件) ibd(数据和索引存储文件,聚簇索引 会将索引和整行数据存储到叶子节点)
mysql索引
聚簇索引(主键索引):将索引行数据全部存储到索引表中(索引的叶子节点)(一个表中只有一个聚簇索引 默认是主键,如果没有设定主键 会找到第一个唯一索引作为聚簇索引,如果前者也不满足,InnoDB会生成一个隐藏的聚集索引GEN_CLUST_INDEX)
普通索引:只会存储索引列的值(会记录行号)
覆盖索引:查询列和索引列是一致的(推荐使用覆盖索引,因为一次查询就可以查询到对应数据,如果不使用覆盖索引需要俩次查询才可以查到对应的数据)
联合索引:遵循最左前缀规则(比如索引顺序ab a是有序的 a=1的时候b才是有序的,如果where b=1 就不会走索引 in or like 函数计算 都会导致索引失效)
辅助索引(除聚簇索引外都叫辅助索引):根据索引字段查到对应主键值 根据主键值去聚簇索引查到对应行数据
索引的数据结构
二叉查找树:左子树小于根的键值 右子树大于根的键值
平衡二叉查找树:用来解决二叉查找树的缺点(平衡问题,俩个子树最大高度差别是1 如果超过1通过自旋的方式来保证平衡),无法保证树的高度,树越高查询效率越低,进行范围查找还需要多次回表查询
B树:解决平衡二叉查找树的缺点(减少树的高度,提高查询效率),每个节点可以存储俩个数据,进行范围查找还需要多次回表查询
B+树:解决范围查询回表查询,叶子节点用链表连接起来
mysql隔离级别
读未提交:事务读取其他事务未提交的数据(最低级别,解决不了任何事务传播行为)
读已提交:事务只能读取其他事务提交的数据(解决了脏读)
可重复读:事务多次读取同一个字段的值相同,在操作期间,禁止其他事务对这个字段进行更改(update)(解决了脏读、不可重复读、幻读(innoDb除外,通过快照读和当前读))
可串行化:确保一个事务可以从一个表中读取相同的行,在没结束前,所有增加删除查询都被禁止,所以性能很低(最高级别(解决一切传播行为),增加了读锁)
mysql事务传播行为
脏读:一个事务读取另一个事务未提交的数据
不可重读:并发更新的时候 一个事务俩次读取的数据不一致
幻读:并发增加、删除对数据量产生变化的时候,一个事务前后读取的数据量不一致
mysql锁机制
行锁:锁住一行数据,事务提交以后释放锁
表锁:索引失效会有行锁升级为表锁,锁住整个表
间歇锁:范围查到时,根据范围锁住行数据
mysql事务四大特性(ACID)
原子性:要么全部成功、要么全部失败,主要是采用Undolog 来实现(如果一个sql执行失败,要回滚到上一个版本,undolog会记录sql执行过程,回滚的时候根据相反规则 比如执行insert回滚会执行delete)
一致性:事务执行成功之后,数据库完整性没有被破坏,执行的合法性,比如数据库表主键不能被破坏、字段大小不能改变(原子性、隔离性、持久性 来最终保证一致性)
隔离性:写-写操作(通过锁来实现,保证一行数据只有一个事务在操作,提交事务之后释放锁,另外一个事务才可以拿到) 读-写(mvcc)
持久性:事务一旦提交,数据就是持久性的,不会被破坏 永久保存到数据库中,主要采用的redolog(数据库是把数据存储到磁盘中,每次查询都会产生IO操作,为了减少IO,数据库引用了buffer(缓存),每次查询先从buffer查询,查不到在查询磁盘数据,在写入到buffer中,每次插入数据的时候会先插入buffer里,后面会根据随机IO写入到磁盘中,这样会产生数据丢失的问题,如果buffer中的数据还未写入到磁盘中,mysql宕机了。redolog是会记录每次数据操作的日志通过顺序IO写入到磁盘中,日志写入和磁盘写入是同步进行的,这样就不会担心数据丢失的问题)
mysql MVCC机制(多版本并发控制,提高数据库并发性能)
注释:同一行数据发生读写操作时,会上锁导致阻塞,mvcc解决了这个问题(这里的读是指的快照读而不是当前读,当前读是上锁 悲观锁)
当前读:读取的数据都是当前数据库最新的数据,会对当前数据上锁,导致其他读操作阻塞 delete update insert for update(排他锁) select lock in share mode(共享锁) 这些操作都是当前读 对数据进行修改需要先读取当前数据
快照读:基于多版本并发控制实现的,即MVCC 读取的数据可能不是最新数据 是历史数据 即不加锁的select(事务隔离级别不是:可串行化)mvcc组成:undolog(事务日志) 版本链(根据事务自增id和上一个事务数据指针组成的) ReaDView(根据版本链选取哪条数据)
ReaDView读视图组成:
m_ids:当前活跃事务编号集合(未提交的事务)
min_trx_id:最小活跃事务编号
max_trx_id:预分配事务编号,当前最大事务编号+1
creator_trx_id:创建readview 的事务idreadView是怎么判断从版本链中select数据:
trx_id:当前事务id
1、 trx_id = creator_trx_id 可以访问
2、 trx_id < min_trx_id 可以访问
3、 trx_id > max_trx_id 不可以访问
4、 min_trx_id <= trx_id <= max_trx_id trx_id在m_ids中不可以访问 反之可以访问RC(读已提交):会产生不可重复读,同一个事务里面每次select都会生成新得readview,这样就会产生俩次select的值不重复的问题)
RR(可重复读):同一个事务里,第一次select会生成readview,以后每次select都会复用这个readview,这样就解决了不可重复读的问题,也同样解决了幻读问题,因为我一直操作第一个生成的readview,其他事务操作并不影响,但是如果俩次快照读增加了当前读切覆盖到其他事务新增的数据,这样就会产生幻读。(当前读是通过间歇锁来解决幻读的,根据范围锁住所有数据,其他事务不可操作)
技术问题:
NO1:
问题:count(字段)< count(uid)< count(1) <= count(*) 性能排序
解答:count(1)和count(*)都是通过遍历主键索引数进行++操作 性能基本相同 count(uid)也是根据遍历主键索引数就是++ 但是他会返回主键uid 所以说慢一些 count(字段)每次进行++操作需要判空 所以性能最低