目录
- 1. 什么是事务,事务的特性
- 2. 事务存在的问题(丢失修改,脏读,不可重复读,幻读是什么?)
- 3. 数据库事务的四种隔离级别
- 4. 三级封锁协议
- 5. 两段锁协议
- 6. 数据库的三大范式
- 7. Mysql锁了解吗
- 8. 读写锁和意向锁
- 9. 数据库行锁、表锁(封锁粒度)
- 10. 什么时候使用表锁?
- 11. 在InnoDB下 ,使用表锁要注意什么?
- 12. InnoDB存储引擎的3种行锁算法
- 13. MySQL可重复读下如何解决幻读?Innodb如何避免幻读的?
- 14. 索引是什么?优点和缺点
- 15. Mysql索引类型??????
- 16. MySQL数据库的索引,底层实现为什么用B+树?
- 17. 索引是怎么提高效率的?
- 18. hash索引么跟B+树索引的区别,哪个性能好
- 19. InnoDB存储引擎特点
- 20. MyISAM存储引擎特点
- 21. MySQL中 MyISAM 和 InnoDB 的区别有哪些?如何选择?
- 22. MVCC多版本并发控制
- 23. 什么是B(B-)树?
- 24. 什么是B+树?
- 25. B+树和B树的区别?为什么用B+树,而不用B树
- 26. 为什么用B+树,而不红黑树?
- 27. 聚集索引和非聚集索引(辅助索引)
- 28. 聚集索引特点
- 29. 非聚集索引特点
- 30. 主键索引 (聚集索引) 和普通索引 (辅助索引) 的区别
- 31. 为什么不能使用UUID作为主键来建立索引
- 32. MySQL执行一个查询的过程?
- 33. 最左前缀原则?
- 34. 数据库中悲观锁和乐观锁的实现
- 35. sql语句中where和having 的区别
- 36. 数据库连表查询都有哪些?
- 37. 介绍下mysql的回表和覆盖索引?
- 38. 哪些场景可以利用索引覆盖来优化SQL
- 39. 索引失效的原因?索引无法使用的原因
- 40. 讲一讲数据库的慢查询?
- 41. 数据库数据量非常大怎么进行设计优化。
- 42. 在数据库中查询语句速度很慢,如何优化?
- 43. MySQL优化方式有哪些?
- 44. 为什么要建索引?什么样的字段需要建索引,建索引的时候一般考虑什么?
- 45. 怎么解决分库分表?
- 46. InnoDB是如何实现事务的?????
- 47. 数据库调优了解么
- 48. MySQL执行计划
- 49. 为什么推荐自增id,有什么优点
- 50. 索引最左匹配
- 51. mysql建立索引的原则
- 52. 什么条件不能命中索引
- 53. sql很慢,怎么排查?
- 54. 数据库的自增主键的优缺点?
- 55. 数据库和缓存的一致性问题
- 56. 数据库分库后,如何生成全局唯一的ID
- 57. Mysql怎么产生死锁
- 58. mysql如何确定sql走哪个索引,mysql sql语句执行时是否使用索引检查方法
- 59. 什么时候用/不用索引,索引的类别
- 60. MySQL索引优化 MySQL索引如何选择
- 61. 覆盖索引?
- 62. 如何高效地使用索引?
1. 什么是事务,事务的特性
- 事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。
- 原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。
① Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
② Consistency(一致性):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
③ Isolation(隔离性):一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
④ Durability(持久性):指一个事务一旦提交,所做的修改就会永久性的保存在数据库中。
只有满足一致性,事务的执行结果才是正确的。
在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。
在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
事务满足持久化是为了能应对系统崩溃的情况。
2. 事务存在的问题(丢失修改,脏读,不可重复读,幻读是什么?)
在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性问题。
丢失修改:T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。
脏读:T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。在一个事务中读取到另一个事务没有提交的数据
不可重复读:T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。在一个事务中,两次查询的结果不一致。(针对的update操作)
幻读:T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。在一个事务中,两次查询的结果不一致(针对的insert操作)
3. 数据库事务的四种隔离级别
什么是事务?
事务是逻辑上的一组操作,要么都执行,要么都不执行。
- 读未提交 READ UNCOMMITED
定义:事务中的修改,即使没有提交,对其它事务也是可见的。就是一个事务可以读取另一个未提交事务的数据。
分析:可能会造成脏读
解决:使用读已提交 READ COMMITED的隔离级别 - 读已提交 READ COMMITED
定义:一个事务所做的修改在提交之前对其它事务是不可见的。就是一个事务要等另一个事务提交后才能读取数据。
分析:可能会发生不可重复读
解决:使用可重复读REPEATABLE READ的隔离级别 - 可重复读 REPEATABLE READ
定义:保证在同一个事务中多次读取同一数据的结果是一样的。
分析:可能会发生幻读
解决:使用序列化SERIALIZABLE的隔离级别 - 序列化 SERIALIZABLE
定义:Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,多个事务互不干扰,不会出现并发一致性问题。
分析:可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。 - 大多数数据库默认的事务隔离级别是读提交Read committed,比如Sql Server , Oracle。Mysql的默认InnoDB存储引擎的默认隔离级别是Repeatable read。
4. 三级封锁协议
运用X锁和S锁对数据对象进行加锁时约定的规则就是封锁协议。
目的是在不同程序上保证数据的一致性。
- 一级封锁协议:事务 T 要修改数据 A 时必须加 X 锁,直到 T 结束才释放锁。
可以解决丢失修改问题,因为不能同时有两个事务对同一个数据进行修改,那么事务的修改就不会被覆盖。 - 二级封锁协议:在一级的基础上,要求读取数据 A 时必须加 S 锁,读取完马上释放 S 锁。
可以解决读脏数据问题,因为如果一个事务在对数据 A 进行修改,根据 1 级封锁协议,会加 X 锁,那么就不能再加 S 锁了,也就是不会读入数据。 - 三级封锁协议:在二级的基础上,要求读取数据 A 时必须加 S 锁,直到事务结束了才能释放 S 锁。
可以解决不可重复读的问题,因为一个事务读 数据A 时,在事务结束前,其它事务不能对 A 加 X 锁,从而避免了在一个事务中多次读取数据读到不一样的值。
5. 两段锁协议
事务的加锁和解锁严格分为两个阶段,第一阶段加锁,第二阶段解锁。
一个事务中一旦开始释放锁,就不能再申请新锁了。
目的 :”引入2PL是为了保证事务的隔离性,保证并发调度的准确性,多个事务在并发的情况下依然是串行的。
可串行化调度是指,通过并发控制,使得并发执行的事务结果与某个串行执行的事务结果相同。串行执行的事务互不干扰,不会出现并发一致性问题。
事务遵循两段锁协议是保证可串行化调度的充分条件。例如以下操作满足两段锁协议,它是可串行化调度。
lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)
但不是必要条件,例如以下操作不满足两段锁协议,但它还是可串行化调度。
lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)
6. 数据库的三大范式
- 第一范式(1NF):每一列属性都是不可再分的属性值,确保每一列的原子性;两列的属性相近或相似或一样,尽量合并属性一样的列,确保不产生冗余数据。
- 第二范式(2NF):数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关。
- 第三范式(3NF):属性不依赖于其它非主属性,属性直接依赖于主键。
7. Mysql锁了解吗
按照锁粒度分类:表锁和行锁
按照读写分类:表级锁和行级锁可以进一步划分为共享锁和排它锁
还有两个表级锁:意向共享锁和意向排它锁
SnailClimb在csdn
总结的很好很好。。
8. 读写锁和意向锁
互斥锁(Exclusive),简写为 X 锁,又称写锁。
共享锁(Shared),简写为 S 锁,又称读锁。
意向共享锁(IS)和意向排他锁(IX):如果事务想要给表中几行数据加上行级共享锁,那么需要先在表级别加上意向共享锁(IS);如果事务想要给表中几行数据加上行级排他锁,那么需要先在表级别加上意向排他锁(IX)(注意:如果是想要加表级S锁或X锁,不需要先加意向锁。)
以下是表级X和S锁和意向锁的兼容性
意向锁的作用:
当向一个表添加表级X锁或者S锁时,如果没有意向锁的话,则需要遍历所有整个表判断是否有不兼容的行锁的存在,以免发生冲突。
如果有了意向锁,只需要判断该意向锁与即将添加的表级锁是否兼容即可,因为意向锁的存在代表了有行级锁的存在或者即将有行级锁的存在,因而无需遍历整个表,即可获取结果。
9. 数据库行锁、表锁(封锁粒度)
MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
- 表锁是mysql中开销最小的策略,它会锁定整张表,用户在对表进行写操作前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。
- 特点:锁粒度大,系统开销小,发生锁冲突的概率最高,并发度最低。加锁快,不会出现死锁。表锁是由MySQL Server负责的。
- 行锁可以最大程度的支持并发处理,同时也带来了最大的锁开销,InnoDB存储引擎实现了两种行锁:共享锁和排他锁。行锁在存储引擎层实现。
- 特点: 锁粒度小,系统开销大,发生锁冲突的概率小,并发度最高。加锁慢,会出现死锁。行锁是由InnoDB存储引擎管理的。
10. 什么时候使用表锁?
- 事务更新大表中的大部分数据直接使用表级锁效率更高。如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
- 事务比较复杂,使用行级索很可能引起死锁导致回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。
11. 在InnoDB下 ,使用表锁要注意什么?
- 使用LOCK TALBES虽然可以给InnoDB加表级锁,但必须说明的是,表锁不是由InnoDB存储引擎层管理的,而是由其上一层MySQL Server负责的,仅当autocommit=0、innodb_table_lock=1(默认设置)时,InnoDB层才能知道MySQL加的表锁,MySQL Server才能感知InnoDB加的行锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁;否则,InnoDB将无法自动检测并处理这种死锁。
- 在用LOCAK TABLES对InnoDB锁时要注意,要将AUTOCOMMIT设为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCAK TABLES释放表锁,因为UNLOCK TABLES会隐含地提交事务;COMMIT或ROLLBACK产不能释放用LOCAK TABLES加的表级锁,必须用UNLOCK TABLES释放表锁。
12. InnoDB存储引擎的3种行锁算法
Record Lock:锁住一行记录
Gap Lock:间隙锁指的是锁定一个范围内的索引记录,开区间,不包括双端端点,对于键值在条件范围内但不存在的记录,叫做间隙,间隙锁也会对这个间隙加锁。
作用:让其他事务无法在间隙中新增数据,阻止了多个事务记录插入到同一范围内,从而防止了幻读。
Next-Key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身,解决了幻读。
- 在可重复读隔离级别下,采用了Next-Key Locking机制避免幻读问题。
- 在读已提交隔离级别下,仅采用Record Lock。
- Next-Key Lock降级为Record Lock仅在查询的列是唯一索引的情况下。
13. MySQL可重复读下如何解决幻读?Innodb如何避免幻读的?
- 在快照读读情况下,mysql通过mvcc来避免幻读。读取的是 Undo 中旧版本的数据,这时就算另一个事务插入一个数据,并立马提交,新插入数据的版本号会比读取事务的版本号高,读取事务时所读的数据还是没变,解决了幻读。
- 在当前读读情况下,mysql通过next-key来避免幻。Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身,让其他事务无法在间隙中新增数据,阻止了多个事务记录插入到同一范围内,从而解决了幻读。
14. 索引是什么?优点和缺点
索引是存储引擎用于提高数据查询效率的一种数据结构。Mysql中的索引是在存储引擎层实现的,在MySQL中使用较多的索引有 Hash 索引和 B+树索引。InnoDB 采用了 B+ 树索引。先通过 B+ 树找到数据所在的页,然后将页读到内存,在内存中找到要查找的数据。(Mysql 将索引存放在磁盘而不是内存中,减少了内存消耗)
索引优点: ①减少了服务器需要扫描的数据量;②帮助服务器避免排序;③将随机IO变为顺序IO,索引可以加快数据库访问的效率。
索引的缺点:创建索引和维护索引会耗费时间;索引会占用物理空间;当对表进行增删改时,索引也需要动态维护,这样会降低数据的维护速度。一般在频繁使用或需要排序的字段上建立索引,而对于很少查询或重复值较多的列,不适合建立索引。
不宜建立索引的场景:对于非常小的表,不宜建立索引,一般采用简单的全表扫描即可。对于特大型的表,建立和使用索引的代价会随之增大。对于查询中很少涉及的列或者重复值较多的列,也不宜建立索引。
适合建立索引的场景:对于中到大型的表,索引会非常有效。一般可以在频繁使用或需要排序的字段上建立索引。
15. Mysql索引类型??????
普通索引、唯一索引、主键索引、组合索引、全文索引。
16. MySQL数据库的索引,底层实现为什么用B+树?
- 每次读取节点,就会进行一次磁盘的 IO 操作,所以树越高,IO次数也就越多。为了尽量减少耗时的IO次数,需要降低树的高度,采取的办法就是将索引构建成 m 叉树。由于操作系统是按磁盘页来读取的,而B+树的中间节点不存放数据,使得单一节点可以存储更多的元素,所以同样大小的磁盘页可以容纳更多的节点元素,这就意味着数据量相同的情况下,B+树会更矮胖一点,所以IO次数也更少。
- B+树的查询必须查到叶子节点,而B树只要找到匹配元素即可,所以B树没有B+树的查询性能稳定。
- B树只能依靠繁琐的中序遍历来做范围查询,而B+树所有叶子节点形成有序链表,很方便范围查询。
17. 索引是怎么提高效率的?
数据索引的存储是有序的,所以通过索引查询一个数据效率很高。
18. hash索引么跟B+树索引的区别,哪个性能好
范围区别:
- hash索引因为底层是哈希表,速度很快除非有很多哈希冲突。数据存储在哈希表中是无序的,如果要范围查找就需要全表扫描,所以他不适合范围查找。哈希索引数据不是按照索引值顺序存储的,无法用于排序。不支持部分索引列匹配查找(因为哈希索引是按照全列名计算hash值的),只适合等值扫描。
- B+ tree树索引,底层是多路查询平衡树,节点是天然有序的(左节点小于服节点,右节点大于父节点),所以对于范围查找的时候不需要做全表扫描;适合等值查找,范围查找,最左前缀查找。
19. InnoDB存储引擎特点
- InnoDB是Mysql默认的事务型存储引擎,支持事务的ACID特性。InnoDB每一条SQL语句都默认封装成事务,自动提交。最好使用BEGIN显式地开启事务,使用COMMIT提交事务。
- 支持行锁和表锁,默认是行锁。可以只对一行数据加锁,并发性能好。
- 采用MVCC多版本并发控制的方式来读取正在执行写操作的行数据,不需要等待行上X锁的释放,可以避免读写操作的相互阻塞,提高了并发性能。(具体原理是读取该行之前版本的数据,叫做快照数据,是通过undo段实现的。读取快照数据不需要上锁,极大地提高了数据库的并发性。InnoDB默认设置下默认的读取方式。)(并且实现了四种隔离级别,默认级别是可重复读,而且通过间隙锁策略防止幻读的出现,间隙锁不仅锁定查询涉及的行,还会锁定索引中的间隙,来防止幻影行的插入。)
- InnoDB表是基于聚集索引建立的,数据按照主键的逻辑顺序存储,一般用自增列来做主键,这样每次插入的新数据会顺序添加到当前索引节点的后续位置,形成一个紧凑的索引结构,近似顺序填满的,也不需要移动数据,所以不会增加很多开销在维护索引上。
- 支持B+树索引和自适应Hash索引,InnoDB 5.6后也支持了全文索引。自适应Hash索引的策略是当InnoDB注意到某些索引值被使用的非常频繁时,它会在内存中基于B+树索引之上再创建一个哈希索引。这样就可以让B+树索引也具有哈希索引的一些优点。
- 支持外键,外键用于和别的表进行关联来保持数据的一致性,比如A表中的一个字段,是B表的主键,那这个字段就是A表的外键。
- (不用说)InnoDB 还有一些关键特性,比如加速插入操作的插入缓冲区、加速读操作的自适应哈希索引、异步IO(AIO)
20. MyISAM存储引擎特点
- MyISAM不支持事务
- 不支持行级锁,采用的表锁设计。读操作使用共享锁,写操作使用排它锁,读写操作会相互阻塞,因此MyISAM存储引擎不适合在高并发的读写混合场景中使用。
- 支持B+树索引,全文索引。InnoDB 5.6才开始支持全文索引。
- 不支持外键
- 崩溃后无法安全恢复。
- 以堆表的方式存储数据,所以存储的数据是没有顺序的,索引的叶子节点直接指向数据的物理地址,避免了二次查找,MyISAM的查询性能会好于InnoDB的查询性能。
- MyISAM中,数据和索引是分别存储的,数据存储在MYD文件中,索引存储在MYI文件中。
- 使用场景: 读操作远远大于写操作的场景;不需要使用事务的场景;
21. MySQL中 MyISAM 和 InnoDB 的区别有哪些?如何选择?
- InnoDB是MySQL默认的存储引擎,支持事务,MyISAM不支持事务,InnoDB每一条SQL语句都默认封装成事务,自动提交,这样会影响速度,所以最好使用BEGIN显式地开启事务,使用COMMIT提交事务。
- 支持行锁和表锁,默认是行锁。可以只对一行数据加锁,并发性能好。而MyISAM只支持表锁。
- InnoDB支持外键,外键用于和别的表进行关联来保持数据的一致性,比如A表中的一个字段,是B表的主键,那这个字段就是A表的外键。MyISAM不支持外键。
- 支持自适应Hash索引,当InnoDB注意到某些索引值被使用的非常频繁时,它会在内存中基于B+树索引之上再创建一个哈希索引,这样就让B+树索引也具有哈希索引的一些优点了,比如O(1)时间复杂度的快速哈希查找。MyISAM没有这种机制。
- InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。
- InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
- 如何选择:
1、是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;
2、如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读写也挺频繁,请使用InnoDB;
3、系统奔溃后,MyISAM恢复起来更困难,能否接受;???为啥
22. MVCC多版本并发控制
多版本并发控制是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。而未提交读隔离级别总是读取最新的数据行,要求很低,无需使用 MVCC。可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。
MVCC可以看做是行级锁的一个变种, 通过保存数据在某个时间点的快照来实现,它尽量避免了加锁操作, 因此开销教低,实现了非阻塞的读操作,写操作也只锁定必要的行,应对高并发事务,MVCC比单纯的加锁更高效。InnoDB的MVCC默认隔离级别是可重复读,它是通过在每行记录后面保存两个隐藏的列来实现的。这两个列一个保存行的创建时间,一个保存行的删除时间,这里的时间指的是系统版本号,每当修改数据时,版本号加一。读操作通过 Undo 读取的是数据之前的历史版本,所以不会阻塞写操作,提高了数据库并发读写的性能。同时还可以解决幻读,因为读取事务时,读取的是 Undo 中旧版本的数据,这时就算另一个事务插入一个数据,并立马提交,新插入数据的版本号会比读取事务的版本号高,读取事务时所读的数据还是没变,解决了幻读。
23. 什么是B(B-)树?
- 根节点至少有两个子节点。
- 每个中间节点都包含 k - 1 个元素和 k 个孩子节点,元素中保存数据。其中 m/2 <= k <= m ,如果除不尽就向上取整。
- 所有叶子节点都位于同一层。
- 每个节点中的元素从小到大排列,节点中 k - 1 个元素正好是 k 个孩子所包含元素的值域分划。
B(B-)树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
24. 什么是B+树?
- 每个中间节点都包含 k 个元素和 k 个子节点,其中 m/2 <= k <= m ,如果除不尽就向上取整。
- 中间节点中的元素不存储数据,只存储索引,所有数据都保存在叶子节点中,叶子节点都位于同一层,而且叶子节点本身按照关键字的大小通过链表串联在一起。B 树中的叶子节点并不需要链表来串联。
- 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)的元素。
- B+树的查找与B树不同,当索引部分某个结点的关键字与所查的关键字相等时,并不停止查找,应继续沿着这个关键字左边的指针向下,一直查到该关键字所在的叶子结点为止。
在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
25. B+树和B树的区别?为什么用B+树,而不用B树
Mysql用磁盘IO次数衡量查询效率,一般来说索引非常大,为了减少内存的占用,索引也会被存储在磁盘上。B类树的特点就是每层节点数目非常多,层数很少,目的就是为了减少磁盘IO次数。
- B+树只有叶节点存放数据,其它节点并不存储数据,节点小,磁盘IO次数就少。而B树是每个索引节点都会有Data域,这增大了节点大小,增加了磁盘IO次数。(磁盘IO一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO次数增多)B+树的层高会小于B树,B树平均的IO次数会远大于 B+树
- B+树叶子节点是用双向链表连接起来的,遍历叶子节点就能进行范围查询。 B树范围查询只能中序遍历。
- B树索引节点没有数据,比较小。B树索引可以完全加载至内存中,占用内存少。
26. 为什么用B+树,而不红黑树?
AVL 树(平衡二叉树)和红黑树(二叉查找树)基本都是存储在内存中才会使用的数据结构。因为红黑树往树的深度过大会造成磁盘IO读写过于频繁,进而导致效率低下。所以要使用高度较小的树的结构。B类树可以有多个子树,可以降低树的高度。
27. 聚集索引和非聚集索引(辅助索引)
- 聚簇索引:按照每张表的主键构造B+树,非叶子节点用来存放索引,叶子节点(数据页)用来存放行记录数据,按照主键的顺序排序,每个数据页都通过一个双向链表来连接,因此,聚集索引能够在B+树索引的叶子节点上直接找到数据,而且对主键的排序查找和范围查找速度非常快。(通过主键聚集数据,同一个页的数据行在物理上是连续的,不同的页之间用链表串接起来。)如果没有定义主键,InnoDB会选择一个唯一的非空索引替代。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚集索引。
- 非聚簇索引(辅助索引):叶子节点存放的是键值对,还包含一个指针,指向聚集索引的主键。当通过非聚集索引来查找数据时,首先遍历非聚集索引,找到对应的叶子节点,并获得对应聚集索引的主键,然后通过这个聚集索引找到对应的行,所以它需要两次索引查找。
将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因。
区别:
- 聚集索引将数据存储与索引放到了一块,找到索引也就找到了数据,速度很快;非聚集索引通过索引查找主键,然后还要再通过聚集索引才能找到数据,速度较慢。
- 聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
- 聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续。
28. 聚集索引特点
缺点:
- 聚集索引提高了IO密集型应用的性能,但是如果数据全部存在内存中,聚集索引就没什么优势了。
- 建立索引的顺序依赖于数据的顺序,如果数据不是按照主键顺序排列的,建立索引会比较慢。
- 更新聚集索引的代价比较高,因为会强制将数据行记录移动到新的位置。可能还会有页分裂问题:如果要插入的位置所在的页已满,存储引擎会将该页分成两个页面来容纳该行,导致占用更多的磁盘空间。
优点:
29. 非聚集索引特点
缺点:
- 非聚集索引查找数据需要2次索引查找,因为非聚集索引的叶子节点保存的不是指向行的位置的指针,而是行的主键值。所以通过非聚集索引查找行,首先找到的是行的主键值,然后根据这个主键值去聚集索引中查找对应的行。
优点:
- 非聚集索引的叶子节点存储的不是指向行的位置的指针,而是主键值,这样减少了当出现行移动或者数据分页时非聚集索引的维护工作。移动行时不需要更新非聚集索引的叶子节点的指针。
30. 主键索引 (聚集索引) 和普通索引 (辅助索引) 的区别
- 主键索引:
主键索引不可以为空
主键索引可以做外键
一张表中只能有一个主键索引 - 普通索引:
用来加速数据访问速度而建立的索引。多建立在经常出现在查询条件的字段和经常用于排序的字段。
被索引的数据列允许包含重复的值主键索引不可以为空
主键索引可以做外键
一张表中只能有一个主键索引
31. 为什么不能使用UUID作为主键来建立索引
如果使用UUID作为主键,由于UUID是无序的,所以所以建立索引会花费很长时间;由于主键字段很长,所以索引占用空间也比较大;另外页分裂和碎片会比较多。
因为插入行时,每一行的主键值不一定比之前插入的大,所以不一定是把新行插入到索引的最后,而是需要为新的行寻找合适的位置,通常是已有数据的中间位置。可能会有频繁地页分裂操作,数据会碎片化。
32. MySQL执行一个查询的过程?
- 客户端发送一条查询给服务器。
- 服务器先查询缓存,如果命中了缓存,则立刻返回缓存中的结果。
- 如果缓存中没有找到,则进行SQL解析、预处理,再由优化器生成对应的执行计划。
- MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询。
- 最后将结果返回给客户端。
33. 最左前缀原则?
MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引。如User表的name和city加联合索引就是(name,city),而最左前缀原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。如果不是按照索引的最左列开始查找,则无法使用索引。如下:
select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
select * from user where city=xx ; // 无法命中索引
这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如 city= xx and name =xx,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。
由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDER BY子句也遵循此规则。
34. 数据库中悲观锁和乐观锁的实现
- 悲观锁,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住。实现:依靠数据库的锁机制实现
- 乐观锁,认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让用户返回错误的信息。
实现:大多数基于数据版本(Version)记录机制实现
具体可通过给表加一个版本号或时间戳字段实现,当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断当前版本信息与第一次取出来的版本值大小,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据,拒绝更新,让用户重新操作。
35. sql语句中where和having 的区别
- where是一个约束声明,在数据分组前进行过滤,过滤的是行。where子句出现在group by 之前,而且不能包含聚集函数,因为where执行顺序先于聚集函数。
- having是一个过滤声明,在数据分组后进行过滤,过滤的是分组。having子句出现在group by 之后,而且可以包含聚集函数。
- where和having 可以同时存在一个SQL语句中。
36. 数据库连表查询都有哪些?
内连接:只有两个元素表相匹配的才能在结果集中显示。
外连接: 左外连接:左边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
右外连接:右边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
全外连接:返回左表和右表中的所有行。当某行在另一表中没有匹配行,则另一表中的列返回空值
交叉连接: 笛卡尔效应,显示的结果是链接表数的乘积。
37. 介绍下mysql的回表和覆盖索引?
- InnoDB有两大类索引,一类是聚簇索引,一类是普通索引,聚簇索引只有一个,假设现在有一张表t,有id,name,address等字段,select * from t where name=‘lisi’,聚集索引是根据id建立的,由于普通索引无法定位到行记录,在查询过程中是需要先扫描普通索引定位到主键,再通过聚集索引定位到具体行记录,这就是回表查询,即先定位主键值,再根据主键值定位行记录。由于要扫描2次索引,性能比较低。
- 索引覆盖是一种避免回表查询的优化策略,具体的做法是将所有要查询的数据所为索引列建立普通索引,这样就可以直接返回索引中的数据,不需要再通过聚集索引去定位行记录,避免了回表。
- 如果一个索引覆盖(包含)了所有需要查询的字段的值,就称这个索引为覆盖索引。因为索引中已经包含了要查询的字段的值,因此查询的时候直接返回索引中的字段值就可以了,不需要再到表中查询,避免了对主键索引的二次查询,也就提高了查询的效率。
- 另外,当发起一个被索引覆盖的查询(索引覆盖查询)时,在explain(执行计划)的Extra列可以看到【Using Index】的信息。
- 不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引列的值,而哈希索引和全文索引都不存索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引。
38. 哪些场景可以利用索引覆盖来优化SQL
- 全表count查询优化,user(PK id, name, sex);
select count(name) from user;
不能利用索引覆盖。
添加索引:
alter table user add key(name);
就能够利用索引覆盖提效。
- 列查询回表优化,
select id,name,sex ... where name='shenjian';
将单列索引(name)升级为联合索引(name, sex),即可避免回表。
- 分页查询
select id,name,sex ... order by name limit 500,100;
将单列索引(name)升级为联合索引(name, sex),即可避免回表。
参考博客:https://www.cnblogs.com/myseries/p/11265849.html
39. 索引失效的原因?索引无法使用的原因
1、在索引列上使用函数或者运算,索引就无法使用了。需要建立函数索引就可以解决了。
2、新建的表还没来得及生成统计信息,分析一下就好了
3、基于cost的成本分析,访问的表过小,使用全表扫描的消耗小于使用索引。
4、使用<>、not in 、not exist,对于这三种情况大多数情况下认为结果集很大,一般大于5%-15%就不走索引而走FTS。
5、单独的>、<。
6、like “%_” 百分号在前。
7、单独引用复合索引里非第一位置的索引列。
8、字符型字段为数字时在where条件里不添加引号。
9、当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。
10、索引失效,可以考虑重建索引,rebuild online。
11、B-tree索引 is null不会走,is not null会走,位图索引 is null,is not null 都会走、联合索引 is not null 只要在建立的索引列(不分先后)都会走。
40. 讲一讲数据库的慢查询?
MySQL中的日志包括:错误日志、二进制日志、通用查询日志、慢查询日志等等。
MySQL慢查询日志记录下所有执行超过long_query_time时间的SQL语句,帮你找到执行慢的SQL,方便我们对这些SQL进行优化。
41. 数据库数据量非常大怎么进行设计优化。
- 表的设计具体注意的问题
在建表选择数据类型时选择更小的 (占用更少的磁盘) 、更简单的 (如能选择整形就不选字符串) 、避免使用NULL(为什么呢)。为了提高查找效率,可以增加冗余列。
- 数据行的长度不要超过8020字节,如果超过这个长度的话在物理页中这条数据会占用两行从而造成存储碎片,降低查询效率。
- 能够用数字类型的字段尽量选择数字类型而不用字符串类型的(电话号码),这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
- 对于不可变字符类型char和可变字符类型varchar 都是8000字节,char查询快,但是耗存储空间,varchar查询相对慢一些但是节省存储空间。在设计字段的时候可以灵活选择,例如用户名、密码等长度变化不大的字段可以选择CHAR,对于评论等长度变化大的字段可以选择VARCHAR。
- 字段的长度在最大限度的满足可能的需要的前提下,应该尽可能的设得短一些,这样可以提高查询的效率,而且在建立索引的时候也可以减少资源的消耗。
- 查询的优化
- 保证在实现功能的基础上,尽量减少对数据库的访问次数;
- 通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担;
- 能够分开的操作尽量分开处理,提高每次的响应速度;
- 在数据窗口使用SQL时,尽量把使用的索引放在选择的首列;
- 不要过多地使用通配符如:SELECT * FROM T1 语句,要用到几列就选择几列
- 加缓存,memcached,redis;
- 主从复制或主主复制,读写分离;
42. 在数据库中查询语句速度很慢,如何优化?
- 建索引。
- 减少表之间的关联。
- 优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据 量大的表排在前面。
- 简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据。
- 尽量用PreparedStatement来查询,不要用Statement。
43. MySQL优化方式有哪些?
- 开启查询缓存,优化查询;
- explain你的select查询,这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你,你的索引主键被如何利用的,你的数据表是如何被搜索和排序的;
- 当只要一行数据时使用 limit 1,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据;
- 为搜索字段建索引;
- 使用 ENUM 而不是 VARCHAR,如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是VARCHAR;
- Prepared Statements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用 prepared statements 获得很多好处,无论是性能问题还是安全问题。Prepared Statements 可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击;
- 垂直分表;
- 选择正确的存储引擎。
- 语句优化,注意索引失效。
- 分库分表
44. 为什么要建索引?什么样的字段需要建索引,建索引的时候一般考虑什么?
45. 怎么解决分库分表?
46. InnoDB是如何实现事务的????
- 实现事务的原子性:通过回滚日志 Undo Log 来记录数据修改前的状态,如果事务执行失败,就通过Undo Log中的记录对数据进行回滚。
- 实现事务的一致性:通过重做日志 Redo Log 来记录数据修改后的状态,如果判断出数据异常,就需要进行回滚。
- 实现事务的隔离性:通过对事务操作的数据进行加锁来实现,有共享锁和排他锁,保证了事务提交前对其他事务都不可见。
- 实现事务的持久性:如果数据库崩溃,就通过配合使用 Undo Log 和 Redo Log 对事务进行恢复,以此来保证事务的持久性。
47. 数据库调优了解么
48. MySQL执行计划
49. 为什么推荐自增id,有什么优点
50. 索引最左匹配
51. mysql建立索引的原则
52. 什么条件不能命中索引
53. sql很慢,怎么排查?
54. 数据库的自增主键的优缺点?
55. 数据库和缓存的一致性问题
56. 数据库分库后,如何生成全局唯一的ID
57. Mysql怎么产生死锁
58. mysql如何确定sql走哪个索引,mysql sql语句执行时是否使用索引检查方法
59. 什么时候用/不用索引,索引的类别
60. MySQL索引优化 MySQL索引如何选择
61. 覆盖索引?
62. 如何高效地使用索引?
- 索引列不能是表达式的一部分,也不能是函数的参数。
- 使用前缀索引。如果要索引很长的字符列,会让索引变得很大并且慢,这时可以以列开始的部分字符索引,这样可以大大节约索引空间,从而提高索引效率。