181、mysql数据库中的引擎
用于数据存储、处理和保护数据的核心服务,不同的数据库引擎有其各自的特点,常见的引擎:InnoDB,Mylsam、Memory、Mrg_Mylsam、Blackhole
innodb:是一个事务性存储引擎,提供了对事务的支持,实现了sql标准的四种隔离级别,具有行级锁定,在写入数据时候,不需要锁定整个表以及外键支持,innodb会在内存中建立缓冲池,用于缓存数据以及索引,可以表损坏后恢复数据
MyIsam:没有提供数据库事务的支持,不支持细粒度的锁以及外键,当insert和update时候,需要锁定整张表,效率低,高并发瓶颈、表损坏后不能恢复数据
Memory引擎:使用存在内存中的内容来创建表,每个表实际只对应一个磁盘文件,访问速度极快,默认使用hash索引,
blackhole引擎:任何写入到该引擎的数据均会被丢掉,不做实际存储,
182、为什么选择inndb
支持事务,确保数据的一致性和完整性;更好的并发处理,避免表级锁可能引发的性能问题;外键约束,以维护数据的完整性和关系;更可靠的崩溃恢复能力
innodb的特性:
事务支持、行级锁、崩溃恢复、外键约束、主从复制、自动增长列
183、mylasm和innodb在锁方面有何区别
mylasm:使用表级锁,一个事务获取锁后,其他事务无法同时修改整个表的数据
innodb:行级锁,多个事务可以同时修改表的不同行,避免了大部分冲突,提高并发性能
补充:MySQL介绍下InnoDB, MyISAM区别?
InnoDB:支持事务、行级锁、读写阻塞与事务隔离级别相关、非常高效的缓存特性,不缓存数据、支持外键、支持全文索引、所有表都保存一个数据文件中
MyISAM:不支持事务、表级锁、读写过程相互阻塞、缓存只会缓存索引文件、不支持外键、只支持全文索引、每个在MyISAM在磁盘上存储成三个文件(MYD、MYI)
补充:mysql事务
事务是指对数据库执行一批操作,在同一个事务当中,这些操作要么全部执行成功,要么全部失败;事务是一个原子操作,是一个最小执行单元,可以由一个或多个sql语句组成;
在同一个事务中,所有的sql语句都执行成功,整个事务成功,有一个sql失败,整个事务失败
补充:事务的实现原理
事务是基于重做日志redolog和回滚日志undo log实现的
Undolog:当事务对数据库进行修改的时候,InnoDB会生成对应的undolog,如果事务执行失败或者调用了rollback,导致事务需要回滚,便可以利用undolog中的信息将数据回滚到修改之前的样子。
当发生回滚时候,InnoDB会根据undolog的内容的与之前相反的工作,对于insert,回滚时执行delete;对于delete,执行insert;对于update,回滚时候执行一个相反的update事务原子性和隔离性实现的基础,它记录是sql执行相关的信息Redo log:事务中操作的任何数据,将最新的数据备份到一个地方,保证事务持久性 当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作;当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。每提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库就通过重做日志来保证原子性和持久性,每当有修改事务时,还会产生undo log,如需回滚,则根据undo log的反向语句进行逻辑操作
184、事务的ACID属性
原子性、一致性、隔离性、持久性,innodb通过事务日志和写前日志来确保acid事务
原子性(Atomicity):事务中的操作要么全部执行成功,要么全部执行失败
一致性(Consistency):事务中操作的数据一级状态改变是一致的,不会因为出现系统以外原因导致状态的不一致
隔离性(Isolation):多个事务并行执行,彼此隔离
持久性(Durability):事务一旦提交,对数据的修改永久保存
补充:隔离级别
RU(read uncommitted):所有事务都可以看到其他未提交的执行结果,不能解决脏读、不可重复读和幻读(脏读:读取未提交的数据)
RC(read committed):一个事务只能看见已经提交事务所作的改变,解决脏读,会出现不可重复读和幻读
”默认“RR(repeatable read):确保同一事务的多个实例在并发读取数据时候,会看到同样的数据行,会导致幻读(当某用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行),不能解决幻读
Serializable:强制事务排序,使之不可能冲突 ,最高的隔离级别,解决脏读、不可重复度和幻读(就是在每个读的数据行上加上共享锁)
并且隔离级别是可以修改的:set global transaction_isolation
补充:innoDB如何ACID的技术保证
185、脏读和幻读
脏读:是一个事务读取了另一个事务尚未提交的数据,当一个事务读取了其他事务中未提交的数据,并且这些数据最终可能被回滚,就会出现脏读;
不可重复读:一个事务先后读取了同一条记录,而事务在两次读取之间该数据被其他事务所修改,则两次读取的数据不同
幻读:是指在一个事务中多次执行相同的查询,但在这些查询之间,其他事务插入、删除和修改了数据,导致之前的查询结果不一致;
幻读与可重复读的区别在于,可重复读关注的是相同数据的多次读取,而幻读关注的是查询结果集不一致
补充:binlog
记录数据库表变更以及表数据修改的二进制文件,binlog不会记录select show等操作,没有做到实际的修改
186、死锁以及避免方式
死锁是指两个或多个事务相互等待对方持有资源,导致他们都无法继续执行,为了避免死锁,可采取加锁顺序、设置超时、使用死锁监测
187、在一个大批量数据插入中如何提高性能
关闭自动提交,将数据插入完成后再提交事务,减少提交的频率
使用批量插入语句,减少单条插入的开销
加你个数据从文件中加载到表中
设置合理的事务隔离级别
188、索引
数据库中存储着满足特定查找的数据结构,并以某种引用指向表中的数据,这样就可以通过数据结构实现高级算法来快速找到我们想要的数据,是一种数据结构,包含着对数据表里所有记录的引用指针
补充:MySQL为啥用B+树,相比hash的优点,覆盖索引,从左匹配机制,举例一个索引什么情况下走这个索引
hash索引底层是哈希表,哈希表是一种以kv存储数据的结构,所以多个数据在存储关系上是完全没有任何顺序的,对于区间查询是无法直接通过索引查询的,就需要全表扫描,故哈希索引只适用于等值查询
B+树是一种多路平衡查询树,节点天然有序,对范围内查询时候不需要全表扫描
补充:B+树和B-树的区别
B-树特点:所有键值都分布在整颗树中,索引值和具体的data都在每个节点里;任何一个关键字出现只出现在一个结点中;B+树的每个节点,都是存储多个值的,不像二叉树那样,一个节点就一个值,B+树把每个节点都给了一点的范围区间,区间更多的情况下,搜索也就更快;
B+树特点:所有关键字存储在叶子节点出现,内部节点不存储真正的数据;为所有叶子结点增加了一个指针
区别:B+树节点不存储数据,所有的data存储在叶子节点导致查询时间复杂度为logn,B-树时间复杂度不固定
189、哪些场景需要创建索引
1、主键自动建立唯一索引
2、频繁作为查询条件的字段应该创建索引
3、查询中与其他表关联的字段,外键关系建立索引
4、多字段查询下倾向创建组合索引
5、查询中排序的字段,排序字段若通过索引去访问将提高排序速度
6、查询中统计或者分组字段
190、索引分类
1、主键索引
表中的列设定为主键后,数据库会自动建立主键索引
2、唯一索引
一个索引只包含单个列,一个表可以有多个单值索引,唯一索引是一种保证索引列中的值都是唯一的索引,可以用于加速查找操作,同时确保列中的值不会重复
3、复合索引
建表时可随表一起建立复合索引,单独创建和删除复合索引(多个列值组成一个索引,专门用于组合搜索,其效率大于索引合并)
4、聚集索引和非聚集索引
注意:并不是一种单独的索引类型,而是一种数据存储方式,
聚集索引定义了表的区里存储顺序,表中的数据按照聚集索引顺序进行存储,一个表只能有一个聚集索引
当创建了聚集索引时候,实际上重新组织了表中的数据,以便他们按照索引的顺序进行存储
聚集索引可以提高范围查询的性能
5、全文索引
只有在MyISAM上才能使用,只能在char、varchar、text类型字段上使用全文索引
补充:为什么B+树高度不超过四层
我们与磁盘的交互的次数,是收到B+树高度的影响的,应当减少与磁盘的IO次数,保证查询效率
补充:索引底层实现
hash索引
基于hash表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对多有的索引列计算一个hashcode,并且hash索引将所有的哈希码存储在索引中,同时在索引表保存指向每个数据行的指针
B-Tree索引
加快数据的访问速度,存储引起过不再需要进行全表扫描来获取数据,数据分布在各个节点中
B+Tree索引
数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址
补充:为什么索引结构默认使用B+Tree,而不是B-Tree、hash或者红黑树
B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B(B-)树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。
补充:Mysql的最左前原则和前缀原则
补充:建立索引的原则
1、最左前缀匹配原则
2、尽量选择区分度高的列作为索引
3、索引列不能参与计算,保持列“干净”,
4、尽量的扩展索引,不要新建索引
191、共享锁和排他锁的概念
共享锁允许多个事务同时获取读取访问权限,但阻止其他事务获取排他锁,多个事务可以同时持有共享锁,不会出现数据冲突的情况(都能访问到数据,但是只能读不能修改)
排他锁在事务需要修改数据的时候获取,阻止其他事务获取共享锁或排他锁。只有一个事务可以支持排他锁(一个事务在一行数据加上排他锁之后,其他事务不能再加上其他锁)
192、表级锁和行级锁
表级锁是对整个表进行锁定,当一个事务获得表级锁的时候,其他事务无法访问该表的任何部分
行级锁允许在表的不同行上同时存在不同的锁状态,即使一个事务持有行级锁,其他事务任然可以在其他行上进行操作
193、乐观锁和悲观锁
乐观锁在大多数情况下,事物之间不会产生冲突,允许并发操作,在进行修改的时候,会比较先前读取的数据与当前数据,如果数据没有被其他事务修改,允许更新
悲观锁的核心思想就是假设冲突会频繁发生,因此在数据处理过程中将数据锁定,防止其他事务修改数据
194、事务隔离级别方面,提供了哪些选项
读未提交:允许一个事务读取另一个未提交的事务的修改
读已提交:一个事务只能读取已提交的数据,避免了脏读,
可重复读:保证一个事务在同一个查询中多次读取相同的数据时候,结果始终一致
串行化:最高的隔离级别,确保事务之间不会出现任何告饶,但可能会导致并发性能问题
补充:为什么mysql需要加锁
当多个用于并发地存取数据时候,在数据库中就会产生多个事务同时存取同一数据的情况,若对并发操作不加控制,就会出现读取和存储不正确的数据,破坏数据库的一致性
195、Mysql各种锁
1、全局锁
全局锁是针对整个数据库的锁,最常用的全局锁是读锁和写锁
读锁(共享锁):阻止其他用户更新数据,但允许他们读取数据,简而言之就是我在读取数据的时候,不允许他们更新数据
写锁(排他锁):阻止其他用户读取和更新数据,就是我需要修改大量数据,并且不允许其他用户在这段时间受到任何干扰 全局锁——flush
tables with read lock,这将阻止其他线程进行更新操作,使用unlock tables释放锁定
2、表级锁(MyIsam)
是mysql最早采用的锁策略,表级锁的特点是开销小,加锁快,不会出现死锁,发生冲突的概率最高,并发度低2
表共享读锁:允许一个事务锁定的表进行读取操作,不允许其他事务对其进行写操作,但是可以进行读操作,读锁之间是不会相互阻塞
表独占写锁:表写锁,允许一个事务锁定的表进行读取和写入操作,其他任何事务都不能对该表进行任何操作, 使用场景:
读密集应用:适用于读取操作很多,写入操作很少的操作 写操作不频繁的场景:表级锁对所有的写操作并不高效,一个写锁会阻塞其他的所有锁,
全表的更新和删除,这种情况下,使用表级锁是最合理的 lock tables demo read / write
哪些命令会发生表级锁:alter table、drop table、lock tables
表级锁风险:性能下降,导致大量的请求阻塞;并发性能差,一个线程对表获得了写锁,其他线程人恶化读写操作都会被阻塞;死锁的可能性大,没有按照一定的顺序获得锁,可能会导致死锁;
3、行级锁(InnoDB)
对数据库表中的单独一行进行锁定,相比于表级锁和也页锁,行级锁的粒度更小,提供更好的并发性能和更少的锁冲突。占用更多的内存和CPU
共享锁(S锁):读锁,允许一个事务读物一行数据,当一行数据被狗共享锁锁定时候,其他事务可以读取这行数据,但不能修改
排他锁(X锁):写锁,允许一个事务读取和修改一行数据,当一行数据被排他锁锁定时候,其他事务不能读取也不能修改这样数据
行级锁只能在事务中有效,只有一个事务开始后并在事务提交或回滚之前,才能对数据进行锁定;如果在非事务中执行,innodb会在语句执行结束之后立即释放所有的锁
优点:高并发读写操作;单行操作,需要操作单行数据的sql,行级锁可以提供较好的并发性和性能;短期锁:行级锁可以防止长时间阻塞其他事务;实现并发控制;复杂的事务处理,方式在事务中处理数据被其他事务修改
哪些命令会发生行级锁:for update 添加行级排他锁;lock in share mode 添加一个共享锁;insert 添加一个排他锁;update 添加一个排他锁;delete 添加一个排他锁
风险:发生死锁的概率大;资源消耗,行级锁需要更多的内存来存储锁信息
补充:页级锁
是mysql中锁定粒度介于行级锁和表级锁中间的一种锁
补充:存储过程
存储过程可又称为过程化SQL语言,是在普通SQL语句的基础之上增加了编程语言的特点,把数据从操作语句和查询语句组织在过程化代码中
存储过程其实就是已预编译围为一个可执行过程的一个或者多个SQL语句,之后使用不需要再次分析和编译,通过调用和传递参数就可以完成
196、从模式上区分
1、乐观锁
假设在多个事务同时访问同一条数据时候,冲突发生的概率很低,因此在操作数据时候不会立即进行锁定,而是在提交数据更改时候检查是否有其他事务修改饿了这条数据,如果没有就提交更改,否则就回滚事务;
乐观锁没有内置的实现,只是一个概念,可以使用版本号字段,当一条记录被修改时候,就增加版本号。在更新记录时候,先检查版本号的时候和读取记录时的版本号一致,如果一致,执行更新;
假定不会发生并发冲突,只在提交操作时检查是否违反数据完整性,在修改数据的时候就把事务锁起来,通过version的方式进行锁定
2、悲观锁
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作,在查询完数据的时候就把事务锁起来,直到提交事务,
补充:MVCC
多版本并发控制:是为了在读取数据时候不加锁来提高读取效率和并发性的一种手段
mvcc解决的是线程安全的问题
Mvcc的实现:基于undolog、版本链、readview(undolog,事务中的每一次修改,innodb都会记录对应的undolog记录,与readlog用户数据的灾后重新提交不同,undolog主要用于数据修改的回滚)
补充:MySQL 中 count(*) 和 count(1) 有什么区别?哪个性能最好?
按照性能排序:count()=count(1)>count(主键)>count(字段)
count(name):统计name字段不为null的记录由多少
count(1):统计表中有多少条记录,包括null
count(主键):count(1)比count(主键)少一个步骤,不需要读取记录中的字段值,所以前者效率高
count():包括null,
补充:回表
当在使用mysql进行查询时候,如果查询条件的字段是建立索引的,那么mysql就会使用b+树进行查找,在某些情况下,mysql任然需要回到表中进行查找,叫做回表
补充:mysql删除重复数据,只保留一条怎么做?
补充:Mysql调优
1、缓存调优:mysql调整缓冲池大小,引入redis
2、服务器加内存条,升级SSD为固态硬盘,把磁盘IO分散在多个设备
3、定期清理垃圾,对于不再使用的表、数据、日志、缓存等,应该及时清理,避免占用过多的mysql资源,提高mysql性能
4、使用合适的引擎,MyISAM适用于读取频繁,写入较少的场景;InnoDB适合并发写入场景,
5、读写分离:读写分离有效提高查询性能,主从同步用到binlog和relaylog
6、数据迁移:停机迁移和不停机迁移(增量同步和全量同步)
补充:Mysql中的binlog、redo log、undo log
binlog:用于记录数据库执行的写入性操作,以二进制的形式保存在磁盘中,binlog是mysql的逻辑日志,使用任何mysql引擎的MySQL数据库都会记录binlog日志;binlog是以追加的方式写入的,通过max_binlog_siza参数来设置每个binlog文件的大小,当文件大小达到给定的值以后,会生成新的文件来保存日志
redo log:只是记录事务对数据页做了哪些修改,这样就能完美解决性能问题;包括redo log buffer和redo log
file,每执行一次DML,先将记录写入redo log buffer,后续某个时间点在一次性将多个操作记录写到redo log
file中,先写日志再写磁盘,就是mysql中的WAL技术;redo记录事务执行后的状态,用来恢复未写入的data
file的已成功事务更新的数据,防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo进行重做;在事务开始时候就产生redo
logUndo log:事务的四大特性——原子性,底层就是通过undo log实现的;保存了事务发生之前的数据的一个版本,可以用于回滚
在执行undo log的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的 Undo
log在事务开始之前,将当前的事务的版本生成undo log
补充:mysql中的慢查询
顾名思义就是执行很慢的查询,超过long_query_time参数设定的时间阈值,就被认为是慢的(10s),慢查询被记录在慢查询日志里
补充:MySQL中的调优手段
1、合理使用索引
创建合适的索引对于提高MySQL数据库的查询性能重要
选择适当的列:根据查询频率和过滤条件,选择经常用于where、join条件或排序操作的列作为索引
考虑列的选择性:选择高度不一致性的列作为索引列,性别提供较低的选择性,订单号提供较高的选择性
覆盖索引:覆盖索引是指在索引中包含了查询所需的所有列,避免回表操作,进一步提高查询的性能
避免不必要的索引:不必要的索引会增加数据库的维护成本,导致性能下降
2、优化查询语句
使用索引、编写有效的where语句、优化join操作(选择合适的join操作)、避免全表扫描(使用limit进行限制)、优化group by和order by、使用explain分析sql的执行计划
3、调整服务器硬件配置
较高CPU、扩大内存、高速磁盘、网络带宽(分布式数据库下)
4、定期维护数据库
数据完整性的保障、定期备份、空间管理和优化、清理垃圾数据、压缩和分区表
5、合理分配资源和连接管理
6、使用缓存技术
缓存层的作用:用来缓存用户定义的热点数据,用户直接从缓存中获取热点数据,降低数据库的读写压力
缓存层可以选择redis,他们所有的数据都存储到内存中,也可以将内存中的数据持久化到磁盘中
7、数据分区分表
数据分区是将一个大型数据集按照某个划分规则划分为较小的逻辑部分,并将这些部分分别存储在不同的物理空间上,每个分区可以根据需求进行独立管理的操作
数据分表是将一个大型的数据库表根据某个规则拆分成较小的逻辑表
可以提高查询性能、分布式存储和负载均衡、简化维护和管理
8、应用负载均衡技术(主从同步)
负载均衡可以将请求军训地分散到多台数据库服务器上,提高整体并发和整体吞吐量;实现高可用和容错性能力;提高访问相应速度
主要手段:
主从复制:通过创建一个主数据库,并同步复制数据到多个数据库,实现读写分离,主数据库处理写操作,从数据库处理读操作,
主主复制:将写操作负载平衡到多个主数据库的策略,每个数据库均可以接收写操作,并将数据库同步到其他数据库,实现负载均衡和冗余备份
9、优化数据库设计
三范式数据库设计,避免数据冗余,减少数据空间,减小维护数据完整性的麻烦
10、监控性能和调优
补充:SQL中执行的顺序
from>on>join>where>group by>agg_func>with>having>select>distinct>order by>limit
补充:distinct和group by的区别
distinct:
distinct只能放在查询字段的最前面,不能放在查询字段的中间或者后面
distinct对后面所有的字段均起作用,是对所有字段而言的
Group by:
一般与聚类函数使用,也可以单独使用
Group by也对后面所有的字段均起作用
查询的字段与group by后面分组的字段没有限制
补充:100万条的数据,B+树的层数计算
计算机磁盘存储数据的最小单元是扇区,一个扇区的大小是512字节;而文件系统最小单元是块,一个块的大小是4k,对于mysql中InnoDB最小存储单元是页,一个页的大小默认为16k(B+树的每个节点可以存16kb的数据)
B+数非叶子节点,保存索引字段和指针,叶子节点保存具体行记录
假设主键为bigint类型,InnoDB的bigint占用8个字节,指针占用6个字节,所以一个页能存放的指针个数为(161024)/(8+6)=1170
常规的互联网项目单条记录为1kb,那么一个页能存储的行记录为(161024)/1024=16,
一个2层高的b+树能存储的行记录为117016=18720
3层可存储11701170*16=2190W
补充:数据库三范式
第一范式:每个数据表中的每个字段都是原子的,即不能再分解为更小的数据单元
第二范式:满足第一范式基础,并要求数据库表中每个实例或行必须可以被唯一地区分——主键(每一行数据只能与其中的一列相关)
第三范式:任何非主属性不依赖其他非主属性,而是直接依赖于主键
补充:SQL约束有哪几种?
Not null:字段内容一定不能为空
unique:字段不能重复
Primary key:标识主键
Foreign key:表与表之间的连接 外键
check:用于控制字段的值范围
补充:drop、delete、truncate的区别
delete:根据条件进行删除,表结构还在,可回滚,删除速度过慢
truncate:删除表中所有数据,表结构还在,不可回滚,删除速度快,
drio:删除整个表,索引和权限也会被删除,不可回滚,删除速度最快
补充:分库分表
分表:单表的数据量太大会影响sql的执行性能,分表就是把一个表的数据放到多个表中,查询时候就查一个表,将每个表的数据量控制在可控范围内
分库:一个库的并发最多撑到2000,一个健康的单库并发至最好保持在每秒1000左右,可以将一个库的数据拆分到多个库中,访问一个库就好了
主要工具:mycat
补充:数据库垂直拆分和水平拆分
水平拆分:就是把一个表的数据给弄到多个库的多个表中,但是每个库的表结构都一样,只不过每个库表存放的数据是不同的,所有库表加起来就是全部的数据
垂直拆分:把一个有很多字段的表给拆分成多个表,或者是多个库上去,每个库的表结构都不一样,每个库表都包含部分字段,将访问频率高的字段放到一个表里去,将访问频率很低的字段放到另外一个表里去
分库分表的两种方式:一种是range,每个库一段连续的数据,按照时间范围来计算,容易产生热点问题;另一种是按照某个字段进行hash均匀分散
补充:数据库主从同步和读写分离
- 通过增加服务器来提高数据库的性能,在主服务器上执行写入和更新,在从服务器上向外提供读功能
- 提高数据安全,可以在从服务器上备份而不破坏主服务器上相应的数据
- 主服务器上生成实时的数据,在从服务器上分析这些数据,提供主服务器性能
- 数据备份,备份及时而且数据安全