java面试(三)数据库

目录

范式(最好记住几个例子)

索引(索引的含义、优缺点)

索引的数据结构(底层)

索引为什么使用B+树不用B树

索引的分类

聚簇索引与非聚簇索引

建立索引的考虑因素

使用索引的注意事项

事务(ACID)

多事务并发会造成的问题(脏读、不可重复读、幻读)

事务隔离性

读锁与写锁

高并发控制数据库

Mysql的工具分析

MyBatis一级缓存

MyBatis二级缓存

Mybatis中的#和$的区别

高并发数据库设计(百万级数据库设计)

数据库优化

主从复制

Mysql数据引擎的选用

数据库连接池


范式(最好记住几个例子)

第一范式:只要是关系型数据库的表,都满足第一范式。
性质:第一范式的数据表中的所有字段都是单一属性,不可分割。
第二范式:不可使用组合键,确保唯一主键。
第三范式:要求数据表中不存在非关键字段对任一候选关键字段的传递函数依赖,表分开。

索引(索引的含义、优缺点)

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。

优点:

  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  • 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
  • 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

缺点:

  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
  • 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚集索引那么需要的空间就会更大。
  • 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

索引的数据结构(底层)

B-树,B+树,带顺序访问的B+树

https://www.cnblogs.com/songwenjie/p/9414960.html

索引为什么使用B+树不用B树

用B+树不用B树考虑的是IO对性能的影响,B树的每个节点都存储数据,而B+树只有叶子节点才存储数据,所以查找相同数据量的情况下,B树的高度更高,IO更频繁。数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)。其中在MySQL底层对B+树进行进一步优化:在叶子节点中是双向链表,且在链表的头结点和尾节点也是循环指向的。

索引的分类

主键索引:某一个属性组能唯一标识一条记录,主键索引只能有一个

唯一索引:避免同一个表中某数据列中的值重复,唯一索引可有多个

常规索引:快速定位特定数据,应加在查询条件的字段,不易添加太多常规索引,影响数据的插入,删除和修改操作

复合索引:指多个字段上创建的索引,只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用

聚簇索引与非聚簇索引

聚集索引

聚集索引表记录的排列顺序和索引的排列顺序一致,所以查询效率快。只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。只有当表包含聚集索引时,表中的数据行才按排序顺序存储。聚集索引对应的缺点就是修改慢,因为为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页重新排序。

非聚集索引

非聚集索引即索引中的逻辑顺序并不等同于表中行的物理顺序,两种索引都采用B+树结构。非聚集索引层次多,不会造成数据重排。

例子对比两种索引

聚集索引就类似新华字典中的拼音排序索引,都是按顺序进行,例如找到字典中的“爱”,就里面顺序执行找到“癌”。而非聚集索引则类似于笔画排序,索引顺序和物理顺序并不是按顺序存放的。

根本区别

聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。
 

建立索引的考虑因素

应该在哪些列上创建索引

  •  经常需要搜索的列上
  •  作为主键的列上
  •  经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度
  •  经常需要根据范围进行搜索的列上
  •  经常需要排序的列上
  •  经常使用在where子句上面的列上

不应该在哪些列上创建索引

  •  查询中很少用到的列
  •  对于那些具有很少数据值的列.比如人事表的性别列,bit数据类型的列
  •  对于那些定义为text,image的列.因为这些列的数据量相当大
  •  当对修改性能的要求远远大于搜索性能时.因为当增加索引时,会提高搜索性能,但是会降低修改性能

使用索引的注意事项

1.索引不会包含有NULL值的列

        只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。应该用0、一个特殊的值或者一个空串代替空值。

2.复合索引

        比如有一条语句是这样的:select * from users wherearea=’beijing’ and age=22;如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area,age,salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

3.使用短索引

        对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

4.排序的索引问题

        mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

5.like语句操作

        一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like“%aaa%” 不会使用索引而like“aaa%”可以使用索引。

6.不要在列上进行运算

        select* from users where  YEAR(adddate)

7.不使用NOT IN和操作

        NOT IN和操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替,id3则可使用id>3 or id
 

事务(ACID)

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

  • 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
  • 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
  • 事务用来管理 insert,update,delete 语句

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。

MYSQL 事务处理主要有两种方法:

1、用 BEGIN, ROLLBACK, COMMIT来实现

  • BEGIN 开始一个事务
  • ROLLBACK 事务回滚
  • COMMIT 事务确认

2、直接用 SET 来改变 MySQL 的自动提交模式:

  • SET AUTOCOMMIT=0 禁止自动提交
  • SET AUTOCOMMIT=1 开启自动提交

多事务并发会造成的问题(脏读、不可重复读、幻读)

  • 脏读 : 一个事务读取到另一事务未提交的更新数据
  • 不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
  • 幻读 : 一个事务读到另一个事务已提交的insert数据

事务隔离性

第一类: Read Uncommitted(读取未提交的内容)

事务A/事务B
       在该隔离级别,所有事物都可以看到其他未提交事务的执行结果,本隔离级别很少用于实际应用,因为他的性能页不比其他级别好多少,读取未提交的数据,也被称之为脏读(Dirty Read)。

第二类: Read Committed(读取提交内容)

       这是大多数数据库系统的默认隔离级别(但不是mysql默认的),他满足了隔离的简单定义:一个事物在提交之前对其他事物是不可见的,这种隔离级别也支持所谓的不可重复读取(Nonerepeatable Read),因为同一事务的其他实例在该实例处理其他期间可能会有新的commit,所以同一select可能返回不同结果。

第三类: Repeatable Read(可复读)

       这是mysql默认的隔离级别,他确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,不过理论上,这会导致另一个棘手的问题,幻读(Phantom Read),简单的说,幻读指当用户读取某一范围的数据行时,另一个事物又在该范围内插入了新行,当用户再读取该范围内的数据时,会发现有新的"幻影"行,Innodb和Falcon存储引擎通过多版本并发控制(MVCC)机制解决了该问题。

第四类: Serializerable(可串行化)

       这是最高的隔离级别,他通过强制事物排序,使之不可能相互冲突,从而解决了幻读问题,简言之,它是在每个读的数据行上加共享锁,在这个级别,可能导致大量的超时现象和锁竞争。
 

隔离级别                        脏读                      不可重复读                       幻读
读取未提交内容             v                                      v                                v
读取已提交内容             x                                      v                                v
可重复读                        x                                      x                                v
可串行化                        x                                      x                                x

高并发控制数据库

解决数据库高并发的常见方案:

  1. 缓存式的 Web 应用程序架构: 在 Web 层和 DB(数据库)层之间加一层 cache 层,主要目的:减少数据库读取负担,提高数 据读取速度。cache 存取的媒介是内存,可以考虑采用分布式的 cache 层,这样更容易破除内存容量 的限制,同时增加了灵活性。
  2. 增加 Redis 缓存数据库:
  3. 增加数据库索引:避免以下两个问题:索引越多,查询速度反而会变慢;数据表每写入一次数据,都会让后面的索引编号重新排序,仍然会降低速度(所以建议在经常变动的表里建索引)
  4. 页面静态化:减少用户访问服务器对数据库的读取量
  5. MySQL 主从读写分离:当数据库的写压力增加,cache 层(如 Memcached)只能缓解数据库的读取压力。读写集 中在一个数据库上让数据库不堪重负。读写分离就是只在主服务器上写,只在从服务器上读
  6. 分表分库:分表【水平拆分】。比如将数据表以业务类别进行拆分,缩短表的长度,可以提高数据库查询的速度(查询时长跟数据的长度成正比),间接提高并发洪峰的处理效率
  7. 负载均衡集群:终极解决办法,想要提高性能上的提高,最根本最有效的方法就是提高硬件上的配置,就酱
     

Mysql的工具分析

https://www.cnblogs.com/amiezhang/p/10217133.html

MyBatis一级缓存

https://www.cnblogs.com/happyflyingpig/p/7739749.html

MyBatis二级缓存

Mybatis中的#和$的区别

Mybatis 的Mapper.xml语句中parameterType向SQL语句传参有两种方式:#{}和${}

我们经常使用的是#{},一般解说是因为这种方式可以防止SQL注入,简单的说#{}这种方式SQL语句是经过预编译的,它是把#{}中间的参数转义成字符串,举个例子:

select * from student where student_name = #{name} 

预编译后,会动态解析成一个参数标记符?:

select * from student where student_name = ?

而使用${}在动态解析时候,会传入参数字符串

select * from student where student_name = 'lyrics'

总结:

#{} 这种取值是编译好SQL语句再取值
${} 这种是取值以后再去编译SQL语句

#{}方式能够很大程度防止sql注入。
$方式无法防止Sql注入。
$方式一般用于传入数据库对象,例如传入表名.
一般能用#的就别用$.
 

高并发数据库设计(百万级数据库设计)

http://blog.itpub.net/26736162/viewspace-2651606/

数据库优化

  1. 数据分区
    对于海量的数据查询优化,一种重要方式是如何有效的存储并降低需要处理的数据规模,所以我们呢可以对海量数据进行分区.例如,针对年份存储的数据,我们可以按照年进行分区,不同数据库有不同的分区方式,但处理机制却大体相同.例如SQLserver的数据分区将不同的数据存于不同的文件组中,而不同的文件存在不同的磁盘分区下,这样吧数据分区,减少磁盘IO和系统负荷.

  2. 索引

    索引一般可以加速数据的检索数据,加速表之间的连接,对表建索引包括在主键上建立聚簇索引,将聚合索引建立在日期列上, 索引的优点很多,但是对于索引的建立,还需要考虑实际情况,而不能对每个列都建索引.如果表结构很大,你要考虑到建立索引和维护索引的开销,索引本身也占用物理空间,动态修改表也要动态维护索引,如果这些开销大过索引带来的速度优化,那就得不偿失.

  3. 缓存机制

    当数据量增加时,一般的处理工具都考虑缓存问题,缓存大小的设置也关系到数据处理的表现.列如,

    处理2亿条数据聚合操作室,缓存设置为100000条/buffer合理

  4. 加大虚存

    由于系统资源有限,而处理的数据量非常大,当内存不足时,适量增加虚存来解决

  5. 分批处理

    由于处理信息量巨大,可以对海量的数据进行分批(类似云计算MapReduce),然后再对处理后的数据进行合并操作,分而治之,这样有利于处理小数据.

  6. 使用临时表和中间表

    数据量增加时,处理中要考虑提前汇总,这样做的目的是化整为零,大表变小表,分块处理完之后再利用一定的规则进行合并,处理过程中的临时表的使用和中间结果的保存都非常重要.如果对海量的数据,大表处理不了,只能拆分为多个小表.如果处理过程中需要多步汇总操作,则按汇总步骤一步一步来.

  7. 优化查询语句

    查询语句的性能对查询效率的影响非常大,尽量早的缩小查询范围

  8. 使用视图

    视图是表中的逻辑表现,不占用物理地址,对于海量数据,可以按一定的规则分散到各个基本表中,查询过程基于视图进行.

  9. 使用存储过程

    在存储过程中尽量使用SQL自带的返回参数,而非自定义的返回参数,减少不必要的参数,避免数据冗余

  10. 用排序来取代非顺序存储

    磁盘上的机械手臂的来回移动使得非顺序磁盘存取变成了最慢的操作,但是在SQL语句中这个现象被隐藏了,这样就使得查询中进行了大量的非顺序页查询,降低了查询速度.

  11. 使用采样数据进行数据挖掘

    基于海量数据的数据挖掘方兴未艾,面对超海量数据,一般的挖掘算法往往采用数据抽样的方式进行处理,这样误差不会很大,大大的提高处理效率和处理的成功率.一般采样时应注意数据的完整性,防止过大的偏差.

主从复制

MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。

Mysql数据引擎的选用

数据库连接池

数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽地与数据库连接。 更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量、使用情况,为系统开发﹑测试及性能调整提供依据。

连接池的核心思想是连接的复用,通过建立一个数据库连接池以及一套连接使用、分配和管理策略,使得该连接池中的连接可以得到高效,安全的复用,避免了数据库连接频繁建立和关闭的开销。
  连接池的工作原理主要由三部分组成,分别为连接池的建立,连接池中连接的使用管理,连接池的关闭。
  第一、连接池的建立。 一般在系统初始化时,连接池会根据系统配置建立,并在池中建立几个连接对象,以便使用时能从连接池中获取。java 中提供了很多容器类,可以方便的构建连接池,例如 Vector(线程安全类),linkedlist 等。
  第二、连接池的管理。 连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其策略是:
  当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用并作相应处理(即标记该连接为正在使用,引用计数加 1);如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没有达到最大连接数,就重新创建一个连接给请求的客户;如果达到,就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。
  当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过了就从连接池中删除该连接,并判断当前连接池内总的连接数是否小于最小连接数,若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。
  第三、连接池的关闭。 当应用程序退出时,关闭连接池中所有的链接,释放连接池相关资源,该过程正好与创建相反。
 

连接池的主要优点

  1)、减少连接的创建时间。连接池中的连接是已准备好的,可以重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。
  2)、更快的系统响应速度。数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
  3)、统一的连接管理。如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统的连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的链接数量,增强了系统在大量用户应用时的稳定性。



 

发布了16 篇原创文章 · 获赞 12 · 访问量 8086

猜你喜欢

转载自blog.csdn.net/ziyou434/article/details/105079851
今日推荐