巩固基础,砥砺前行 。
只有不断重复,才能做到超越自己。
能坚持把简单的事情做到极致,也是不容易的。
mysql怎么优化 : MySQL的优化可以从以下几个方面入手:
- 数据库设计优化:合理设计表结构,选择合适的数据类型,规范化表结构,避免冗余数据等。
- 索引优化:为经常查询的列添加索引,合理选择索引类型,避免使用过多的索引。
- SQL语句优化:避免使用SELECT *,使用JOIN代替子查询,尽量避免使用LIKE和%等模糊查询,使用EXPLAIN查看SQL语句执行计划。
- 缓存优化:使用缓存来减少对数据库的访问次数,如使用Redis缓存热门数据。
- 硬件优化:增加内存、优化磁盘I/O等,提高服务器的性能。
- 代码优化:优化应用程序代码,减少不必要的数据库操作,避免频繁的连接和关闭数据库。
- 定期维护:定期备份数据、优化表、清理日志等,保持数据库的稳定性和高效性。
数据库怎么调优 : 数据库调优是指通过优化数据库的性能,提高其响应速度和处理能力,从而提高系统的整体性能和稳定性。以下是一些常见的数据库调优方法:
1.优化查询语句:尽量避免使用SELECT *等大量数据的查询语句,使用索引查询,避免JOIN查询等。
2.优化索引:合理设计数据库索引,删除不必要的索引,使用覆盖索引等。
3.优化表结构:合理设计表结构,避免使用大量的NULL值,避免使用过多的TEXT、BLOB类型的数据。
4.优化缓存:增加缓存大小,调整缓存策略,避免频繁的I/O操作。
5.优化参数设置:根据实际情况调整数据库的参数设置,如缓冲池大小、连接数、查询缓存等。
6.优化存储引擎:选择合适的存储引擎,如MyISAM、InnoDB等。
7.分区和分表:对于大型数据库,可以根据数据的特点进行分区和分表,提高查询效率和可维护性。
8.定期维护:定期进行数据库的备份、清理和优化,避免数据紊乱和性能下降。
总之,数据库调优需要根据具体情况进行定制化的优化方案,综合考虑数据库的硬件环境、软件配置、应用需求等因素。
Mysql慢查询该如何优化?
1.检查是否走了索引,如果没有则优化SQL利用索引
2.检查所利用的索引,是否是最优索引
3.检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据
4.检查表中数据是否过多,是否应该进行分库分表了
5.检查数据库实例所在机器的性能配置,是否太低,是否可以适当增加资源
Mysql锁有哪些,如何理解
按锁粒度分类:
1.行锁:锁某行数据,锁粒度最小,并发度高
2.表锁:锁整张表,锁粒度最大,并发度低
3.间隙锁:锁的是一个区间
还可以分为:
1.共享锁:也就是读锁,一个事务给某行数据加了读锁,其他事务也可以读,但是不能写
2.排它锁:也就是写锁,一个事务给某行数据加了写锁,其他事务不能读,也不能写
还可以分为:
1.乐观锁:并不会真正的去锁某行记录,而是通过一个版本号来实现的
2.悲观锁:上面所的行锁、表锁等都是悲观锁
在事务的隔离级别实现中,就需要利用所来解决幻读
锁的类型有哪些
基于锁的属性分类:共享锁、排他锁。
基于锁的粒度分类:行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎)、记录锁、间隙锁、临键
锁。
基于锁的状态分类:意向共享锁、意向排它锁。
,共享锁(Share Lock)
共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。
排他锁(exclusive Lock)
排他锁又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取。避免了出现脏数据和脏读的问题。
表锁
表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行
访问;
特点:
粒度大,加锁简单,容易冲突;
行锁
行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他
的记录可正常访问;
特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高;
记录锁(Record Lock)
记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的
某一条记录。
精准条件命中,并且命中的条件字段是唯一索引
加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读
取的脏读问题。
页锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。
所以取了折衷的页级,一次锁定相邻的一组记录。
特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
间隙锁((Gap Lock)
属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一
个区间,遵循左开右闭原则。
范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别
中。
触发条件:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一个事务里,A事务的两次查询出的结果会不一样。
比如表里面的数据ID为1,4,5,7,10,那么会形成以下几个间隙区间,-n-1区间,1-4区间,7-10区间,10-n区
间(一n代表负无穷大,n代表正无穷大)
临建锁(Next-Key Lock)
也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来
的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住
触发条件:范围查询并命中,查询命中了索引。结合记录锁和问隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。
如果当事务A加锁成功之后就设置一个状态告诉后面的人,已经有人对表里的行加了一个排他锁了,你们不能对整个表加共享锁或排它锁了,那么后面需要对整个表加锁的人只需要获取这个状态就知道自己是不是可以对表加锁,避免了对整个索引树的每个节点扫描是否加锁,而这个状态就是意向锁。
意向共享锁
当一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁。
意向排他锁
当一个事务试图对整个表进行加排它锁之前,首先需要获得这个表的意向排它锁。
B树和B+树的区别,为什么Mysql使用B+树
B树的特点:
1.节点排序
2.一个节点了可以存多个元素,多个元素也排序了
B+树的特点:1.拥有B树的特点2.叶子节点之间有指针
3.非叶子节点上的元素在叶子节点上都冗余了,也就是叶子节点中存储了所有的元素,并且排好顺序
B树和B+树的区别,为什么Mysql使用B+树
B树的特点:
1.节点排序
2.一个节点了可以存多个元素,多个元素也排序了
B+树的特点:1.拥有B树的特点2.叶子节点之间有指针
3.非叶子节点上的元素在叶子节点上都冗余了,也就是叶子节点中存储了所有的元素,并且排好顺序
Mysql索引使用的是B+树,因为索引是用来加快查询的,而B+树通过对数据进行排序所以是可以提高查询速度的,然后通过一个节点中可以存储多个元素,从而可以使得B+树的高度不会太高,在Mysql中一个Innodb页就是一个B+树节点,一个Innodb页默认16kb,所以一般情况下一颗两层的B+树可以存2000万行左右的数据,然后通过利用B+树叶子节点存储了所有数据并且进行了排序,并且叶子节点之间有指针,可以很好的支持全表扫描,范围查找等SQL语句。
索引数据结构有btree和hash,但是我们一般使用的都是btree,为啥不用hash呢?
hash冲突,如果冲突了,数组就会扩容,;
不支持范围查找,如果这样查询,就会全表扫描。
雪花❄️算法也是递增,只不过不是严格的数据递增,而是趋势递增。
为什么会有最左元素匹配原则呢?
考虑索引的结构。
mysql:可重复读
oracle:读已提交
可重复读不仅针对当前数据,那一时刻的所有数据都被定格了
什么是回表?
查找到索引文件的地址后,还需要再次查找对应的数据文件。这个过程叫回表。
innodb的非主键索引,叶子节点存储的是索引下标,然后按照索引下标再去主键中查找对应的数据,也是回表。
聚集索引和非聚集索引的区别?
索引和数据在一起的就是聚集索引。innodb的主键索引就是聚集索引,myisam的主键索引就是非聚集索引,索引文件和数据文件是分开存储的,查找的时候,先到索引文件中查到对应的索引地址,再到数据文件中查找数据。索引所在行的整行数据
mysql聚簇和非聚簇索引的区别
都是B+树的数据结构
聚簇索引:将数据存储与索引放到了一块、并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的非聚簇索引:叶子节点不存储数据、存储的是数据行地址,也就是说根据索引查找到数据行的位置再取磁盘查找数据,这个就有点类似一本树的目录,比如我们要找第三章第一节,那我们先在这个目录里面找,找到对应的页码后再去对应的页码看文章。
优势:
1、查询通过聚簇索引可以直接获取数据,相比非聚簇索引需要第二次查询(非覆盖索引的情况下)效率要高
2、聚簇索引对于范围查询的效率很高,因为其数据是按照大小排列的
3、聚簇索引适合用在排序的场合,非聚簇索引不适合
劣势:
1、维护索引很昂贵,特别是插入新行或者主键被更新导至要分页(page sp1it)的时候。建议在大量插入新行后,选在负载较低的时间段,通过OPTIMIZE TABLE优化表,因为必须被移动的行数据可能造成碎片。使用独享表空间可以弱化碎片
2、表因为使用UUId(随机ID)作为主键,使数据存储稀疏,这就会出现聚族索引有可能有比全表扫面更慢,所以建
议使用int的auto_increment作为主键
3、如果主键比较大的话,那辅助索引将会变的更大,因为辅助索引的叶子存储的是主键值;过长的主键值,会导致非
叶子节点占用占用更多的物理空间
InnoDB中一定有主键,主键一定是聚簇索引,不手动设置、则会使用unique索引,没有unique索引,则会使用
数据库内部的一个行的隐藏id来当作主键索引。在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值
MyISM使用的是非聚簇索引,没有聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。
如果涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,
这些操作是需要在内存中完成的。
聚簇索引与非聚集索引的特点是什么?
在InnoDB中聚簇索引和非聚簇索引实际上是物理存储方式的一个不同。
聚簇索引
1.聚簇索引将数据存储在索引树的叶子节点上。
2.聚簇索引可以减少一次查询,因为查询索引树的同时就能获取到数据。
3.聚簇索引的缺点是,对数据进行修改或删除操作时需要更新索引树,会增加系统的开销。
4.聚簇索引通常用于数据库系统中,主要用于提高查询效率。
非聚簇索引(又称二级索引/辅助索引)
1.非聚簇索引不将数据存储在索引树的叶子节点上,而是存储在数据页中。
2.非聚簇索引在查询数据时需要两次查询,一次查询索引树,获取数据页的地址,再通过数据页的地址查询数据(通常情况下来说是的,但如果索引覆盖的话实际上是不用回表的)
3.非聚簇索引的优点是,对数据进行修改或删除操作时不需要更新索引树,减少了系统的开销。
4.非聚簇索引通常用于数据库系统中,主要用于提高数据更新和删除操作的效率。
什么是Hash索引?
哈希索引(hash index)基于哈希表实现。哈希索引通过Hash算法将数据库的索引列数据转换成定长的哈希码作
为key,将这条数据的行的地址作为value一并存入Hash表的对应位置。
在MySQL中,只有Memeory引擎显式的支持哈希索引,这也是Memory引擎表的默认索引结构,Memeory同时也支持B-Tree索引。并且,Memory引擎支持非唯一哈希索引,如果多个列的哈希值相同(或者发生了Hash碰撞),索引会在对应Hash键下以链表形式存储多个记录地址。
::哈希索引还有如下特点:
哈希索引不支持部分索引列的匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的。例
如,在数据列(A,B)上建立哈希索引,如果查询只有数据列A,则无法使用该索引。
哈希索引具有哈希表的特性,因此只有精确匹配所有列的查询对于哈希索引才有效,比如=、<>、IN(,因为
数据的存储是无序的),且无法使用任何范围查询。
因为数据的存储是无序的,哈希索引还无法用于排序。
对于精确查询,则哈希索引效率很高,时间复杂度为O(1),除非有很多哈希冲突(不同的索引列有相同的哈希值),如果发生哈希冲突,则存储引擎必须遍历链表中的所有数据指针,逐行比较,直到找到所有符合条件的行。哈希冲突越多,代价就越大!
InnoDB到底支不支持哈希索引?
对于InnoDB的哈希索引,确切的应该这么说:
•InnoDB用户无法手动创建哈希索引,这一层上说,InnoDB确实不支持哈希索引;
InnoDB会自调优(self-tuning),如果判定建立自适应哈希索引(Adaptive HashIndex,AHI),能够提升查询
效率,InnoDB自己会建立相关哈希索引,这一层上说,InnoDB又是支持哈希索引的;
那什么是自适应哈希索引(Adaptive Hash Index,AHI)呢?
1、自适应即我们不需要自己处理,当InnoDB引擎根据查询统计发现某一查询满足hash索引的数据结构特点,就
会给其建立一个hash索引;
2、hash索引底层的数据结构是散列表(Hash表,其数据特点就是比较适合在内存中使用,自适应Hash索引存
在于InnoDB架构中的缓存中(不存在于磁盘架构中)
什么是唯一索引?
讲起来非常简单,其实和“普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。可以是单列
唯一索引,也可以是联合唯一索引。
最大的所用就是确保写入数据库的数据是唯一值
什么时候应该使用唯一索引呢?
我们前面讲了唯一索引最大的好处就是能保证唯一性。看似没什么太大的价值,可能就会有同学说,我业务层做一个重复检查不就好了。问题就在这个地方,“业务是无法确保唯一性的”,除非你说你的代码没有BUG。很多时候业务场景需要保证唯一性,如果不在数据库加限制的话,总有一天会出现脏数据。
那又有同学就说了,既然你不想重复你可以使用主键索引。这个回答也很有意思。
我们确实可以通过主键索引来保证唯一,但是,如果你的数据不能保证有序插入。比如说身份证字段,
你如果用身份证字段作为主键的话,会导致查询效率降低。
唯一索引还有一个好处就是可以为空,真实的业务场景肯定是可以保证身份证为空的,如果没有绑定身
份证就不让注册好像也有点说不过去。
聚簇索引的原理就不在这里细讲了,会有一个单独的章节来介绍。
唯一索引是否会影响性能呢?
我找们通过和普通索引来做一个对比,有查询和插入两个场悬
首先第一个数据查询,一般情况下来说索引是通过 B+树 从根节点开始层序遍历到叶子结点,数据页内部通过二分检索
普通索引查到满足条件的第一条记录,继续查找下一条记录,直到找到不满足条件的记录
唯一索引 查到第一个满足条件的记录,就停止搜索。
InnoDB它是以数据页为单位进行读写的,我们读一条记录,并不是从磁盘加载一条记录,而是以页为单
普通索引比唯一索引就多了一次 查找和判断下一条 记录的操作,也就是一次指针寻找数据和一次计算。当然还有一种特殊情况,读取到的这条数据正好是数据页的最后一条,但是这种概率也是非常低,几乎可以忽略不计。
整体看下来看上去性能差距并不大对吧.
来看第二个更新的性能,我们按照上面图上的例子在 2 和6 之间插入一个 3.
在内存中
普通索引找到2和6之间的位置→插入值→
·唯一索引找到卫和6之间的位置→当判断有没有冲突→插入值→结束
不在内存中
普通索引 将更新记录在 change buffer→结束
•唯一索引 将数据页读入内存→当判断到没有冲突→插入值→结束
数据读取到内存涉及了随机|O访问,这是在数据库里面成本最高的操作之一,
而change buffer就可以减少这种随机磁盘访问,所以性能提示比较明显。所以在这一块来说,如果两者在业务场景下都能满足时可以优先考虑使用普通索引。
什么是联合索引,组合索引,复合索引?
我们在索引回顾的时候和大家对索引做了一个分类对吧,按照字段个数来分的话,就分为了单列索引和组合
索引对吧。那么他们之间的特点是什么呢?我们来看
,单列索引 一个索引只包含了一个列,一个表里面可以有多个单加要2,但早这不叫组各思己
•组合索引(联合索引&复合索引)一个索引包含多个列。
看上去感觉这组合索引并没有太大作用是吧,我一个列已经有一个索引了,我还要这组合索引干嘛?
真相往往不那么简单,首先我们得承认我们的业务千变万化,我们的查询语句条件肯定是非常多的。
高效率如果说只有单列索引,那就会涉及多次二级索引树查找,再加上回表,性能相对于联合索引来说
是比较低的。
减少开销 我们要记得创建索引是存在空间开销的,对于大数据量的表,使用联合索引会降低空间开销。
索引覆盖 如果组合索引索引值已经满足了我们的查询条件,那么就不会进行回表,直接返回。
但是我们按照我们的查询条件去创建一个联合索引的话,就避免了上面的问题
那么联合索引是怎么工作的
呢?
这里涉及到了一个重点,叫做 最左前缀,简单理解就是只会从最左边开始组合,组合索引的第一个字段必须出现在查询组句中,还不能跳跃,只有这样才能让索引生效,比如说我查询条件里面有组合索引里面的第二个字段,那么也是不会走组合索引的。举个例子
SQL
// 假设给username,age创建了组合索引
// 这两种情况是会走索引的
select * from user where username ='张三
select * from user where username
// 这种是不会走索引的
select * from user where age =18
select * from user where city
'北京
and age=18
and age
18
复合索引创建时字段顺序不一样使用效果一样吗?
SQL
// 特殊情况,这种也是会走索引的,虽然我的age在前面,username在后面。
// 刚刚不是手最左前缀匹配吗,为什么放到第二位也可以呢?
// 虽说顺序不一致,但是在SQL执行过程中,根据查询条件命中索引,//无论我username在不在前面,都会按照username去进行索引查找。select * from user where age = 18 and username =
‘张三
mysql索引的数据结构,各自优劣
索引的数据结构和具体存储引擎的实现有关,在MySQL中使用较多的索引有Hash索引,B+树索引等,InnoDB存储引擎的默认索引实现为:B+树索引。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
B+树:
B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接。在B+树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大幅波动,而且基于索引的顺序扫描时,也可以利用双向指针快速左右移动,效率非常高。因此,B+树索引被广泛应用于数据库、文件系统等场景。
哈希索引:
哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点
逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快
如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;前提是键值都是
唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;
如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成
不连续的了,就没办法再利用索引完成范围查询检索;
哈希素引也没办法利用索引完成排序,以及likexxx%这样的部分模糊查询(这种部分模糊查询,其实本质上也是
范围查询);
哈希索引也不支持多列联合索引的最左匹配规则;
B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是
极低的,因为存在哈希碰撞问题。
Innodb是如何实现事务的
Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例:1.Innodb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据
3.针xupdate语句生成一个RedoLog对象,并存入LogBuffer中
4.针对update语句生成undolog日志,用于事务回滚
5.如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据页持久化到磁盘中
6.如果事务回滚,则利用undolog日志进行回滚
mysql left join中on后加条件判断和where中加条件的区别
left join中关于where和on条件的几个知识点:
1.多表left join是会生成一张临时表,并返回给用户
2.where条件是针对最后生成的这张临时表进行过滤,过滤掉不符合where条件的记录,是真正的不符合就过滤掉。
3.on条件是对left join的右表进行条件过滤,但依然返回左表的所有行,右表中没有的补为NULL
4.on条件中如果有对左表的限制条件,无论条件真假,依然返回左表的所有行,但是会影响右表的匹配值。也就是说on中左表的限制条件只影响右表的匹配内容,不影响返回行数。
结论:
1.where条件中对左表限制,不能放到on后面
2.where条件中对右表限制,放到on后面,会有数据行数差异,比原来行数要多
ACID靠什么保证的?
A原子性由undo log日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
C一致性由其他三大特性保证、程序代码要保证业务上的一致性
|隔离性由MVCC来保证
D持久性由内存+redo log来保证,mysql修改数据同时在内存和redolog记录这次操作,宕机的时候可以从redo
log恢复
InnoDB redo 1og 写盘,InnoDB 事务进入prepare状态。
如果前面 prepare 成功,bin1og 写盘,再继续将事务日志持久化到bin1og,如果持久化成功,那么 InnoDB 事务
则进入 commit 状态(在 redo 1og 里面写一个 commit 记录)
redolog的刷盘会在系统空闲时进行
MySQL的索引结构是什么样的?聚簇索引和非聚簇索引又是什么?
二叉树-》 AVL树-》 红黑树-》 B-树-》 B+树
二叉树:每个节点最多只有两个子节点,左边的子节点都比当前节点小,右边的子节点都比当前节点大。
AVL树: 树中任意节点的两个子树的高度差最大为1
红黑树:1、每个节点都是红色或者黑色。2 根节点是黑色。3 每个叶子节点都是黑色的空节点。4 红色节点的父子节点都必
须是褐色。5 从任一节点到其每个叶子节点的所有路径都包含相同的黑色节点。
B-树:1、B-树的每个非叶子节点的子节点个数都不会超过D(这个D就是B-树的阶)2、所有的叶子节点都在同一层。3.所有
节点关键字都是按照递增顺序排列。
B+树: 1、非叶子节点不存储数据,只进行数据索引。2、所有数据都存储在叶子节点当中。3、每个叶子节点都存有相邻叶
子节点的指针。4、叶子节点按照本身关键字从小到大排序。
聚簇索引就是数据和索引是在一起的。
MylSAM使用的是非聚簇索引,树的子节点上的data不是数据本身,而是数据存放的地址。InnoDB采用的是聚簇索引,树的
叶子节点上的data就是数据本身。
聚簇索引的数据物理存放顺序和索引顺序是一致的,所以一个表当中只能有一个聚簇索引,而非聚簇索引可以有多个。
InnoDB中,如果表定义了PK,那PK就是聚簇索引
如果没有PK,就会找第一个非空的unique列作为聚簇索引。否则,
InnoDB会创建一个隐藏的row-i作为聚簇索引。
MySQL的覆盖索引和回表
如果只需要在一颗索引树上就可以获取SQL所需要的所有列,就不需要再回表查询,这样查询速度就可以更快。
实现索引覆盖最简单的方式就是将要查询的字段,全部建立到联合索引当中。
user (PK id, name ,sex)
select count(name) from user;->在name字段上建立一个索引。
select id,name ,sex from user; ->将name上的索引升级成为(name,sex)的联合索引。
MySQL有哪几种数据存储引擎?有什么区别?
MySQL中通过show ENGINES指令可以看到所有支持的数据库存储引擎。 最为常用的就是MyISAM和InnoDB两种。
MyISAM和InnDB的区别:
1、存储文件。 MylSAM每个表有两个文件。 MYD和MYISAM文件。 MYD是数据文件。 MYI是索引文件。而InnDB每个表
只有一个文件,idb。
2、LnnoDB支持事务,支持行级锁,支持外键。
3、InnoDB支持XA事务
4、InnoDB支持savePoints
MySQL 基础复习 三种存储引擎的特点
1.create database aa;
2.show create database aa\G;
3.drop database aa; 删除数据库,mysql是不会有提示的,而且不能回复
4.show engines; sopport 表示该数据引擎是否能使用,yes表示可以,no表示不能,default表示该引擎是当前的默认引擎。
5.mysql数据库引擎介绍:
5.1 InnoDB:
它是事务型数据库的首选引擎,支持事务安全表(提供了提交、回滚、奔溃的恢复能力),支持行锁和外键。
在mysql5.5之后,他就是mysql的默认数据库引擎。 InnoDB 锁定在行级 并且 也在select语句中提供了一个类似oracle的非锁定读。
InnoDB能够处理大数据量的数据。
InnoDB存储引擎完全和mysql服务器整合,InnoDB为在主内存中缓存数据和索引而维护他自己的缓存池。
InnoDB中的表和缩影存储在一个逻辑空间中,表中可以包含多个数据文件或者原始磁盘分区。 这一点和 MyISAM不同,MyISAM单个表中存放在分离的文件中。
InnoDB表可设置任何尺寸。
InnoDB支持外键完整性约束。存储表中的数据时,按照表中的住建顺序存放,如果没有主键,他会为每行数据创建一个6B的rowId,以此作为行记录的主键。
InnoDB用在需要高性能的大型数据库的地方。
InnoDB不会创建目录,MySQL 在她的数据目录下创建一个可以动态扩容的 名为ibdata1的 大小为10M的数据文件,创建两个5M的数据库日志文件,ib_logfile0和ib_logfile01.
5.2 MyISAM
MyISAM具有较高的查询、插入速度。不支持事务,它是mysql5.5之前的版本默认的数据库。
支持大文件在支持大文件的系统上被支持。
当insert update delete 混合使用时,动态尺寸的行产生更少的碎片。
单表最大索引数是64,可以通过编译改变.每个索引最大的列是16列
最大的键长是100B ,可以通过编译改变,
blob和text 列可以被索引
null值可以出现在索引中
所有的键值以高字节优先被存储以允许一个更高的索引压缩
表中的自增长列的内部处理,insert 和 update 操作自动更新这一列,这使得自增长(auto_increment)列更快。在序列顶的值悲伤出后就不再使用了
可以把数据文件和索引文件放在不同的位置
每个字符列可以有不同的字符集
有varchar的表可以固定或者动态记录长度
varchar 和 char 列可以多达64K
使用MyISAM创建数据库,产生三个文件,文件名以表名开始,.frm 文件存储表定义 、.myd 文件存储数据 、.myi存储索引
5.3 memory
它把表中的数据存放在内存中
memory表中可以有32个索引、每个索引可以有16列,以及500B的最大键长度
支持存储hash和bree索引
可以在memory表中有非唯一键
不支持blob和text
支持自增长列和对包含null值列的索引
memory表在所有客户端之间共享
MySQL 数据表基本操作
1.在创建表的时候定义主键
create table aa{
id int(10) primary key auto_incremnt,
name varchar(10)
};
指定索引从哪里开始:alter table aa AUTO_INCREMENT=123456
2.定义完列之后申明主键
create table aa{
id int(10) ,
name varchar(10),
primary key(id)
};
- 追加
alter table aa add primary key(id);
-
一堆约束 外键约束 非空约束 唯一性约束
-
显示表字段以及类型 desc aa
-
显示建表语句 show create table aa\G
7.修改表名 alter table aa rename bb
- 修改字段类型 alter table aa modify name varchar(100)
9.修改列名 alter table aa change name newname varchar(10)
10 添加列 alter table aa add sex char(1) [first | after columnlname]
11 添加约束:alter table aa add nickname varchar(30) not null
12 删除字段:alter table aa drop nickname
13 修改字段的位置:alter table aa modify name varchar(10) first | alter name
14 更改数据库引擎:alter table aa engine = MyISAM
15 删除表的外键:alter table aa drop foreign key name
16 drop table if exist aa
17 删除有关联的表:首先删除关联关系,然后在删除对应的表:alter table aa drop foreign key fk_name; drop table aa;
MySQL 数据类型
MySQL 支持多种数据类型,主要有 数值类型、日期/时间、字符串等
数值类型:整数类型:tinyint(1)、smallint(2)、mediumint(3)、int(4)、bigint(8);浮点数据类型有:float(4)、double(8) ;指定小数类型:decimal(M,D) M+2个字节。无论是定点还是浮点,如果用户指定的精度超出精度范围,则会四舍五入进行处理。
时间日期类型:year(YYYY)、time(HH:MM:SS)、date(YYYY-MM-DD)、datetime(YYYY-MM-DD HH:MM:SS)、timestamp(YYYY-MM-DD HH:MM:SS)
字符串类型:char、varchar、binary、varbinary、blob、text、enum、set。字符串类型分为文本类型和二进制类型。
float(5,1)–>float(5.12) = 5.1
double(5,1)->double(5.15) = 5.2
decimal(5,1)->decimal(5.123) = 5.1
InnoDB的索引和MyISAM的索引有什么区别?
首先InnoDB和MyISAM都是使用的B+树实现的,但是InnoDB使用的是聚簇索引而MyISAM使用的是非聚簇索引,聚簇索引根据主键创建一颗B+树,叶子节点则存放的是数据行记录,也可以把叶子结点称为数据页。通俗点来说就是把数据和索引存在同一个块,找到了索引也就找到了数据。
·因为叶子结点将索引和数据放在一起,就决定了聚簇索引的唯一性,一张表里面只能有一个聚簇索引。InnoDB引擎默认将主键设置为聚簇索引,但如果没有设置主键,那么InnoDB将会选择非空的唯一索引作为代替,如果没有这样的索引,InnoDB将会定一个隐式主键作为聚簇索引。
因为聚簇索引特殊的物理结构所决定,叶子结点将索引和数据存放在一起,在获取数据的速度上是比非
聚簇索引快的。
聚簇索引数据的存储是有序的,在进行排序查找和范围查找的速度也是非常快的。
A也正因为有序性,在数据插入时按照主键的顺序插入是最快的,否则就会出现页分裂等问题,严重
影响性能。对于InnoDB我们一般采用自增作为主键ID。
第二个问题主键最好不要进行更新,修改主键的代价非常大,为了保持有序性会导致更新的行移动,一
般来说我们通常设置为主键不可更新。
在这部分只介绍InnoDB和MyISAM主键索引的不同?辅助索引后面在说
而非聚簇索引是将索引和数据分开存储,那么在访问数据的时候就需要2次查找,但是和InnoDB的非聚簇部分还是有所区别。InnoDB是需要查找2次树,先查找辅助索引树,再查找聚簇索引树(这个过程也叫回表)。而MyISAM的主键索引叶子结点的存储的部分还是有所区别。InnoDB中存储的是索引和聚簇索引ID,但是MyISAM中存储的是索引和数据行的地址,只要定位就可以获取到
其实看到这个部分会有一个疑惑,那就是InnoDB的聚簇索引比MyISAM的主键快,那为什么会认为
MyISAM查询效率比InnoDB快呢?
第一点,对于两者存储引擎的的性能分析不能只看主键索引,我们也要看看辅助索引,前头我们介绍过InnoDB辅助索引会存在一个回表的过程。而MyISAM的辅助索引和主键索引的原理是一样的,并没有什么区别。
(重点)InnoDB对MVCC的支持,事物是比较影响性能的,就算你没用但是也省不了检查和维护,而
MyISAM 这块却没有这方面的影响,具体MVCC详解将在后面章节描述。
如果一个表没有主键索引那还会创建B+树吗?
答案是会的!!!
InnoDB是MySQL中的一种存储引擎,它会为每个表创建一个主键索引。如果表没有明确的主键索引,
InnoDB 会使用一个隐藏的,自动生成的主键来创建索引。
这个隐藏的主键索引使用的就是 B+ 树结构。
索引的优缺点是什么?
•需要占用物理空间,建立的索引越多需要的空间越大
创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
会降低表的增删改的效率,因为每次增删改索引需要进行动态维护,导致时间变长
::使用索引一定能提升效率吗?
(什么时候适合创建索引,什么时候不适
合创建索引?)
答案是不一定,任何事物我们都应该辩证的看,知道其运行逻辑从而利用其优点,尽量避开它的缺点。在上
面我们已经和大家介绍了过了索引带来的优缺点,那接下来就和大家分享几个建索引的提示。
对于查询中使用的少的字段尽量不要创建索引,创建索引是有成本的,空间占用、创建和维护成本、增
删改效率降低。
对于数据密度小的列也不建议创建索引,因为InnoDB中索引的B+树所决定的,你能带来的效率提升非常有限。(但是也有例外,举个例子枚举值(1,2,3),头两个占比百分之1%,第三个占比99%,并且头两个搜索占比比第三个高很多,那么是可以建议加索引的)。InnoDB的辅助索引是存在回表的,如果数据密度过小,那么性能可能还不如全表扫。像上面这种场景具有特殊性,也说明一个道理,在大多数场景下建议可能适用,但是也有不适用的时候,我们不要把这种建议当作铁律。
MySQL 索引
声明:写这个玩意,仅仅是为了复习看看。仅此而已。
索引,老生常谈。就是为了快,用空间换时间的。
索引是在存储引擎中实现的,每种存储引擎的所应都不一定相同,并且每种存储引擎也不一定支持所有的索引类型。mysql中的缩影的存储类型有两种btree和hash。myisam和innodb只支持btree。memory和heap可以支持btree和innodb。每个表都支持至少16个索引,每个表索引长度最少256字节。
索引的优点:
1、通过创建唯一索引,可以保证数据库中的每条记录的唯一性
2、可以加快查询速度
3、在实现数据的参考完整性方面,可以加快表之间的连接
4、在使用分组和排序是,可以显著减少查询中分组和排序的时间
索引的缺点:
1、创建和维护缩影需要耗费时间,并且随着数据量的增加所耗费的时间也会增加
2、索引需要占用存储空间,物理空间,如果有大量的缩影,索引文件可能比数据文件更快达到最大尺寸
3、对表进行crud操作时,索引需要动态的移动,这样减低了数据的维护速度
索引的分类:
1、普通索引和唯一索引
2、单列索引和组合索引
3、全文索引
全文索引可以在char、varchar、text类型上创建,mysql上只有myisam引擎可以创建全文索引
4、空间索引
mysql上只有myisam引擎可以创建空间索引
索引的设计原则
索引设计不合理或者缺少索引都会对数据库和应用程序的性能造成障碍。高效的索引对千获得良好的性能非常重要。设计索引时,应该考虑以下准则:
- 索引 并非越多越好, 一个表中如有大量的索引, 不仅占用磁盘空间, 而且会影响
INSERT 、DELETE、UPDATE 等语句的性能,因 为当表中的数据更改的同 时,索引也 会进行调整和更新。 - 避免对经常更新的表进行过多的索引 , 并且索引中的列尽可能少。而对经常用 千查询的字段应该创建索引,但要避免添加不必要的字段。
- 数据量小的表最好不要使用索引, 由千数据较少, 查询花费的时间可能比遍历索引的时间还要短,索引可能不会产生优化效果。
- 在条件表达式中经常用到的不同值较多的列上建立索引, 在不同值很少的列上不要建立索引。比如在学生表的“性别”字段上只有“男”与“女”两个不同值,因此就无须建立 索引。如果建立索引不但不会提高查询效率,反而会严重降低数据更新速度。
- 当唯一性是某种数据本身的特征时,指 定唯一索引。使用唯一索引需能确保定义的列的数据完整性,以提高查询速度。
- 在频繁进行排序或分组(即进行group by 或 order by 操作)的列上建立索引,如 果待排序的列有多个,可以在这些列上建立组合索引
mysql建立索引时中的length什么用
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length.
参考MySQL手册 13.1.4. CREATE INDEX语法
对于CHAR和VARCHAR列,只用一列的一部分就可创建索引。创建索引时,使用col_name(length)语法,对前缀编制索引。前缀包括每列值的前length个字符。BLOB和TEXT列也可以编制索引,但是必须给出前缀长度。
此处展示的语句用于创建一个索引,索引使用列名称的前10个字符。
CREATE INDEX part_of_name ON customer (name(10));
因为多数名称的前10个字符通常不同,所以此索引不会比使用列的全名创建的索引速度慢很多。另外,使用列的一部分创建索引可以使索引文件大大减小,从而节省了大量的磁盘空间,有可能提高INSERT操作的速度
创建索引
MySQL 支持多种方法在单个或多个列上创建索引:
- 在创建表的定义语句CREATE TABLE中指定索引列
- 使用 ALTER TABLE 语句在存在的表上创建索引
- 使用 CREATE INDEX语句在已存在的表 上添加索引
-- 建表的时候指定索引
CREATE TABLE aa(
ID INT NOT NULL,
info VARCHAR(255) NULL,
comment VARCHAR (255) NULL,
year_publication YEAR NOT NULL,
INDEX(year_publication)
)
--创建唯一索引
UNION INDEX(year_publication)
--创建全文索引
FULLTEXT INDEX FullTxtidx (info)
显示索引
SHOW INDEX FROM TABLE_NAME;
Table: book Non_unique: 1
Key_nam : year_publication
Seq_in_index: 1
Column_name: year_publication
Collation: A
Cardinality : 0
Sub_part: NULL
Packed: NULL Null:
Index_type: BTREE
Comment:
Index comment:
其中各个主要参数的含义为:
- Table 表示创建索引的表。
- Non_ unique 表示索引非唯一, l 代表是非唯一索引, 0 代表唯一索引。
- Key_ name 表示索引的名称。
- Seq_in_index 表示该字段在索引中的位置,单列索引该值为 I, 组合索引为每个字段在索引定义中的顺序。
- Column_name 表示定义索引的列字段。
- Sub_part 表示索引的长度。
- Null 表示该字段是否能为空值。
- Index_type 表示索引类型
在已经存在的表上创建索引
ALTER TABLE TABLE_NAME ADD INDEX INDEX_NAME(CLOUMN(INDEX_LENGTH))
create index
CREATE INDEX INDEX_NAME(CLOUMN(INDEX_LENGTH))
删除索引
有两种方式
1. ALTER TABLE TABLE_NAME DROP INDEX INDEX_NAME;
2. DROP INDEX INDEX_NAME ON TABLE_NAME;
MySQL 函数
数字函数、字符串函数、时间日期函数、条件函数、系统函数、加密函数、其他特殊函数
数字函数
- abs() 绝对值
2.pi() 圆周率
-
mod(x,y) 余数、sprt()
-
获取整数函数:ceil() ceiling() floor()
ceil(-3.35) = -3
ceilIng(3.35) = 4
floor(-3.35) = -4
floor(3.35) = 3
-
随机数函数 rand()[0,1] rand(X)
-
四舍五入:round() round(x,y) y表示小数点后保留几位 truncate()
-
符号函数:sign(x)
sign(-21) = -1
sign(0) = 0
sign(21) = 1
8. 幂运算:pow() power() exp()
- 对数:log() log10()
字符串函数
1.char_length() 字符个数
2.length() 字节长度
- concat() 如果是有null,则为null;concat_ws() 会忽略null
concat_ws(‘-’,1,1) = 1-1
concat_ws(‘-’,1,null) = 1-
4.字符串替换: insert(s1,x,len,sr) 索引是从1开始
- lower() upper()
6.获取指定长度的字符串:left(s,len)、right(s,len)
-
填充 lpad(s1,len.s2) rpad()
-
删除空格 trim ltrin rtrim
-
删除指定字符串 trim(s2 from string)
-
重复生成字符串repeat(s,n)
11, 空格函数:space(n) ;替换replace(s,s1,s2)
12.字符串大小比较:strcmp(s1,s2) 返回 -1,0,1
13.匹配字符串位置:locate(str,s) 返回索引位置,索引从0开始;positoin(str1 in str);instr(str,str1)
-
reverse()
-
返回指定位置的字符串函数:elt()
elt(1,1,b,c) = a
elt(3,a,b) = null
16 返回指定字符串位置的函数:field()
field(s,s1,s2)
field(‘hi’,a,b,‘hi’) = 3
field(‘hi’,‘hihi’,‘hh’) = 0
17 返回字符串位置的函数:find_in_set(s1,s2) s1 在s2中出现的索引位置
18 获取字符串函数:make_set
时间日期
1.curdate() cur_date() curdate()+0
2.curtime() cur_time() curtime()+0
3.current_timestamp() localdate() now() sysdate()
- nuix 时间戳函数 unix_timestamp()
5.uct_date() 世界标准时间
6.month() monthname()
7.dayname() dayofweek() 注意:1表示周日 7表示周6 weekday() 表示工作日索引。0表示周一
8.week(date) 查询日期是一年中的第几周 ,week(date,modle):modle 表示一周的第一天是周几,默认是0,0标识 一周第一天是周日 ;weekofyear(date) 查询日期是一年中的第几周
9.dayofyear(date) 、dayofmonth(date) 时间在一年、一月中的第几天
- year() 、quartrt()、minute()、second()
11.extract(type from date) :type可以为 year 、year_month、year_minute
12 时间和秒转换:time_to_sec() sec_to_time()
13 计算时间和日期的函数:
date_add()、adddate() :时间加法操作:date_add(date,interval 数量 单位) 单位可以是 年月日时分秒
date_sub()、subdate():时间减法操作:date_add(date,interval 数量 单位) 单位可以是 年月日时分秒
addtime(date,express) :addtime(‘2020-01-01 11:00:00’ ,‘1:00:00’) 加了一个小时 ;subtime() 同理 addtime(‘2020-01-01 12:00’,‘24:00’)
date_diff(d1,d2) : 返回天数
- 时间日期格式化 date_format() DATE_FORMAT(NOW(),‘%Y-%m-%d %H:%i:%s’)
条件判断函数
- ifnull(a,b,c) 三目表达式
2.ifnull(a,b)
- case when
系统信息函数
select version()
select connection_id()
show processlist
select database() ,schema()
select user(),current_user(),system_user(),session_user()
select charset(‘123’) 获取字符集
select last_insert_id()
加密函数、
password()
md5()
encode(str,pwd_str)
decode(str,pwd_str)
其他函数
cast() convert()
索引
是一个单独的、存储在磁盘上的数据库结构,它 们包含着对数据表里所有记录的引用指针
MySQL 中索引的存储类型有两种: BTREE 和 HASH, 具体和表的存储引擎相关;
MyISAM 和InnoDB 存储引擎只支持BTREE 索引; MEMORY/HEAP 存储引擎可以支持 HASH
和 BTREE 索引。
索引的优点主要有以下几条:
通过创建唯一索引, 可以保证数据库表中每一行数据的唯一性。
可以大大加快数据的查询速度, 这也是创建索引的最主要的原因。
在实现数据的参考完整性方面, 可以加速表和表之间的连接。
在使用分组和排序子句进行数据查询时, 也可以显著减少查询中分组和排序的时间。
增加索引也有许多不利,主要表现在如下几个方面:
创建索引和维护索引要耗费时间, 并且随着数据量的增加所耗费的时间也会增加。
索引需要占磁盘空间, 除了数据表占数据空间之外, 每一个索引还要占一定的物理空间,如果有大量的索引,索引文件可能比数据文件更快达到最大文件尺寸。
当对表中的数据进行增加、删除和修改的时候, 索引也要动态地维护, 这样就降低了数据的维护速度。
索引的优缺点是什么?
数据是存储在磁盘上的,操作系统读取磁盘的最小单位是块,如果没有索引,会加载所有的数据到内存,依次进
行检索,加载的总数据会很多,磁盘10多。
如果有了索引,会以某个列为key创建索引,MySQL采用B+树结构存储,一方面加载的数据只有某个列和主键
ID,另一方便采用了多叉平衡树,定位到指定某个列的值会很快,根据关联的ID可以快速定位到对应行的数据,
所以检索的速度会很快,因为加载的总数据很少,磁盘10少。
可见,索引可以大大减少检索数据的范围、减少磁盘1O,使查询速度很快,因为磁盘10是很慢的,是由它的硬件
结构决定的。
优点
索引能够提高数据检索的效率,降低数据库的IO成本。
,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性,创建唯一索引在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间加速两个表之间的连接,一般是在外键上创建索引
×缺点
需要占用物理空间,建立的索引越多需要的空间越大
创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
会降低表的增删改的效率,因为每次增删改索引需要进行动态维护,导致时间变长
索引的分类
索引的分类
按「数据结构」分类:B+tree索引、Hash索引、Full-text索引。
按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引。按「字段个数」分类:单列索引、联合索引。
1.普通索引和唯—索引
2.单列索引和组合索引
3.全文索引
4.空间索引删除线格式
索引的设计原则
索引并非越多越好
避免对经常更新的表进行过多的索引
数据量小的表最好不要使用索引
在条件表达式中经常用到的不同值较多的列上建立索引, 在不同值很少的列上不要建立索引
当唯一性是某种数据本身的特征时,指定唯一索引。使用唯一索引需能确保定义的列的数据完整性,以提高查询速度
在频繁进行排序或分组(即进行group by 或 order by 操作)的列上建立索引
create index index_1 on by_his_user(USER_NAME);
EXPLA 语句输出结果的各个行解释如下:
(1)select_type 行指定所使用的SELECT查询类型,这里值为SIMPLE, 表示简单的SELECT,
不使用UNION 或子查询。其他可能的取值有: PRIMARY、UNION、SUBQUERY 等。
(2)table 行指定数据库读取的数据表的名字, 它们按被读取的先后顺序排列。
(3)type 行指定了本数据表与其他数据表之间的 关联关系, 可能的取值有 system、const、
eq_ref、 ref、 range、 index 和 All。
(4)possible_keys 行给出了 MySQL 在搜索数据记录时可选用的各个索引。
(5)key 行是 MySQL 实际选用的索引。
(6)key—len 行给出索引 按字节计算的长度, ke y_len 数值越小, 表示越快。
(7)ref 行给出了关联关系中另 一个数据表里的数据列的名字。
(8)rows 行是 MySQL 在执行这个查询时预计会从这个数据表里读出的数据行的个数。
extra 行提供了与关联操作有关的信息
性能下降SQL慢,执行时间长,等待时间长:
查询语句写的烂
索引失效???
关联查询太多join
服务器调优及各个参数设置
join
left join
right join
inner join
left join on where b.XXX is null
right join on where a.XXX is null
full outer join
full outer join where a.XXX is null or b.XXX is null
数据库迁移
数据库迁移就是把数据从一个系统移动到另一个系统上
相同版本的 MySQL 数据库之间的迁移
主版本号 相同的 MySQL 数据库之间进行数据库移动
eg:将www.abc.com 主机上的 MySQL 数据库全部迁移到 www.bcd.com 主机上。在
www.abc.com 主机上执行的命令如下
mysqldump -h www.abc.com -uroot -ppassword dbname |
mysql -h www.bcd.com -uroot -ppassword
MySQLdump 导入的数据直接通过管道符 " I " 传给 MySQL 命令导入的主机
www.bcd.com 数据库中, dboame 为需要迁移的数据库名称, 如果要迁移全部的数据库 , 可使用参数–all-databases
不同版本的 MySQL 数据库之间的迁移
将旧版本数据库中的数据备份出来,然后导入到新版本的数据库中
不同数据库之间的迁移
可以使用naviat Premium工具进行不同数据库之间数据的迁移
数据恢复
可以使用命令进行恢复
直接复制到数据库目录
如果数据库通过复制数据库文件备份,可以直接复制备份的文件到 MySQL 数据目录下实现恢复。
通过这种方式恢复时,必须保存备份数据的数据库和待恢复的数据库服务器的主版本号相同。而且这种方式只对 MyISAM 引擎的表有效,对于 InnoDB 引擎的表不可用。
执行恢复以前关闭MySQL服务,将备份的文件或目录覆盖 MySQL 的 data 目录,启动MySQL 服务。对于 Linux/Unix 操作系统来说, 复制完文件需要将文件的用户和组更改为
MySQL 运行的用户 和组,通 常用户是 MySQL, 组也是 MySQ
mysql执行计划怎么看
执行计划就是sql的执行查询的顺序,以及如何使用索引查询,返回的结果集的行数
EXPLAIN SELECT * from A where X=? and Y=?
id I select_type I table I partitions | type
filtered I Extra
1。id:是一个有顺序的编号,是查询的顺序号,有几个select 就显示几行。id的顺序是按 select 出现的顺序增
长的。id列的值越大执行优先级越高越先执行,id列的值相同则从上往下执行,id列的值为NULL最后执行。
2。selectType 表示查询中每个select子句的类型
SIMPLE:表示此查询不包含 UNION查询或子查询
•PRIMARY:表示此查询是最外层的查询(包含子查询)
SUBQUERY:子查询中的第一个SELECT
UNION:表示此查询是UNION的第二或随后的查询
• DEPENDENT UNION:UNION中的第二个或后面的查询语句,取决于外面的查询
• UNION RESULT,UNION的结果
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询.即子查询依赖于外层查询的结果.
DERIVED:衍生,表示导出表的SELECT(FROM子句的子查询)
3.table:表示该语句查询的表
4.type:优化sql的重要字段,也是我们判断sql性能和优化程度重要指标。
mysql执行计划怎么看
执行计划就是sql的执行查询的顺序,以及如何使用索引查询,返回的结果集的行数
EXPLAIN SELECT * from A where X=? and Y=?
id I select_type I table I partitions I type
I possible_keys | key
filtered | Extra
1。id:是一个有顺序的编号,是查询的顺序号,有几个select 就显示几行。id的顺序是按 select 出现的顺序增
长的。id列的值越大执行优先级越高越先执行,id列的值相同则从上往下执行,id列的值为NULL最后执行。
2。selectType 表示查询中每个select子句的类型
SIMPLE:表示此查询不包含UNION查询或子查询
•PRIMARY:表示此查询是最外层的查询(包含子查询)
• SUBQUERY:子查询中的第一个SELECT
UNION:表示此查询是 UNION的第二或随后的查询
• DEPENDENT UNION:UNION中的第二个或后面的查询语句,取决于外面的查询
• UNION RESULT,UNION的结果
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询.即子查询依赖于外层查询的结果.
DERIVED:衍生,表示导出表的SELECT(FROM子句的子查询)
3.table:表示该语句查询的表
4.type:优化sql的重要字段,也是我们判断sql性能和优化程度重要指标。他的取值类型范围
const:
|通过索引一次命中,匹配一行数据
Lsystem:)
表中只有一行记录,相当于系统表;
eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配
ref:非唯一性索引扫描,返回匹配某个值的所有
•range:只检索给定范围的行,使用一个索引来选择行,一般用于between、
index:只遍历索引树;
ALL:表示全表扫描,这个类型的查询是性能最差的查询之一。 那么基本就是随着表的数量增多,执行效率越
慢。
执行效率:
ALL <index <range< ref<eq_ref<const<system。最好是避免ALL和index
5.possible_keys:它表示Mysql在执行该sql语句的时候,可能用到的索引信息,仅仅是可能,实际不一定会用
到。
6.key:此字段是 mysql在当前查询时所真正使用到的索引。他是possible_keys的子集
MySQL 执行计划 explain
Explain:使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,能查看哪些索引被使用,表的执行顺序。
explain select* from book where year_publication=l990 \G
id: 1
select_type: SIMPLE
table : book
type: ref
possible_keys: year_publication
key: year_publication
key_len: 1
ref: const
rows: l
Extra:
explain 语句输出结果的各个行解释如下:
- select_type 行指定所使用的SELECT查询类型,这里值为SIMPLE, 表示简单的SELECT, 不使用UNION 或子查询。其他可能的取值有: PRIMARY、UNION、SUBQUERY 等。
- table 行指定数据库读取的数据表的名字, 它们按被读取的先后顺序排列。
- type 行指定了本数据表与其他数据表之间的 关联关系, 可能的取值有 system、const、eq_ref、 ref、 range、 index 和 All。
- possible_keys 行给出了 MySQL 在搜索数据记录时可选用的各个索引。
- key 行是 MySQL 实际选用的索引。
- key—len 行给出索引 按字节计算的长度, key_len 数值越小,表示越快。
- ref 行给出了关联关系中另 一个数据表里的数据列的名字。
- rows 行是 MySQL 在执行这个查询时预计会从这个数据表里读出的数据行的个数。
- extra 行提供了与关联操作有关的信息
id
三种情况:
id相同,执行顺序由上至下
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
id相同不同,同时存在
select_type
表示查询中每个select子句的类型
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
(2) PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
(3) UNION(UNION中的第二个或后面的SELECT语句)
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
(5) UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)
(6) SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)
(8) DERIVED(派生表的SELECT, FROM子句的子查询)
(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
table
显示表名称或者别名
type
对表访问方式,表示MySQL在表中找到所需行的方式,又称“访问类型”。
常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)
ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
index: Full Index Scan,index与ALL区别为index类型只遍历索引树
range:只检索给定范围的行,使用一个索引来选择行
ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成
possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)
Key
key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中
如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
ref
列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
rows
估算出结果集行数
Extra
该列包含MySQL解决查询的详细信息,有以下几种情况:
Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by
Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”
– 测试Extra的filesort
explain select * from emp order by name;
Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
Impossible where:这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。
Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
No tables used:Query语句中使用from dual 或不含任何from子句
mysql 备份恢复命令
数据备份
1.备份某个数据库中的一张表
mysqldump -uroot -p 数据库名称 表名 >aa.sql
eg:mysqldump -uroot -p course student >aa.sql
2.备份某个数据库
命令:mysqldump -uroot -p 数据库名称 >aa.sql
eg:mysqldump -uroot -p course >aa.sql
3.备份整个数据库
命令:mysqldump -uroot -p >aa.sql
eg:mysqldump -uroot -p --all-databases >aa.sql
4.仅导出表结构不导出数据 --no-data
命令:mysqldump -uroot -p --no-data [数据库名称] >aa.sql
eg:mysqldump -uroot -p --no-data [springbootv2][--all-databases] >aa.sql
5.仅导出表结构不导出数据 --no-create-info
命令:mysqldump -uroot -p --no-create-info [数据库名称] >aa.sql
eg:mysqldump -uroot -p --no-create-info [springbootv2][--all-databases] >aa.sql
6.导出course库中的存储过程和触发器 --routines --triggers [–测试未通过]
命令:mysqldump -uroot -p --routines --triggers [数据库名称] >aa.sql
eg:mysqldump -uroot -p --routines --triggers [springbootv2][--all-databases] >aa.sql
数据恢复
有两种恢复方式 登录/不登录
1.不登录
命令:mysql -uroot -p <备份文件.sql
eg:mysql -uroot -p <test.sql
2.登录
命令:mysql> source 备份文件.sql
eg: mysql> source test.sql
数据库 中的事务
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。
l 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
l 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。
这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;
事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
l 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。
这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
l 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
并发事务处理带来的问题:
更新丢失(Lost Update)
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,
就会发生丢失更新问题--最后的更新覆盖了由其他事务所做的更新。
例如,两个程序员修改同一java文件。每程序员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。
最后保存其更改副本的编辑人员覆盖前一个程序员所做的更改。如果在一个程序员完成并提交事务之前,
另一个程序员不能访问同一文件,则可避免此问题。
脏读(Dirty Reads)
一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,
另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,
就会产生未提交的数据依赖关系。这种现象被形象地叫做”脏读”。
一句话:事务A读取到了事务B已修改但尚未提交的的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取
的数据无效,不符合一致性要求。
不可重复读(Non-Repeatable Reads)
一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!
这种现象就叫做“不可重复读”。
一句话:事务A读取到了事务B已经提交的修改数据,不符合隔离性
幻读(Phantom Reads)
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
一句话:事务A读取到了事务B体提交的新增数据,不符合隔离性。
多说一句:幻读和脏读有点类似,
脏读是事务B里面修改了数据,
幻读是事务B里面新增了数据。
事务隔离级别
脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在
一定程度上 “串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度的
要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。
mysql主从同步原理
mysql主从同步的过程:
Mysql的主从复制中主要有三个线程:master(binloa dump thread)、slave
thread),Master—条线程和Slave中的两条线程。
·主节点binlog,主从复制的基础是主库记录数据库的所有变更记录到binlog。binlog是数据库服务器启动的
那一刻起,保存所有修改数据库结构或内容的一个文件。
主节点log dump线程,当binlog有变动时,log dump 线程读取其内容并发送给从节点。
从节点1/O线程接收binlog内容,并将其写入到relaylog文件中。
·从节点的SQL线程读取relay log文件内容对数据更新进行重放,最终保证主从数据库的一致性。
注:主从节点使用binglog文件+position偏移量来定位主从同步的位置,从节点会保存其已接收到的偏移量
如果从节点发生宕机重启,则会自动从 position的位置发起同步。
由于mysql默认的复制方式是异步的,主库把日志发送给从库后不关心从库是否已经处理,这样会产生一个问题就
是假设主库挂了,从库处理失败了,这时候从库升为主库后,日志就丢失了。由此产生两个概念。
全同步复制
主库写入binlog后强制同步日志到从库,所有的从库都执行完成后才返回给客户端,但是很显然这个方式的话性能
会受到严重影响。
半同步复制
和全同步不同的是,半同步复制的逻辑是这样,从库写入日志成功后返回ACK确认给主库,主库收到至少一个从库
的确认就认为写操作完成。
Mysql数据库中,什么情况下设置了索引但无法使用?
1.没有符合最左前缀原则
2.字段进行了隐私数据类型转化
3.走索引没有全表扫描效率高
存储拆分后如何解决唯一主键问题
UUID:简单、性能好,没有顺序,没有业务含义,存在泄漏mac地址的风险
数据库主键:实现简单,单调递增,具有一定的业务可读性,强依赖db、存在性能瓶颈,存在暴露业务信息的风
险
redis,mongodb,zk等中间件:增加了系统的复杂度和稳定性
雪花算法
海量数据下,如何快速查找一条记录?
1、使用布隆过滤器,快速过滤不存在的记录。
使用Redis的bitmap结构来实现布隆过滤器。
2、在Redis中建立数据缓存。-将我们对Redis使用场景的理解尽量表达出来。
以普通字符串的形式来存储,(serld->user.json)。以一个hash来存储一条记录(userld key->username field->,userAge->)。以一个整的hash来存储所有的数据,Userlnfo->field就用userld,value就用user.json。一个hash最多能支持2^32-1(40多个亿)个键值对。
缓存击穿:对不存在的数据也建立key。这些key都是经过布隆过滤器过滤的,所以一般不会太多.
缓存过期:将热点数据设置成永不过期,定期重建缓存。 使用分布式锁重建缓存。
3、查询优化。
按槽位分配数据,
自己实现槽位计算,找到记录应该分配在哪台机器上,然后直接去目标机器上找。
简述MyISAM和InnoDB的区别
MyISAM:
不支持事务
支持表级锁,
存储表的总行数;
一个MYISAM表有三个文件:索引文件、表结构文件、数据文件;
采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯
一性。
InnoDb:
支持ACID的事务,支持事务的四种隔离级别;
支持行级锁及外键约束:因此可以支持写并发;
不存储总行数;
一个InnoDb引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也有可能为多个(设置为独立表空,表大小受操作系统文件大小限制,一般为2G),受操作系统文件大小的限制;
主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问辅索引;最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。
简述mysql中索引类型及对数据库的性能的影响
普通索引:允许被索引的数据列包含重复的值。
唯一索引:可以保证数据记录的唯一性。
主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字
PRIMARYKEY来创建。
联合索引:索引可以覆盖多个数据列,如像INDEx(olumnA,columnB)引。
全文索引:通过建立倒排索引,可以极大的提升检索效率,解决判断字段是否包含的问题,是目前搜索引擎使用的一
种关键技术。可以通过ALTER TABLE table_name ADDFULLTEXT(column);创建全文索引
索引可以极大的提高数据的查询速度。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
但是会降低插入、删除、更新表的速度,因为在执行这些写操作时,还要操作索引文件
索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那
么需要的空间就会更大,如果非聚集索引很多,一旦聚集索引改变,那么所有非聚集索引都会跟着变。
强平衡二叉树和弱平衡二叉树有什么区别
强平衡二叉树AVL树,弱平衡二叉树就是我们说的红黑树。
1.AVL树比红黑树对于平衡的程度更加严格,在相同节点的情况下,AVL树的高度低于红黑树
2.红黑树中增加了一个节点颜色的概念
3.AVL树的旋转操作比红黑树的旋转操作更耗时
B树和B+树的区别,为什么Mysql使用B+树
B树的特点:
1.节点排序
2.一个节点了可以存多个元素,多个元素也排序了
B+树的特点:1.拥有B树的特点2.叶子节点之间有指针
3.非叶子节点上的元素在叶子节点上都冗余了,也就是叶子节点中存储了所有的元素,并且排好顺序
Mysql索引使用的是B+树,因为索引是用来加快查询的,而B+树通过对数据进行排序所以是可以提高查询速度的,然后通过一个节点中可以存储多个元素,从而可以使得B+树的高度不会太高,在Mysql中一个Innodb页就是一个B+树节点,一个Innodb页默认16kb,所以一般情况下一颗两层的B+树可以存2000万行左右的数据,然后通过利用B+树叶子节点存储了所有数据并且进行了排序,并且叶子节点之间有指针,可以很好的支持全表扫描,范围查找等SQL语句。
事务的基本特性和隔离级别有哪些?
事务:表示多个数据操作组成一个完整的事务单元,这个事务内的所有数据操作要么同时成功,要么同时失败。
事务的特性:ACID
1、原子性:事务是不可分割的,要么完全成功,要么完全失败。
2、一致性:事务无论是完成还是失败,都必须保持事务内操作的一致性。当失败时,都要对前面的操作进行回滚,不管中途
是否成功。
3、隔离性:当多个事务操作一个数据的时候,为防止数据损坏,需要将每个事务进行隔离,互相不干扰。
4、持久性:事务开始就不会终止。他的结果不受其他外在因素的影响。
事务的隔离级别:SHOW VARIABLES like’transaction%’
设置隔离级别:set transaction level xxx 设置下次事务的隔离级别。
set session transaction level xxx 设置当前会话的事务隔离级别
set global transaction level xxx 设置全局事务隔离级别
MySQL当中有五种隔离级别
NONE:不使用事务。
READ UNCOMMITED:
READ COMMITED:防止脏读,最常用的隔离级别
REPEATABLE READ:防止脏读和不可重复读。MYSQL默认
SERIALIZABLE:事务串行,可以防止脏读、幻读,不可重复度
如何实现分库分表
将原本存储于单个数据库上的数据拆分到多个数据库,把原来存储在单张数据表的数据拆分到多张数据表中,实现
数据切分,从而提升数据库操作性能。分库分表的实现可以分为两种方式:垂直切分和水平切分。
水平:将数据分散到多张表,涉及分区键,
。分库:每个库结构一样,数据不一样,没有交集。库多了可以缓解io和cpu压力
”分表:每个表结构一样,数据不一样,没有交集。表数量减少可以提高sq|执行效率、减轻cpu压力
垂直:将字段拆分为多张表,需要一定的重构
·分库:每个库结构、数据都不一样,所有库的并集为全量数据
、分表:每个表结构、数据不一样,至少有一列交集,用于关联数据,所有表的并集为全量数据
什么是MVCC
多版本并发控制:读取数据时通过一种类似快照的方式将数据保存下来,这样读锁就和写锁不冲突了,不同的事务
session会看到自己特定版本的数据,版本链
MVCC只在 READ COMMITTED和 REPEATABLE READ两个隔离级别下工作。其他两个隔离级别够和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。
聚簇索引记录中有两个必要的隐藏列:
trx_id:用来存储每次对某条聚簇索引记录进行修改的时候的事务id。
roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性,因为它没有老版本)
已提交读和可重复读的区别就在于它们生成ReadView的策略不同。
开始事务时创建readview,readView维护当前活动的事务id,即未提交的事务id,排序生成一个数组
访问数据,获取数据中的事务id(获取的是事务id最大的记录),对比readview:
如果在readview的左边(比readview都小),可以访问(在左边意味着该事务已经提交)
如果在readview的右边(比readview都大)或者就在readview中,不可以访问,获取roll_pointer,取上一版本
重新对比(在右边意味着,该事务在readview生成之后出现,在readview中意味着该事务还未提交)
已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的
时候生成一个ReadView,之后的读都复用之前的ReadView。
这就是MysqI的MVCC,通过版本链,实现多版本,可并发读-写,写-读。通过ReadView生成策略的不同实现不同的
隔离级别。
什么是脏读、幻读、不可重复读?要怎么处理?
这些问题都是MySQL进行事务并发控制时经常遇到的问题。
脏读:在事务进行过程中,读到了其他事务未提交的数据。
不可重复读:在一个事务过程中,多次查询的结果不一致。
幻读:在一个事务过程中,用同样的操作查询数据,得到的记录数不相同。
处理的方式有很多种:加锁、康务隔离、MVCC
加锁:
1、脏读:在修改时加排他锁,直到事务提交才释放。读取时加共享锁,读完释放锁。
2、不可重复读:读数据时加共享锁,写数据时加排他锁。
3、幻读:加范围锁。
事务的基本特性和隔离级别
事务基本特性ACID分别是:
原子性指的是一个事务中的操作要么全部成功,要么全部失败。
一致性指的是数据库总是从一个一致性的状态转换到另外一个一致性的状态。比如A转账给B100块钱,假设A只有90块,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证
隔离性指的是一个事务的修改在最终提交前,对其他事务是不可见的。
持久性指的是一旦事务提交,所做的修改就会永久保存到数据库中。
隔离性有4个隔离级别,分别是:
read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。
用户本来应该读取到id=1的用户age应该是10,结果读取到了其他事务还没有提交的事务,结果读取结果
age=20,这就是脏读。
read commit 读已提交,两次读取结果不一致,叫做不可重复读。
不可重复读解决了脏读的问题,他只会读取已经提交的事务。
用户开启事务读取id=1用户,查询到age=10,再次读取发现结果=20,在同一个事务里同一个查询读取到不同的结果叫做不可重复读。
repeatable read 可重复复读,这是mysql的默认级别,就是每次读取结果都一样,但是有可能产生幻读。
serializable串行,一般是不会使用的,他会给每一行读取的数据加锁,会导致大量超时和锁竞争的问题
索引的基本原理
索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。
索引的原理:就是把无序的数据变成有序的查询
1.把创建了索引的列的内容进行排序
2.对排序结果生成倒排表
3.在倒排表内容上拼上数据地址链
4.在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
索引设计的原则?
查询更快、占用空间更小
1.适合索引的列是出现在where子句中的列,或者连接子句中指定的列
2.基数较小的表,索引效果较差,没有必要在此列建立索引
3.使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词
超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配。
4.不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至
重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
5.定义有外键的数据列一定要建立索引。
6.更新频繁字段不适合创建索引
7.若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
8.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索
引即可。
9.对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
10.对于定义为text、image和bit的数据类型的列不要建立索引。
索引覆盖是什么
索引覆盖就是一个SQL在执行时,可以利用索引来快速查找,并且此SQL所要查询的字段在当前索引对应的字段中都包含了,那么
就表示此SQL走完索引后不用回表了,所需要的字段都在当前索引的叶子节点上存在,可以直接作为结果返回了
最左前缀原则是什么
当一个SQL想要利用索引是,就一定要提供该索引所对应的字段中最左边的字段,也就是排在最前面的字段,比如针对a,b,c三个字段建立了一个联合索引,那么在写一个sql时就一定要提供a字段的条件,这样才能用到联合索引,这是由于在建立a,b,c三个字段的联合索引时,底层的B+树是按照a,bc三个字段从左往右去比较大小进行排序的,所以如果想要利用B+树进行快速查找也得符合这个规则
谈谈如何对MySQL进行分库分表?多大数据量需要进行分库分表?分库分表的方式和分片策略由哪些?分库分表后,SQL语句的执行流程是怎样的?
什么是分库分表? 就是当表中的数据量过大时,整个查询效率就会降低得非常明显。这时为了提升查询效率,就要将一个表
中的数据分散到多个数据库的多个表当中。
分库分表最常用的组件:
Mycatl ShardingSphere
数据分片的方式有垂直分片和水平分片。垂直分片就是从业务角度将不同的表拆分到不同的库中,能够解决数据库数据文件过大的问题,但是不能从根本上解决查询问题。水平分片就是从数据角度将一个表中的数据拆分到不同的库或表中,这样可以从根本上解决数据量过大造成的查询效率低的问题。
有非常多的分片策略,比如 取模、按时间、按枚举值。。。。
阿里提供的开发手册当中,建议:一个表的数据量超过500W或者数据文件超过2G,就要考虑分库分表了。
分库分表后的执行流程:
一个user表,按照userid进行了分片,然后我需要按照sex字段去查,这要怎么查?强制指定只查一个数据库,要怎么做?查
询结果按照userid来排序,要怎么排?
分库分表的问题:跨库查询,跨库排序,分布式事务,公共表,主键重复……
全库表路由:对于不带分片键的DQL、DML以及DDL语句,会遍历所有的库表,逐一执行。例如selectfrom course 或者selectfrom course where ustatus=‘1(不带分片键)
全库路由:对数据库的操作都会遍历所有真实库。例如set
autocommit=0
全实例路由:对于DCL语句,每个数据库实例只执行一次,例如
CREATE USER customer@127.0.0.1 identified BY’123’;
关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都
怎么优化过?
在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会
定期将业务中的慢查询反馈给我们。
慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引?是load了不需要的数据列?还是数据量
太大?
所以优化也是针对这三个方向来的,
首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中
并不需要的列,对语句进行分析以及重写。
分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中
索引。
如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分
表。
SQL优化有哪些着手点?组合索引的最左前缀原则的含义?
首先讲第一个问题:
SQL优化,既然是优化,那么首先得要定位问题才能对症下药,开启慢查询日志监控,找出系统中比较慢的SQL。这就减少了筛查范围,然后逐条进行执行计划分析。没建索引的建索引,建了索引的看看索引是不是失效了,然后排查为什么索引失效?这些问题排查完了之后,可能因为表数据量过大,那就要考虑是不是要拆表,进行分表。|
常用优化建议:
1.优化查询的选择、连接和排序操作。
2.优化查询中使用的索引,包括创建新索引、删除无用索引、调整索引的顺序等。
3.优化查询中使用的表连接方式,包括内连接、外连接、自连接等。
4.优化查询中使用的子查询,包括对子查询进行优化、使用连接代替子查询等。
5.优化查询中使用的聚合函数,包括使用索引进行优化、使用分组连接代替聚合函数等。
第二个问题:
组合索引的最左前缀原则指的是,在创建组合索引时,应该将最常用于筛选数据的列放在索引的最左侧,这样可以使索引更有效地帮助查询优
化。
例如,如果有一张表中包含三个字段:A、B和C,并且频繁使用A和B 这两个字段进行筛选数据,则应该将 A和B 作为组合索引的最左前
缀,而不是C。
这样,在使用组合索引进行查询时,数据库系统就可以使用索引进行快速筛选,而不必扫描整张表。这有助于提高查询的效率。
最左前缀原则对于组合索引的创建非常重要,因为它可以帮助数据库系统更有效地使用索引。如果不遵循最左前缀原则,则组合索引可能会变
得无用,甚至阻碍查询的优化。
分库分表之后,id主键如何处理?
其实这是分库分表之后你必然要面对的一个问题,就是 id昨生成?因为要是分成多个表之后,每个表都是从 1开始累加,那肯定不对啊,需要
一个全局唯一的id来支持。所以这都是你实际生产环境中必须考虑的问题。
数据库自增长 ID
这个就是说你的系统里每次得到一个id,都是往一个库的一个表里插入一条没什么业务含义的数据,然后获取一个数据库自增的一个id。拿到
这个id之后再往对应的分库分表里去写入。
优点:非常简单,有序递增,方便分页和排序。
缺点:分库分表后,同一数据表的自增ID容易重复,无法直接使用(可以设置步长,但局限性很明显);性能吞吐量整个较低,如果设计一个
单独的数据库来实现 分布式应用的数据唯一性,即使使用预生成方案,也会因为事务锁的问题,高并发场景容易出现单点瓶颈。
适用场景:单数据库实例的表ID(包含主从同步场景),部分按天计数的流水号等;分库分表场景、全系统唯一性ID场景不适用。
Redis生成ID
通过Redis的INCR/INCRBY自增原子操作命令,能保证生成的1D肯定是唯一有序的,本质上实现方式与数据库一致。
优点:整体吞吐量比数据库要高。
缺点:Redis 实例或集群宕机后,找回最新的ID值比较麻烦。
适用场景:比较适合计数场景,如用户访问量,订单流水号(日期+流水号)等
UUID、GUID生成ID
优点:性能非常高,本地生成,没有网络消耗;
缺点:UUID太长了、占用空间大,作为主键性能太差了;
由于UUID不具有有序性,会导致B+树索引在写的时候有过多的随机写操作
适合的场景:如果你是要随机生成个什么文件名、编号之类的,你可以用UUID,但是作为主键不建议用UUID的。
snowflake(雪花)算法
snowflake 算法来源于Twitter,使用scala语言实现,snowflake算法的特性是有序、唯一,并且要求高性能,低延迟(每台机器每秒至少生
成10k条数据,并且响应时间在2ms以内),要在分布式环境(多集群,跨机房)下使用,因此 snowflake算法得到的ID是分段组成的:
与指定日期的时间差(毫秒级),41位,够用69年
集群1D+机器ID,10位,最多支持1024台机器
序列,12位,每台机器每毫秒内最多产生4096个序列号
雪花算法核心思想是:分布式ID固定是一个long型的数字,一个long型占8个字节,也就是64个bit
1bit:符号位,固定是0,表示全部|D都是正整数
41bit:表示的是时间戳,单位是毫秒。41 bits可以表示的数字多达241-1,也就是可以标识241-1个毫秒值,换算成年就是表示
69年的时间。
10bit:机器ID,有异地部署,多集群的也可以配置,需要线下规划好各地机房,各集群,各实例ID的编号
12bit:序列ID,用来记录同一个毫秒内产生的不同id,12 bits 可以代表的最大正整数是2^12-1=4096,也就是说可以用这个12 bits
代表的数字来区分同一个毫秒内的4096个不同的id。
优点:
毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。
不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。
可以根据自身业务特性分配bit位,非常灵活。
缺点:
强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
IP地址如何在数据库中存储?
在MySQL中,当存储IPv4地址时,应该使用32位的无符号整数(UNSIGNEDINT)来存储IP地址,而不是使用字符串,用UNSIGNED INT
类型存储IP地址是一个4字节长的整数。
如果是字符串存储|P地址,在正常格式下,最小长度为7个字符(0.0.0.0),最大长度为15个(255.255.255.255),因此,我们通常会使用varchar(15)来存储。同时为了让数据库准确跟踪列中有多少数据,数据库会添加额外的1字节来存储字符串的长度。这使得以字符串表示的IP的实际数据存储成本需要16字节。
这意味着如果将每个IP地址存储为字符串的话,每行需要多耗费大约10个字节的额外资源。
如果你说磁盘够使不是事儿,那我得告诉你,这个不仅会使数据文件消耗更多的磁盘,如果该字段加了索引,也会同比例扩大索引文件的大小,缓存数据需要使用更多内存来缓存数据或索引,从而可能将其他更有价值的内容推出缓存区。执行SQL对该字段进行CRUD时,也会消耗更多的CPU资源。
MySQL中有内置的函数,来对IP和数值进行相互转换。
INET_ATON()
将IP转换成整数。
算法:第一位乘256三次方+第二位乘256二次方+第三位乘256一次方+第四位乘256零次方
• INET_NTOA()
将数字反向转换成IP
SELECT INET_ATON(‘127.0.0.1’);
Java
INET_ATON(‘127.0.0.1’)|
2130706433
1 row in set (0.00 sec)
SELECT INET_NTOA(‘2130706433’);
INET_NTOA(‘2130706433’)|
127.0.0.1
1 row in set
(0.02 sec)
如果是 IPv6地址的话,可以使用函数INET6_ATON()和 INET6_NTOA()来转化:
Mysql> SELECT HEX(INET6_ATON(‘1030::C9B4:FF12:48AA:1A2B’))
Java
| HEX(INET6_ATON(‘1030::C9B4:FF12:48AA:1A2B’))|
| 1030000000000000C9B4FF1248AA1A2B
1 row in set
mysql> SELECT INET6_NTOA(UNHEX('1030000000000000C9B4FF1248AA1A2B
| INET6_NTOA(UNHEX(‘1030000000000000C9B4FF1248AA1A2B’))
| 1030::c9b4:ff12:48aa:1a2b
1 row in set
然后将数据库定义为varbinary 类型,分配 128bits空间(因为ipv6采用的是128bits,16个字节)
间。;或者定义为char 类型,分配 32bits空
如何实现MySQL的读写分离?
其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。
MySQL主从复制原理的是啥?
主库将变更写入binlog日志,然后从库连接到主库之后,从库有一个1O线程,将主库的binlog日志拷贝到自己本地,写入一个relay 中继日志中。接着从库中有一个SQL线程会从中继日志读取binlog,然后执行binlog日志中的内容,也就是在自己本地再次执行一遍SQL,这样就可以保证自己跟主库的数据是一样的。
这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的,也就是说主库上并行的操作,在从库上会串行执行。所以这就是一个非常重要的点了,由于从库从主库拷贝日志以及串行执行SQL的特点,在高并发场景下,从库的数据一定会比主库慢一些,是有延时的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能读取到。
而且这里还有另外一个问题,就是如果主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,有些数据可能就
丢失了。
所以MySQL实际上在这一块有两个机制,一个是半同步复制,用来解决主库数据丢失问题;一个是并行复制,用来解决主从同步延时问题。
这个所谓半同步复制,也叫semi-sync复制,指的就是主库写入binlog日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入
自己本地的relay log之后,接着会返回一个ack给主库,主库接收到至少一个从库的ack之后才会认为写操作完成了。
所谓并行复制,指的是从库开启多个线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。
MySQL主从同步延时问题
以前线上确实处理过因为主从同步延时问题而导致的线上的bug,属于小型的生产事故。
是这个么场景。有个同学是这样写代码逻辑的。先插入一条数据,再把它查出来,然后更新这条数据。在生产环境高峰期,写并发达到了2000/s,这个时候,主从复制延时大概是在小几十毫秒。线上会发现,每天总有那么一些数据,我们期望更新一些重要的数据状态,但在高峰期时候却没更新。用户跟客服反馈,而客服就会反馈给我们。
查看 Seconds_Behind_Master,可以看到从库复制主库的数据落后了几ms。
一般来说,如果主从延迟较为严重,有以下解决方案:
·分库,将一个主库拆分为多个主库,每个主库的写并发就减少了几倍,此时主从延迟可以忽略不计。
打开 MySQL支持的并行复制,多个库并行复制。如果说某个库的写入并发就是特别高,单库写并发达到了2000/s,并行复制还是没意义。
重写代码,写代码的同学,要慎重,插入数据时立马查询可能查不到。
如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询设置直连主库。不推荐这种方法,你这么搞导致读写分离的意义就丧失了。
A
1
原子性(Atomicity):当前事务的操作要么同时成功,要么同时失败。原子性由
undo log日志来保证
一致性(Consistency):使用事务的最终目的,由业务代码正确逻辑保证
·隔离性(Isolation):在事务并发执行时,他们内部的操作不能互相干扰
·持久性(Durability):一旦提交了事务,它对数据库的改变就应该是永久性的。
持久性由redo log日志来保证
InnoDB引擎中,定义了四种隔离级别供我们使用,级别越高事务隔离性越好,但性
能就越低,而隔离性是由MySQL的各种锁以及MVCC机制来实现的
•read uncommit (读未提交):有脏读问题
(read commit(读已提交):有不可重复读问题
repeatable read(可重复读):有幻读问题
serializable(串行):上面问题全部解决
set tx_isolation=‘read-uncommitted’;
set tx_isolation=‘read-committed’;
set tx isolation=‘repeatable-read’
set tx isolation='serializable:
串行化在读后面加锁
读锁(共享锁、S锁):select… lock in share mode;
读锁是共享的,多个事务可以同时读取同一个资源,但不允许其他事务修改
写锁(排它锁、X锁):select… for update;
写锁是排他的,会阻塞其他的写锁和读锁,update、delete、insert都会加写锁
B树和B+树之间的区别是什么?
B-Tree结构
叶节点具有相同的深度 叶节点的指针为空
所有索引元素不重复
节点中的数据索引从左到右递增排列
SHOW GLOBAL STATUS like ‘Innodb_page_size’
B+Tree (B-Tree变种)
非叶子节点不存储data,只存储索引(冗余),可以放更多的索引
叶子节点包含所有索引字段
叶子节点用指针连接,提高区间访问的性能
什么是索引下推?
::索引下推(INDEX CONDITION PUSHDOWN,简称ICP)是在MySQL5.6针对扫描二级索引的一项优化改进。总的来说是通过把索引过滤条件下推到存储引擎,来减少MySQL存储引擎访问基表的次数以及MySQL服务层访问存储引擎的次数。ICP适用于MYISAM和INNODB,本篇的内容只基于INNODB。
在讲这个技术之前你得对mysql架构有一个简单的认识,见下图
MySQL服务层:也就是SERVER层,用来解析SQL的语法、语义、生成查询计划、接管从MySQL存储引擎层上推的数据进行二次过滤
等等。
MySQL存储引擎层:按照MySQL服务层下发的请求,通过索引或者全表扫描等方式把数据上传到MySQL服务层。
MySQL 索引扫描:根据指定索引过滤条件,遍历索引找到索引键对应的主键值后回表过滤剩余过滤条件。
MySQL索引过滤:通过索引扫描并且基于索引进行二次条件过滤后再回表。
select * from ‘user’ where nickname like ‘张%’ and age = 18:
索引下推的使用条件
•ICP目标是减少全行记录读取,从而减少10操作,只能用于非聚簇索引。聚簇索引本身包含的表数据,也就不存在下推一说。
只能用于range、ref.
where 条件中是用
eq_ref、ref_or_null 访问方法;and而非or的时候。
ICP 适用于分区表。
ICP 不支持基于虚拟列上建立的索引,比如说函数索引
ICP不支持引用子查询作为条件。
ICP不支持存储函数作为条件,因为存储引擎无法调用存储函数。
索引下推相关语句
#查看索引下推是否开启
select @@optimizer_switch
#开启索引下推
set optimizer_switch=“index_condition_pushdown=on”;
#关闭索引下推
set optimizer_switch=“index_condition_pushdown=off”;
有哪些情况会导致索引失效?
这个问题要分版本回答!!!版本不同可能会导致索引失效的场景也不同,直接给答案的都是耍流氓!!!
这里回答基于最新MySQL8版,MySQL8失效的以前版本也失效,MySQL8不失效的,以前可能会失
效。
使用
like 并且是左边带%,右边可以带会走索引(但是并不绝对,详细解释看下面 like专题分析)
隐式类型转换,索引字段与条件或关联字段的类型不一致。(比如你的字段是int,你用字符串方式去查
询会导致索引失效)。
在where条件里面对索引列使用运算或者使用函数。
使用
且存在非索引列
在 where 条件中两列做比较会导致索引失效
使用IN可能不会走索引(MySQL环境变量eq_range_index_dive_limit 的值对IN语法有很大影
响,该参数表示使用索引情况下 IN中参数的最大数量。MySQL 5.7.3以及之前的版本中,
举例,
eq_range_index_dive_limit 的默认值为10,之后的版本默认值为200。我们拿 MySQL8.0.19 eq_range_index_dive_limit=200表示当IN(…)中的值 >200个时,该查询一定不会走<=200则可能用到索引。)
索引。
使用非主键范围条件查询时,部分情况索引失效。
使用 order by可能会导致索引失效
is null
is not null ≠可能会导致索引失效
如果表中有字段为NULL索引是否会失效?
为什么LIKE以%开头索引会失效?
数据结构和算法动态可视化(Ch
首先看看B+树是如何查找数据的:
查找数据时,MySQL会从根节点开始,按照从左到右的顺序比较查询条件和节点中的键值。如果查询条件小于节点中的键值,则跳到该节点的左子节点继续查找;如果查询条件大于节点中的键值,则跳到该节点的右子节点继续查找;如果查询条件等于节点中的键值,则继续查找该节点的下一个节点。
比如说我有下面这条SQL:
select
from
where nickname
如果数据库中存在南冥
北冥
西冥
东冥,那么在B+树中搜索的效率和全表扫描还有什么区别呢?
走的聚簇索引全表扫描还不用回表。
最后在扩展讲一个点,其实不一定会导致索引失效。举个例子:
如果表中有字段为NULL索引是否会失效?
首先讲答案不一定。即使我们使用 is null 或者 is not null它其实都是会走索引的。那为什么会有这样的言论呢?这里首先就得来讲讲NULL值是怎么在记录中存储的,又是怎么在B+树中存储的呢。那么在InnoDB中分为聚簇索引和非聚簇索引两种,聚簇索引本身是不允许记录为空的,所以可以不不用考虑,那么就剩下非聚簇索引也就是我们的辅助索引。
那既然IS NULL
用全表扫描呢?
IS NOT NULL、
!= 这些条件都可能使用到索引,那到底什么时候索引,什么时候采
首先我们得知道两个东西,第一个在InnoDB引擎是如何存储NULL值的,第二个问题是索引是如何存储
NUI|值的
这样我们才能从根上理解 NUIL 在什么场景走索引。在什么场景不走索引
在InnoDB引擎是如何存储NULL值的?
InnoDB引擎通过使用一个特殊的值来表示null,这个值通常被称为"null bitmap"。null bitmap是一个二进制位序列,用来标记表中每一个列是否为null。当null bitmap中对应的位为1时,表示对应的列为null;当null bitmap中对应的位为0时,表示对应的列不为nul。在实际存储时,InnoDB引擎会将null bitmap作为行记录的一部分,存储在行记录的开头,这样可以在读取行记录时快速判断每个列是否为null。
从头开始说理解起来会比较容易,理解了独占表空间文件就更容易理解行格式了,接着往下看:
当我们创建表的时候默认会创建一个*.idb文件,这个文件又称为独占表空间文件,它是由段、区、页、
行组成。InnoDB存储引擎独占表空间大致如下图;
表空间(Tablespace)
Segment(表空间)是由各个段(segment)组成的,段是由多个区(extent)组成的。段一般分为数据段、
索引段和回滚段等。
、数据段 存放B+树的叶子节点的区的集合
索引段存放B+树的非叶子节点的区的集合
回滚段 存放的是回滚数据的区的集合,MVCC就是利用了回滚段实现了多版本查询数据
Extent(区)在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区(extent)为单位分配。每个区的大小为1MB,对于16KB的页来说,连续的64个页会被划为一个区,这样就使得链表中相邻的页的物理位置也相邻,就能使用顺序|/O了。
(我们知道InnoDB存储引擎是用B+树来组织数据的。B+树中每一层都是通过双向链表连接起来的,如果是以页为单位来分配存储空间,那么链表中相邻的两个页之间的物理位置并不是连续的,可能离得非常远,那么磁盘查询时就会有大量的随机/O,随机|/O是非常慢的。解决这个问题也很简单,就是让链表中相邻的页的物理位置也相邻,这样就可以使用顺序|/0了,那么在范围查询(扫描叶子节点)的时候性能就会很高。)
Page(页)记录是按照行来存储的,但是数据库的读取并不以「行」为单位,否则一次读取(也就是一次1/0
操作)只能处理一行数据,效率会非常低。
因此,InnoDB的数据是按「页」为单位来读写的,也就是说,当需要读一条记录的时候,并不是将这个行
记录从磁盘读出来,而是以页为单位,将其整体读入内存。
默认每个页的大小为16KB,也就是最多能保证16KB的连续存储空间。
页是InnoDB存储引擎磁盘管理的最小单元,意味着数据库每次读写都是以16KB为单位的,一次最少从磁盘中读取16K的内容到内存中,一次最少把内存中的16K内容刷新到磁盘中。
页的类型有很多,常见的有数据页、undo日志页、溢出页等等。数据表中的行记录是用「数据页」来管理
的,数据页的结构这里我就不讲细说了,总之知道表中的记录存储在「数据页」里面就行。
Row(行)数据库表中的记录都是按行(row)进行存放的,每行记录根据不同的行格式,有不同的存储结
构。
重点来了!!!
InnoDB提供了4种行格式,分别是Redundant、Compact、Dynamic和Compressed行格式。
Redundant 是很古老的行格式了,MySQL5.0版本之前用的行格式,现在基本没人用了,那就不展开
详讲了。
MySQL 5.0之后引入了Compact 行记录存储方式,由于Redundant不是一种紧凑的行格式,而采用更为紧凑的Compact,设计的初衷就是为了让一个数据页中可以存放更多的行记录,从MySQL5.1版本之后,行格式默认设置成Compact。
Dynamic 和Compressed 两个都是紧凑的行格式,它们的行格式都和Compact 差不多,因为都是基
于Compact改进一点东西。从MySQL5.7版本之后,默认使用Dynamic行格式。
那么我们来看看Dynamic里面长什么样,先混个脸熟。
这里简单介绍一下,Dynamic行格式其他内容后面单独出一个章节介绍。
NULL值列表(本问题介绍重点)
表中的某些列可能会存储NULL值,如果把这些NULL值都放到记录的真实数据中会比较浪费空
间,所以Compact行格式把这些值为NULL的列存储到NULL值列表中。如果存在允许 NULL值的列,则每个列对应一个二进制位(bit),二进制位按照列的顺序逆序排列。
二进制位的值为 1时,代表该列的值为NULL。二进制位的值为0时,代表该列的值不为
NULL。另外,NULL值列表必须用整数个字节的位表示(1字节8位),如果使用的二进制位个数
不足整数个字节,则在字节的高位补0。
当然NULL值列表也不是必须的。当数据表的字段都定义成NOTNULL的时候,这时候表里的行格
式就不会有NULL值列表了。所以在设计数据库表的时候,通常都是建议将字段设置为NOT
NULL,这样可以节省1字节的空间(NULL值列表占用1字节空间)。
厂NULL值列表」的空间不是固定1字节的。当一条记录有9个字段值都是NULL,那么就会创建2字节空间的「NULL值列表」,以此类推。
索引是如何存储NULL值的?
我们知道 InnoDB引擎中按照物理存储的不同分为聚簇索引和非聚簇索引,聚簇索引也就是主键索引,那么是不允许为空的。那就不再我们本问题的讨论范围,我们重点来看看非聚簇索引,非聚簇索引是允许值为空的。
在InnoDB中非聚簇索引是通过B+树的方式进行存储的
从图中可以看出,对于 s1表的二级索引 idx_key1 来说,值为 NULL的二级索引记录都被放在了
B+ 树的最左边,这是因为设计 InnoDB 的大叔有这样的规定:
We define the SQL null to be the smallest possible value of a field
也就是说他们把 SQL中的NULL值认为是列中最小的值。在通过二级索引idx_key1对应的B+树快速定位到叶子节点中符合条件的最左边的那条记录后,也就是本例中id值为521的那条记录之后,就可以顺着每条记录都有的next_record属性沿着由记录组成的单向链表去获取记录了,直到某条记录的key1列不为NULL。
我们了解了上面的两个问题之后,我们就可以来看看,使不使用索引的依据是什么了
实际上来说我们用
is null is not null ≠这些条件都是能走索引的,那什么时候走索引什么时候走
全表扫描呢?
总结起来就是两个字:成本!!!
如何去度量成本计算使用某个索引执行查询的成本就非常复杂了,展开讲这个话题就停不下来了,后面考虑
单独列一个篇幅去讲。
这里总结性讲讲:第一个,读取二级索引记录的成本,第二,将二级索引记录执行回表操作,也就是到聚簇
索引中找到完整的用户记录操作所付出的成本。
要扫描的二级索引记录条数越多,那么需要执行的回表操作的次数也就越多,达到了某个比例时,使用二级索引执行查询的成本也就超过了全表扫描的成本(举一个极端的例子,比方说要扫描的全部的二级索引记录,那就要对每条记录执行一遍回表操作,自然不如直接扫描聚簇索引来的快)
所以MySQL优化器在真正执行查询之前,对于每个可能使用到的索引来说,都会预先计算一下需要扫描的
二级索引记录的数量,比方说对于下边这个查询:
SELECT * FROM SI WHERE key1 IS NULL;
优化器会分析出此查询只需要查找key1 值为NULL的记录,然后访问一下二级索引
idx_key1,看一下值为 NULL的记录有多少(如果符合条件的二级索引记录数量较少,那么统计结果是精确的,如果太多的话,会采用一定的手段计算一个模糊的值,当然算法也比较麻烦,我们就不展开说了),这种在查询真正执行前优化器就率先访问索引来计算需要扫描的索引记录数量的方式称之为index dive。当然,对于某些查询,比方说WHERE子句中有IN条件,并且IN条件中包含许多参数的话,比方说这样:
SQL
SELECT * FROM s1 WHERE key1 IN (‘a’,‘b
zzzzzzz’
这样的话需要统计的key1 值所在的区间就太多了,这样就不能采用 index dive 的方式去真正的访问二级索引idx_key1,而是需要采用之前在背地里产生的一些统计数据去估算匹配的二级索引记录有多少条(很显然根据统计数据去估算记录条数比 index dive 的方式精确性差了很多)。
反正不论采用 index dive 还是依据统计数据估算,最终要得到一个需要扫描的二级索引记录条数,如果这个条数占整个记录条数的比例特别大,那么就趋向于使用全表扫描执行查询,否则趋向于使用这个索引执行查询。
理解了这个也就好理解为什么在WHERE子句中出现 IS NULL、
!=这些条件仍然可以
使用索引,本质上都是优化器去计算一下对应的二级索引数量占所有记录数量的比值而已。
大家可以看到,MySQL 中决定使不使用某个索引执行查询的依据很简单:就是成本够不够小。而不是是否在WHERE子句中用了 IS NULL、IS NOT NULL、!=这些条件。大家以后也多多辟谣吧,没那么复杂,只是一个成本而已。
为什么LIKE以%开头索引会失效?
首先看看B+树是如何查找数据的:
// 特殊情况,这种也是会走索引的,虽然我的age在前面,username在后面。
/ 刚刚不是手最左前缀匹配吗,为什么放到第二位也可以呢?
// 虽说顺序不一致,但是在SQL执行过程中,根据查询条件命中索引// 无论我username在不在前面,都会按照username去进行索引查找。select * from user where age = 18 and username =‘张三
使用Order By时能否通过索引排序?
我们知道在很多场景下会导致索引失效,比如说没有遵循B+树的最左匹配原则,但是也有一些情况是遵循了最左匹配原则但是还是没有走索引,这里我们使用order by进行排序的时候就有不走索引的情况,那么带大家来分析一下
SQL
drop table if exists drop table if exists create table ‘user’(
user
user_examp te
id` int primary key comment’主键ID’
card_id’ int comment’身份证’,
nickname’varchar(10)comment‘昵称’,age’ int not null comment’年龄’,‘card_id’ (‘card_id’)
key
) engine=InnoDB default charset=utf8mb4;
//这里我们明明对card_id建好了单列索引,那为什么不走索引呢?
select * from ‘user’ order by card_id
如果索引覆盖是可以走索引的
如果带上索引条件是可以走索引的
通过索引排序内部流程是什么呢?
explain select nickname,card_id,age from user order by card_id;
我们在了解mysql底层是怎么排序的之前,我们先来了解一下一个概念 sort buffen
首先mysql会为每一个线程都分配一个固定大小的sort buffer 用于排序。它是一个具有逻辑概念的
内存区域,我们可以通过sort_buffer_size 参数来控制,默认值是 256kb
// 输入查看最,小可以设置为32K,最大可以设置为46。
show variables like ‘sort_buffer_size’;
SQL
由于 sort buffer 大小是一个固定的,但是我们待排序的数据量它不是,所以根据它们之间的一个差值
呢,就分为了内部排序和外部排序
当待排序的数据量小于等于sort buffer 时,那我们的sort buffer 就能够容纳,MySQL就可以直接
在内存里面排序就行了,内部排序使用的排序算法是 快排
当待排序的数据量大于 sort buffer时,那我们的sort buffer 就不够用了对吧。这个时候MySQL就得要借助外部文件来进行排序了。将待排序数据拆成多个小文件,对各个小文件进行排序,最后再汇总成一个有序的文件,外部排序使用的算法时 归并排序
我们来聊聊row_id排序
和大家说一个这个参数max_length_for_sort_data ,在我们MySQL中专门控制用户排序的行数据长
度参数。默认是4096,也就是说如果超过了这个长度MySQL就会自动升级成
row_id 算法。
//默认max_length_for_sort_data的大小为4096字节
show variables like ‘max_Length_for_sort_data’
row_id 排序的思想就是把不需要的数据不放到
sort buffe中,让sort buffer只存放需要排序的字段。
explain select nickname,card_id,age from user order by card_id;
SQL
我们前面说到了sort buffer,在 sort buffer 里面进行排序的数据是我们select的全部字段,所以当我们查询的字段越多,那么 sort buffer 能容纳的数据量也就越小。而通过row_id 排序就只会存放row_id 字段和排序相关的字段。其余的字段等排序完成之后通过主键1D进行回表拿。
group by分组和order by在索引使用上有什么不同吗?
没什么太大的差异 group by实际是先进行排序,再进行分组。所以遵循order by的索引机制。
索引的基本原理
索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。
索引的原理:就是把无序的数据变成有序的查询
1.把创建了索引的列的内容进行排序
2.对排序结果生成倒排表
3.在倒排表内容上拼上数据地址链
4.在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
索引设计的原则?
查询更快、占用空间更小
1.适合索引的列是出现在where子句中的列,或者连接子句中指定的列
2.基数较小的类,索引效果较差,没有必要在此列建立索引
3.使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词
超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配。
4.不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至
重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
5.定义有外键的数据列一定要建立索引。
6.更新频繁字段不适合创建索引
7.若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
8.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索
引即可。
9.对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
10.对于定义为text、image和bit的数据类型的列不要建立索引。
索引覆盖是什么
索引覆盖就是一个SQL在执行时,可以利用索引来快速查找,并且此SQL所要查询的字段在当前索引对应的字段中都包含了,那么
就表示此SQL走完索引后不用回表了,所需要的字段都在当前索引的叶子节点上存在,可以直接作为结果返回了
最左前缀原则是什么
当一个SQL想要利用索引是,就一定要提供该索引所对应的字段中最左边的字段,也就是排在最前面的字段,比如针对a,b,c三个字段建立了一个联合索引,那么在写一个sql时就一定要提供a字段的条件,这样才能用到联合索引,这是由于在建立a,b,c三个字段的联合索引时,底层的B+树是按照a,bc三个字段从左往右去比较大小进行排序的,所以如果想要利用B+树进行快速查找也得符合这个规则
Innodb是如何实现事务的
Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例:1.Innodb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据
3.针对update语句生成一个RedoLog对象,并存入LogBuffer中
4.针对update语句生成undolog日志,用于事务回滚
5.如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据页持久化到磁盘中
6.如果事务回滚,则利用undolog日志进行回滚
MySQL的集群是如何搭建的?读写分离是怎么做的?
由于这个发送binlog的过程是异步的。主服务在向客户端反馈执行结果时,是不知道binlog是否同步成功了的。这时候如果主服务宕机了,而从服务还没有备份到新执行的binlog,那就有可能会丢数据。
那怎么解决这个问题呢,这就要靠MySQL的半同步复制机制来保证数据安全
半同步复制机制是一种介于异步复制和全同步复制之前的机制。主库在执行完客户端提交的事务后,并不是立即返回客户端响应,而是等待至少一个从库接收并写到relay log中,才会返回给客户端。MySQL在等待确认时,默认会等10秒,如果超过10秒没有收到ack,就会降级成为异步复制。
这种半同步复制相比异步复制,能够有效的提高数据的安全性。但是这种安全性也不是绝对的,他只保证事务提交后的binlog至少传输到了一个从库,并且并不保证从库应用这个事务的binlog是成功的。另一方面,半同步复制机制也会造成一定程度的延迟,这个延迟时间最少是一个TCP/IP请求往返的时间。整个服务的性能是
mysql高可用方案?
1、MMM
MMM(Master-Master replication managerfor Mysql,Mysql主主复制管理器)是一套由Perl语言实现的脚本程序,可以对mysql集群进行监控和故障迁移。他需要两个Master,同一时间只有一个Master对外提供服务,可以说是主备模式。
他是通过一个VIP(虚拟IP)的机制来保证集群的高可用。整个集群中,在主节点上会通过一个VIP地址来提供数据读写服务,而当出现故障时,VIP就会从原来的主节点漂移到其他节点,由其他节点提供服务。
2、MHA
Master High Availability Manager and Tools for MySQL。是由日本人开发的一个基于Perl脚本写的工具。这个工具专门用于监控主库的状态,当发现master节点故障时,会提升其中拥有新数据的slave节点成为新的master节点,在此期间,MHA会通过其他从节点获取额外的信息来避免数据一致性方面的问题。MHA还提供了mater节点的在线切换功能,即按需切换master-slave节点。MHA能够在30秒内实现故障切换,并能在故障切换过程中,最大程度的保证数据一致性。在淘宝内部,也有一个相似的TMHA产品。
MHA是需要单独部署的,分为Manager节点和Node节点,两种节点。其中Manager节点一般是单独部署的一台机器。而Node节点一般是部署在每台MySQL机器上的。Node节点得通过解析各个MySQL的日志来进行一些操作。
Manager节点会通过探测集群里的Node节点去判断各个Node所在机器上的MySQL运行是否正常,如果发现某个Master故障了,就直接把他的一个Slave提升为Master,然后让其他Slave都挂到新的Master上去,完全透明。
3、MGR
MGR:MySQL Group Replication。是MySQL官方在5.7.17版本正式推出的一种
组复制机制。主要是解决传统异步复制和半同步复制的数据一致性问题。
由若干个节点共同组成一个复制组,一个事务提交后,必须经过超过半数节点的决议并通过后,才可以提交。引入组复制,主要是为了解决传统异步复制和半同步复制可能产生数据不一致的问题。MGR依靠分布式一致性协议(Paxos协议的一个变体),实现了分布式下数据的最终一致性,提供了真正的数据高可用方案(方案落地后是否可靠还有待商榷)。
支持多主模式,但官方推荐单主模式:
。多主模式下,客户端可以随机向MySQL节点写入数据
单主模式下,MGR集群会选出primary节点负责写请求,primary节点与其它节
点都可以进行读请求处理.
GTID同步集群
上面我们搭建的集群方式,是基于Binlog日志记录点的方式来搭建的,这也是最
为传统的MySQL集群搭建方式。而在这个实验中,可以看到有一个
Executed_Grid_Set列,暂时还没有用上。实际上,这就是另外一种搭建主从同步的
方式,即GTID搭建方式。这种模式是从MySQL5.6版本引入的。
GTID的本质也是基于Binlog来实现主从同步,只是他会基于一个全局的事务ID来标识同步进度。GTID即全局事务ID,全局唯一并且趋势递增,他可以保证为每一个在主节点上提交的事务在复制集群中可以生成一个唯一的ID。
在基于GTID的复制中,首先从服务器会告诉主服务器已经在从服务器执行完了哪些事务的GTID值,然后主库会有把所有没有在从库上执行的事务,发送到从库上进行执行,并且使用GTID的复制可以保证同一个事务只在指定的从库上执行一次,这样可以避免由于偏移量的问题造成数据不一致。
他的搭建方式跟我们上面的主从架构整体搭建方式差不多。只是需要在my.cnf中
修改一些配置。
在主节点上:
mysql聚簇和非聚簇索引的区别
都是B+树的数据结构
,聚簇索引:将数据存储与索引放到了一块、并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的I物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的非聚簇索引:叶子节点不存储数据、存储的是数据行地址,也就是说根据索引查找到数据行的位置再取磁盘查找数据,这个就有点类似一本树的目录,比如我们要找第三章第一节,那我们先在这个目录里面找,找到对应的页码后再去对应的页码看文章。
优势:
1、查询通过聚簇索引可以直接获取数据,相比非聚簇索引需要第二次查询(非覆盖索引的情况下)效率要高
2、聚簇索引对于范围查询的效率很高,因为其数据是按照大小排列的
3、聚簇索引适合用在排序的场合,非聚簇索引不适合
劣势:
1、维护索引很昂贵,特别是插入新行或者主键被更新导至要分页(page sp1it)的时候。建议在大量插入新行后,选在负载较低的时间段,通过OPTIMIZE TABLE优化表,因为必须被移动的行数据可能造成碎片。使用独享表空间可以弱化碎片
2、表因为使用UUId(随机ID)作为主键,使数据存储稀疏,这就会出现聚族索引有可能有比全表扫面更慢,所以建
议使用int的auto_increment作为主键
3、如果主键比较大的话,那辅助索引将会变的更大,因为辅助索引的叶子存储的是主键值;过长的主键值,会导致非
叶子节点占用占用更多的物理空间
InnoDB中一定有主键,主键一定是聚簇索引,不手动设置、则会使用unique索引,没有unique索引,则会使用
数据库内部的一个行的隐藏id来当作主键索引。在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值
MyISM使用的是非聚簇索引,没有聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。
如果涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,
这些操作是需要在内存中完成的。
Mysql数据库中,什么情况下设置了索引但无法使用?
1.没有符合最左前缀原则
2.字段进行了隐私数据类型转化
3.走索引没有全表扫描效率高
Innodb是如何实现事务的
Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例:1.Innodb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据
3.针对update语句生成一个RedoLog对象,并存入LogBuffer中
4.针对update语句生成undolog日志,用于事务回滚
5.如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据页持久化到磁盘中
6.如果事务回滚,则利用undolog日志进行回滚
mysql索引的数据结构,各自优劣
索引的数据结构和具体存储引擎的实现有关,在MySQL中使用较多的索引有Hash索引,B+树索引等,InnoDB存储引擎的默认索引实现为:B+树索引。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
B+树:
B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接。在B+树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大幅波动,而且基于索引的顺序扫描时,也可以利用双向指针快速左右移动,效率非常高。因此,B+树索引被广泛应用于数据库、文件系统等场景。
哈希索引:
哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点
逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快
如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经过一次算法即可找到相应的键值;前提是键值都是
唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据;
如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;
哈希素引也没办法利用索引完成排序,以及likexxx%这样的部分模糊查询(这种部分模糊查询,其实本质上也是
范围查询);
哈希索引也不支持多列联合索引的最左匹配规则;
B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是
极低的,因为存在哈希碰撞问题。
MySQL有哪几种数据存储引擎?有什么区别?
MySQL中通过show ENGINES指令可以看到所有支持的数据库存储引擎。 最为常用的就是MyISAM和nnoDB两种。
MylSAM和LnnDB的区别:
1、存储文件。 MylSAM每个表有两个文件。 MYD和MYISAM文件。 MYD是数据文件。 MYI是索引文件。而InnDB每个表
只有一个文件,idb。
2、LnnoDB支持事务,支持行级锁,支持外键。
3、InnoDB支持XA事务
4、LnnoDB支持savePoints
mysql主从同步原理
mysql主从同步的过程:
Mysql的主从复制中主要有三个线程:master(binlog dump thread)
thread),Master—条线程和Slave中的两条线程。
·主节点binlog,主从复制的基础是主库记录数据库的所有变更记录到binlog。binlog是数据库服务器启动的
那一刻起,保存所有修改数据库结构或内容的一个文件。
主节点log dump线程,当binlog有变动时,log dump 线程读取其内容并发送给从节点。
从节点1/O线程接收binlog内容,并将其写入到relaylog文件中。
·从节点的SQL线程读取 relay log 文件内容对数据更新进行重放,最终保证主从数据库的一致性。
注:主从节点使用binglog文件+position偏移量来定位主从同步的位置,从节点会保存其已接收到的偏移量
如果从节点发生宕机重启,则会自动从 position的位置发起同步。
由于mysql默认的复制方式是异步的,主库把日志发送给从库后不关心从库是否已经处理,这样会产生一个问题就
是假设主库挂了,从库处理失败了,这时候从库升为主库后,日志就丢失了。由此产生两个概念。
全同步复制
主库写入binlog后强制同步日志到从库,所有的从库都执行完成后才返回给客户端,但是很显然这个方式的话性能
会受到严重影响。
半同步复制
和全同步不同的是,半同步复制的逻辑是这样,从库写入日志成功后返回ACK确认给主库,主库收到至少一个从库
的确认就认为写操作完成。
海量数据下,如何快速查找一条记录?
1、使用布隆过滤器,快速过滤不存在的记录。
使用Redis的bitmap结构来实现布隆过滤器。
2、在Redis中建立数据缓存。-将我们对Redis使用场景的理解尽量表达出来。
以普通字符串的形式来存储,(serld->user.json)。以一个hash来存储一条记录(userld key->username field->,userAge->)。以一个整的hash来存储所有的数据,Userlnfo->field就用userld,value就用user.json。一个hash最多能支持2^32-1(40多个亿)个键值对。
缓存击穿:对不存在的数据也建立key。这些key都是经过布隆过滤器过滤的,所以一般不会太多
缓存过期:将热点数据设置成永不过期,定期重建缓存。 使用分布式锁重建缓存。
3、查询优化。
按槽位分配数据,
自己实现槽位计算,找到记录应该分配在哪台机器上,然后直接去目标机器上找
事务的基本特性和隔离级别有哪些?
事务: 表示多个数据操作组成一个完整的事务单元,这个事务内的所有数据操作要么同时成功,要么同时失败。
事务的特性:ACID
1、原子性:事务是不可分割的,要么完全成功,要么完全失败。
2、一致性:事务无论是完成还是失败,都必须保持事务内操作的一致性。当失败时,都要对前面的操作进行回滚,不管中途
是否成功。
3、隔离性:当多个事务操作一个数据的时候,为防止数据损坏,需要将每个事务进行隔离,互相不干扰。
4、持久性:事务开始就不会终止。他的结果不受其他外在因素的影响。
事务的隔离级别:SHOW VARIABLES like’transaction%’
设置隔离级别:set transaction level xxx设置下次事务的隔离级别。
set session transaction level xxx设置当前会话的事务隔离级别
set global transaction level xxx设置全局
set global transaction level xxx设置全局事务隔离级别
MySQL当中有五种隔离级别
NONE:不使用事务。
READ UNCOMMITED:I允许脏读
READ COMMITED:防止脏读,最常用的隔离级别
REPEATABLE READ::防止脏读和不可重复读。MYSQL默认
SERIALIZABLE:事务串行,可以防止脏读、幻读,不可重复度。
五种隔离级别,级别越高,事务的安全性是更高的,但是,事务的并性能也就会越低。
什么是MVCC
MVCC(Multi-Version Concurrency Control)多版本并发控制,就可以做到读写不阻塞,
且避免了类似脏读这样的问题,主要通过undo日志链来实现
read commit(读已提交),语句级快照
repeatable read(可重复读),事务级快照
多版本并发控制:读取数据时通过一种类拟快照的方式将数据保存下来,这样读锁就和写锁不冲突了,不同的事务
session会看到自己特定版本的数据,版本链
MVCC只在 READ COMMITTED 和 REPEATABLE READ两个隔离级别下工作。其他两个隔离级别够和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。
聚簇索引记录中有两个必要的隐藏列:
trx_id:用来存储每次对某条聚簇索引记录进行修改的时候的事务id。
roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性,因为它没有老版本)
已提交读和可重复读的区别就在于它们生成ReadView的策略不同。
开始事务时创建readview,readView维护当前活动的事务id,即未提交的事务id,排序生成一个数组
访问数据,获取数据中的事务id(获取的是事务id最大的记录),对比readview:
如果在readvew的左边(比readview都小),可以访问(在左边意味着该事务已经提交)
如果在readview的右边(比readview都大)或者就在readview中,不可以访问,获取roll_pointer,取上一版本
重新对比(在右边意味着,该事务在readview生成之后出现,在readview中意味着该事务还未提交)
已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的
时候生成一个ReadView,之后的读都复用之前的ReadView。
这就是MysqI的MVCC,通过版本链,实现多版本,可并发读-写,写-读。通过ReadView生成策略的不同实现不同的
隔离级别。
什么是脏读、幻读、不可重复读?要怎么处理?
这些问题都是MySQL进行事务并发控制时经常遇到的问题。
脏读:在事务进行过程中,读到了其他事务未提交的数据。
不可重复读:在一个事务过程中,多次查询的结果不一致。
幻读:在一个事务过程中,用同样的操作查询数据,得到的记录数不相同。
处理的方式有很多种:加锁、事务隔离、MVCC
加锁:
1、脏读:在修改时加排他锁,直到事务提交才释放。读取时加共享锁,读完释放锁。
2、不可重复读:读数据时加共享锁,写数据时加排他锁。
3、幻读:加范围锁。
事务的基本特性和隔离级别
事务基本特性ACID分别是:
原子性指的是一个事务中的操作要么全部成功,要么全部失败。
一致性指的是数据库总是从一个一致性的状态转换到另外一个一致性的状态。
BCf转账给B100块钱,假设A只有90块,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证
隔离性指的是一个事务的修改在最终提交前,对其他事务是不可见的。
持久性指的是一旦事务提交,所做的修改就会永久保存到数据库中。
隔离性有4个隔离级别,分别是:
read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。
用户本来应该读取到id=1的用户age应该是10,结果读取到了其他事务还没有提交的事务,结果读取结果
age=20,这就是脏读。
read commit 读已提交,两次读取结果不一致,叫做不可重复读.
不可重复读解决了脏读的问题,他只会读取已经提交的事务。
用户开启事务读取id=1用户,查询到age=10,再次读取发现结果=20,在同一个事务里同一个查询读取到不同的结果叫做不可重复读。
repeatable read 可重复复读,这是mysgl的默认级别,
,就是每次读取结果都一样,但是有可能产生幻读。
serializable串行,一般是不会使用的,他会给每一行读取的数据加锁,会导致大量超时和锁竞争的问题。
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个
Mysql慢查询该如何优化?
1.检查是否走了索引,如果没有则优化SQL利用索引
2.检查所利用的索引,是否是最优索引
3.检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据
4.检查表中数据是否过多,是否应该进行分库分表了
5.检查数据库实例所在机器的性能配置,是否太低,是否可以适当增加资源
什么是Mysql中的降序索引?
大家可能对索引比较熟悉,而对降序索引比较陌生,事实上,降序索引是索引的子集。
我们通常使用下面的语句来创建一个索引:
create index idx tl bcd on tl(b,c,d);
上面sql的意思是在t1表中,针对b,c,d三个字段创建一个联合索引。
但是大家不知道的是,上面这个sql实际上和下面的这个sql是等价的:
create index idx tl_bcd on tl(b asc,c asc,d asc);
asc 表示的是升序,使用这种语法创建出来的索引叫做升序索引。也就是我们平时在创建索引的时候,创建的都是升序索引。
可能你会想到,在创建的索引的时候,可以针对字段设置asc,那是不是也可以设置desc呢?
当然是可以的