数据库相关知识点

  • 二级索引

    • 聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据。具备惟一性,聚簇索引默认是主键,若是表中没有定义主键,InnoDB 会选择一个惟一的非空索引代替。若是没有这样的索引,InnoDB 会隐式定义一个主键来做为聚簇索引。java

    • 非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam经过key_buffer把索引先缓存到内存中,经过索引访问数据,在内存中直接搜索索引,而后经过索引找到磁盘相应数据,这也就是为何索引不在key buffer命中时,速度慢的缘由。  redis

    • innodb中,在聚簇索引之上建立的索引称之为辅助索引,辅助索引访问数据老是须要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、惟一索引,辅助索引叶子节点存储的再也不是行的物理位置,而是主键值算法

    • 为何主键一般建议使用自增id?数据库

      聚簇索引的数据的物理存放顺序与索引顺序是一致的,即只要索引是相邻的,那么对应的数据必定也是相邻地存放在磁盘上。若是不是自增id,那么会不断地调整数据的物理地址、分页,而自增id只须要一页一页地写,索引结构相对紧凑,磁盘碎片少,效率高。segmentfault

      MyISAM的主索引为非聚簇索引,所以其物理地址必然凌乱,拿到这些物理地址,按照合适的算法进行I/O读取,而聚簇索引只须要一次I/O缓存

      可是涉及大数据量的排序、全表扫描、count之类的操做的话,仍是MyISAM占优点些,由于索引所占空间小,这些操做是须要在内存中完成的安全

    • 适用场景服务器

      • 聚簇索引适用在排序的场合数据结构

      • 取出必定范围数据的适合,使用聚簇索引多线程

      • 维护索引很是昂贵,特别是插入新行或者主键被更新致使到分页时

      • 当使用UUID(随机ID)做为主键,使数据存储稀疏,这就会出现聚簇索引有可能比全表扫描更慢

  • InnoDB索引底层数据结构

    • InnoDB是默认的表存储引擎,其特色是行锁设计、支持MVCC、支持外键、提供一致性非锁定读、同时被设计用来最有效的利用以及使用内存和CPU。

    • 体系结构:

    • 后台线程主要负责刷新内存池中的数据、将已修改的数据刷新到磁盘等。

      使用缓冲池技术来提升数据库的总体性能,缓冲池就是一块内存区域,在数据库中进行取页的操做。缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲、自适应哈希索引、innoDB的锁信息、数据字典信息等。

    • 关键特性:插入缓冲(insert buffer,为了提升写性能)、两次写(提升可靠性)、自适应哈希索引(经过缓冲池的B+树页构造而来,创建速度很是快,不须要对整张表构建哈希索引。innoDB存储引擎会自动根据访问的频率和模式来自动地为某些热点页创建哈希索引)、异步IO(AIO,提升磁盘操做性能,用户能够在发出一个IO请求后当即再发出另一个IO请求,当所有IO请求发送完毕后,等待全部IO操做完成。相对的是Sync IO,即每进行一次IO操做,都须要等待这次操做结束才能继续接下来的操做)、刷新邻接页(InnoDB存储引擎在刷新一个脏页时,会检测该页所在区(extent)的全部页,若是是脏页,那么一块儿刷新。经过AIO能够将多个IO写操做合并为一个IO操做)

  • B+树

    • 咱们为了设计索引的存储结构,以前是创建平衡二叉树,从而避免遍历整张表,最坏状况的时间复杂度是O(logN)->为了当数据量很大时,下降时间复杂度,咱们须要创建其余高度更低的树->那么经过在一个树节点中包含多条数据,和包含多个指针域来实现。->进一步优化,B+树是B树的一种变体,查询性能更好。B+树是一种树数据结构,n叉树,每一个节点有多个孩子,一般用于数据库和操做系统的文件系统中。

    • 特色是可以保持数据稳定有序,其插入和修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入。

    • 一个m阶的B树具备如下特征:(即每一个节点最多包含m个孩子,m值取决于磁盘页的大小)

      如5阶B树中,结点最多有4个key,最少有2个key。

      插入删除时须要始终知足结点key的个数的限制条件

       

       

    • m阶的B+树的特征?

       

         

    • B+树和B树(balance tree)的区别?

      1.有k个子结点的结点必然有k个关键码

      2.B+树非叶结点仅具备索引做用,跟记录有关的信息均存放在叶结点中,所以磁盘页能容纳更多节点元素,更“矮胖”

      3.B+树的全部叶结点构成一个有序链表,能够按照关键码排序的次序遍历所有记录

      4.B+树的查询必须查找到叶子节点,而B树只要匹配到便可不关注元素位置,所以B+树查找更稳定

      5.B+树全部叶子节点自己根据关键字的大小进行链接,从而快速实现范围查询。

        https://segmentfault.com/a/1190000019927682?utm_source=tag-newest
        https://blog.csdn.net/Fmuma/article/details/80287924
  • 什么是事务

    事务是逻辑上的一组逻辑,要么都执行,要么都不执行。(经典例子:银行转帐)

    四大特性(ACID):

       * 原子性:事务是最小的执行单位,不容许分割
      * 一致性:执行事务先后,数据保持一致,多个事务对同一数据读取的结果是相同的。
      * 隔离性:并发访问数据库时,一个用户的事务不被其余事务干扰,各并发事务之间的数据库是独立的。
      * 持久性:*一个事务被提交后*,它对数据库中数据的改变是持久的。即便数据库发生故障也不该该对其有任何影响。
  • 并发事务带来哪些问题

    多个事务并发运行,常常会操做相同的数据来完成各自的任务(多个用户对同一数据进行操做)

    • 脏读:当一个事务正在访问数据而且对数据进行了修改,而这种修改尚未提交到数据库中,这时另一个事务也访问了这个数据,而后使用了这个数据。此时用到的数据是尚未提交的数据。

    • 丢失修改:在一个事务读取一个数据时,另一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失。

    • 不可重复读:指在一个事务内屡次读同一数据。在这个事务尚未结束时,另外一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,因为第二个事务的修改致使第一个事务两次读取的数据可能不太同样。这就发生了在一个事务内两次读到的数据是不同的状况,所以称为不可重复读。

    • 幻读:它发生在一个事务读取了几行数据,接着另外一个并发事务插入/删除了一些数据时。在随后的查询中,第一个事务就会发现多了/少了一些本来不存在的记录,就好像发生了幻觉同样。

  • 事务隔离级别有哪些?MySQL的默认隔离级别是?

    • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,容许读取还没有提交的数据变动,可能会致使脏读、幻读或不可重复读

    • READ-COMMITTED(读取已提交): 容许读取并发事务已经提交的数据,能够阻止脏读,可是幻读或不可重复读仍有可能发生

    • REPEATABLE-READ(可重复读):  对同一字段的屡次读取结果都是一致的,除非数据是被自己事务本身所修改,能够阻止脏读和不可重复读,但幻读仍有可能发生

    • SERIALIZABLE(可串行化): 最高的隔离级别,彻底服从ACID的隔离级别。全部的事务依次逐个执行,这样事务之间就彻底不可能产生干扰,也就是说,该级别能够防止脏读、不可重复读以及幻读

  • MySQL锁机制与InnoDB锁算法

    • 为了解决并发、数据安全的问题,采用锁机制。

    • 按照锁粒度将数据库锁分为表级锁和行级锁

      • 表级锁:对当前操做的整张表加锁,实现简单 ,资源消耗也比较少,加锁快,不会出现死锁 。其锁定粒度最大,触发锁冲突的几率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。当事务更新大表中大部分数据时直接使用表级锁效率更高&事务复杂时,使用行级锁可能会引发死锁致使回滚。

      • 行级锁:只针对当前操做的行进行加锁。 行级锁能大大减小数据库操做的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。InnoDB支持行级锁

      • 页级锁:粒度介于二者之间,一次锁定相邻的一组记录。BDB支持页级锁。开销和加锁时间界于表锁和行锁之间,会出现死锁。锁定粒度界于表锁和行锁之间,并发度通常。

    • 按照是否可写分为共享锁和排他锁:

      • 共享锁S:读锁,其余用户能够并发读取数据,但任何事务都不能获取数据上的排他锁,直到已释放全部共享锁。若是事务T对数据A加上共享锁后,则其余事务只能对A再加共享锁,不能加排他锁。

      • 排它锁X:写锁,防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。若是事务T对数据A加上排他锁后,则其余事务不能再对A加任任何类型的封锁。

    • InnoDB另外的两个表级锁:(意向锁是InnoDB自动加的,不须要用户干预)

      • 意向共享锁IS:事务准备给数据行记入共享锁,事务在一个数据行加共享锁前必须先取得该表的IS锁。

      • 意向排它锁IX:事务准备给数据行加入排他锁,事务在一个数据行加排他锁前必须先取得该表的IX锁。

    • 死锁和避免死锁

      • InnoDB的行级锁是基于索引实现的,若是查询语句为命中任何索引,那么InnoDB会使用表级锁.

      • MyISAM老是一次性得到所需的所有锁(采用表级锁),InnoDB的锁是逐步得到的(默认行级锁)。当两个事务都须要得到对方持有的锁,致使双方都在等待,从而产生死锁。

      • InnoDB的行级锁是基于索引实现的,若是查询语句为命中任何索引,那么InnoDB会使用表级锁。

      • 避免死锁的方式:使用表级锁;多个程序尽可能约定以相同的顺序访问表;同一个事务尽量作到一次锁定所须要的全部资源。

  • 大表优化

    • 限定数据的范围:禁止不带任何限制数据范围条件的查询语句。

    • 读/写分离:数据库拆分,主库负责写,从库负责读。

    • 垂直分区:根据数据库里面数据表的相关性进行拆分,把一张列比较多的表拆分为多张表。可使列数据变小,减小I/O次数,简化表的结构,易于维护;可是主键会出现冗余,须要管理冗余列,使事务变得更加复杂。

    • 水平分区:保持数据表结构不变,经过某种策略存储数据分片。使每一片数据分散到不一样的表/库中,实现分布式。水平拆分最好分库(数据库分片的方案有客户端代理:分片逻辑在应用端,封装在jar包里,经过修改或封装JDBC层实现;中间件代理:在应用和数据中间加一个代理层,分片逻辑统一维护在中间件服务中)。支持很是大的数据量存储,应用端改造也少,可是分片事务难以解决,带来逻辑、部署、运维的各类复杂度。

  • 池化设计思想?数据库链接池?

    • 初始预设资源,解决的问题就是抵消每次获取资源的消耗,如建立线程的开销,获取远程链接的开销等。还包括池子的初始值、池子的活跃值、池子的最大值等。

    • 最大的做用是支持复用,避免重复的建立销毁带来的开销。

    • 表明实现有java线程池、jdbc链接池、redis链接池等。

    • “单线程的方式:你们排队一个一个取水,为了避免浪费水,每一个人接完水后,关掉水龙头,下一我的接的时候再打开水龙头,开水龙和关水龙头能够当作建立和销毁一个线程用于一我的的取水任务。这种方式适合人少的场景。     

      多线程的方式:多提供几个水龙头,这种方式适合人较多的场景,例如学生宿舍的公共水房。

          线程池的方式:提供一个水池,先将水放到水池,而后由多我的同时在水池取水,水龙头能够不用频繁开关,能够支持多人并发取水,可是水池须要专人监管,如监控水池溢出,水池没水,水池取水人员达到上限等。这种方式适合高并发的状况。”

    • 数据库链接本质就是一个socket的链接。在链接池中,建立链接后,将其放置在池中,并再次使用它,所以没必要创建新的链接。若是使用了全部链接,则会创建一个新链接并将其添加到池中。链接池还减小了用户必须等待创建与数据库的链接的时间。

    • JDK内置的四种线程池拒绝策略:调用者运行策略;停止策略;丢弃策略;dubbo/Netty/ActiveMq/pinpoint中的线程拒绝策略(第三方实现);

  • 分库分表

    分红多个表以后,每一个表都是从1开始累加,可是咱们应该是须要一个全局惟一的id来支持。生成全局id的方式有:

    • UUID:不适合做为主键,无序不可读,查询效率低。

    • 数据库自增id:两台数据库分别设置不一样步长,生成不重复ID的策略来实现高可用。这种方式生成的id有序,可是须要独立部署数据库实例,成本高,且有性能瓶颈。

    • 利用redis生成id:性能好,且灵活方便。可是引入新的组件形成系统更加复杂,可用性下降,编码更加复杂,系统成本增长。

  • 一条SQL语句在MySQL中如何执行?

     

     

    MySQL分为Server层(全部跨存储引擎的功能在此实现)和存储引擎层(主要负责数据的存储和读取,采用能够替换的插件式架构,支持InnoDB、MyISAM、Memory等)。

    0.客户端和server之间经过链接器链接,登陆MySQL时进行身份认证和权限相关。

    1.应用程序把查询SQL语句发送给服务器端执行

    2.查询缓存:接收到查询请求后,并不会直接去数据库查询,而是在数据库的查询缓存中找是否有相应的查询数据。若是语句不在查询缓存中,就会继续后面的执行阶段,执行完成后,执行结果会被存入查询缓存中。

    3.查询优化处理,生成执行计划(若是没有命中缓存)/将一个SQL转换为一个执行计划

      * 解析SQL:MySQL解析SQL语句,生成一棵对应的解析树。 
      * 预处理:根据一些MySQL规则进一步检查解析树是否合法,如数据表和列是否存在,解析列名和别名,是否有歧义。
      * 优化SQL执行计划:优化器是在表里面有多个索引的时候,决定使用哪一个索引;或者在一个语句有多表关联的时候,决定各个表的链接顺序,将SQL语句转化成执行计划,一条查询能够有不少种执行方式,最后都返回相同的结果,最后找到其中最好的执行计划。

    4.MySQL根据相应的执行计划完成整个查询:执行计划是一个数据结构,其中有大量的操做须要经过调用存储引擎实现的接口完成。

    5.将查询结果返回客户端

  • 一条SQL语句执行得很慢的缘由有哪些?

    • 大多数状况下很正常,偶尔很慢

      1.数据库在刷新脏页:redolog写满了;内存不够用了;MySQL认为系统“空闲”的时候;MySQL正常关闭的时候

      2.执行时遇到锁,如表锁、行锁。经过show processlist查看当前状态

    • 一直执行得很慢

      1.没用到索引,只能走全表扫描:字段没有索引;字段有索引但没有用上索引(若是字段左边作了运算,那么查询时就不会用上索引。须要把运算放在字段右边);函数操做致使没有用上索引。

      2.数据库选错索引:主键索引存放的值是整行字段的数据,非主键索引上存放的值不是整行字段的数据,而是存放主键字段的值。系统经过预测而选择走全表扫描或者走索引,可是因为统计的失误,致使系统没有走索引,而是走了全表扫描。

相关文章
相关标签/搜索