数据库
Posted baoziy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库相关的知识,希望对你有一定的参考价值。
- 数据抽象:
物理抽象、概念抽象、视图级抽象,内模式、模式、外模式
- 完整性约束:
实体完整性、域完整性、参照完整性、用户定义完整性
- 超键、候选键、主键、外键
l 超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以作为超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
l 候选键:不含有任何多余属性的超键称为候选键。
l 主键:主键就是候选键里面的一个,是人为规定的。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
l 外键:在一个表中存在的另一个表的主键称此表的外键。
- 什么是视图
l 使用视图和使用表完全一样,只需要把视图当成一张表就OK了。视图是一张虚拟表。
l 优点: 1)对数据库的访问,因为视图可以有选择性的选取数据库里的一部分。 2 )用户通过简单的查询可以从复杂查询中得到结果。 3 )维护数据库表的独立性,视图可从多个表检索数据。 4 )对于相同的数据 表可产生不同的视图。
l 缺点: 性能:查询视图时,必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,那么就无法更改数据
l 视图的使用场景:
i. 不希望访问者获取整个表的信息,只暴露部分字段给访问者,所以就建一个虚表,就是视图。
ii. 查询的数据来源于不同的表,而查询者希望以统一的方式查询,这样也可以建立一个视图。把多个表查询结果联合起来,查询者只需要直接从视图中获取数据,不必考虑数据来源于不同表所带来的差异。
- 触发器的作用:
触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化,可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。
- 数据库范式
a) 1NF:每个属性是不可分的。 2NF:若关系R是1NF,且每个非主属性都完全函数依赖于R的键。例SLC(SID#, CourceID#, SNAME,Grade),则不是2NF; 3NF:若R是2NF,且它的任何非键属性都不传递依赖于任何候选键。
b) 第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。
c) 第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。
d) 第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如 果存在"A → B → C"的决定关系,则C传递函数依赖于A。因此,满足第三范式的数据库表应该不存在如下依赖关系: 关键字段 → 非关键字段 x → 非关键字段y
- 什么是存储过程?有哪些优缺点
l 存储过程是一些预编译的SQL语句。
l 特点:
i. 存储过程是一个预编译的代码块,执行效率比较高
ii. 一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率
iii. 可以一定程度上确保数据安全
- 如何维护数据库的完整性和一致性
维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?为什么?尽可能使用约束,如check,主键,外键,非空字段等来约束,这样做效率最高,也最方便。其次是使用触发器,触发器一经定义,那么任何用户对表的操作(增,删,改)均由服务器激活相应的触发器,在DBMS核心层进行集中地完整性约束。这种方法可以保证,无论什么业务系统访问数据库都可以保证数据的完整新和一致性。最后考虑的是自写业务逻辑,但这样做麻烦,编程复杂,执行效率低下。
- 数据库事务
l 什么是事务
所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。事务(Transaction)是并发控制的基本单位。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
l 事务的特性:ACID
i. 原子性:指事务包含的所有操作要么全部成功,要么全部失败回滚
ii. 一致性:在事务执行之前和事务结束以后,数据库的完整性约束不会被破坏。
iii. 隔离性:隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
iv. 持久性:在事务执行结束,该事务对数据库所作的更改操作是持久的。
l 事务隔离级别以及脏读、不可重复读、幻读
i. 脏读是指一个事务处理过程中读取了另一个未提交的事务中的数据。
ii. 不可重复读是指对数据库中某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了该数据。
iii. 幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,发现还有一行没有修改,其实这行是执行事务T2时添加的,就好像产生幻觉一样,这就是发生了幻读。
iv. 解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
v. 现在来看看mysql数据库为我们提供的四种隔离级别:
② Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。(MySQL默认的事务隔离级别)
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
- 数据库索引
索引的实现方式B+树(不是二叉树):因为B+ 树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度(B+ 树元素自底向上插入)。
InnoDB使用的是聚簇索引(根据主键创建),将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。
MyISM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。
聚簇索引的优势在哪里?
1 由于行数据和叶子节点存储在一起,这样主键和行数据是一起被载入内存的,找到叶子节点就可以立刻将行数据返回了,如果按照主键Id来组织数据,获得数据更快。
2 辅助索引使用主键作为"指针" 而不是使用地址值作为指针的好处是:减少了当出现行移动或者数据页分裂时辅助索引的维护工作。使用主键值当作指针会让辅助索引占用更多的空间,换来的好处是InnoDB在移动行时无须更新辅助索引中的这个"指针"。
Page结构:
理解InnoDB的实现不得不提Page结构,Page是整个InnoDB存储的最基本构件,也是InnoDB磁盘管理的最小单位,与数据库相关的所有内容都存储在这种Page结构里。Page分为几种类型,常见的页类型有数据页(B-tree Node)Undo页(Undo Log Page)系统页(System Page) 事务数据页(Transaction System Page)等。单个Page的大小是16K(编译宏UNIV_PAGE_SIZE控制),每个Page使用一个32位的int值来唯一标识,这也正好对应InnoDB最大64TB的存储容量(16Kib * 2^32 = 64Tib)。一个Page的基本结构如下图所示:
- 数据库的锁
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
l 行锁 vs 表锁
l 读锁 vs 写锁
l 乐观锁 vs 悲观锁以及如何实现?(MVCC)
悲观锁的特点是先获取锁,再进行业务操作:
通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
乐观锁,也叫乐观并发控制,它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。
l 加锁的方式
乐观锁(给表加一个版本号字段) 这个并不是乐观锁的定义,给表加版本号,是数据库实现乐观锁的一种方式。
l 乐观锁和悲观锁的比较
i. 悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法
ii. 乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能;
iii. 乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方。
iv. 响应速度:如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。
v. 冲突频率:如果冲突频率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁会需要多次重试才能成功,代价比较大。
vi. 重试代价:如果重试代价大,建议采用悲观锁
- MySQL都有什么锁,死锁判定原理和具体场景,死锁怎么解决?
a) MySQL有三种锁的级别:页级、表级、行级。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
b) 什么情况下会造成死锁
所谓死锁<DeadLock>: 是指两个或两个以上的进程在执行过程中。因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法进行下去。此时称系统处于死锁状态或系统产生了死锁。
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。
c) 死锁的解决办法
查出的线程杀死 kill
设置锁的超时时间
- MySQL常见数据库存储引擎比较InnoDB;MyISAM;Memory
注意:
mysiam引擎的表的数据是按照插入的顺序显示的。
说明:innodb引擎的表的数据是按照主键的顺序插入的。
事务处理上方面:
MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。
InnoDB:提供支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
锁级别:
MyISAM:只支持表级锁,用户在操作MyISAM表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。
InnoDB:支持事务和行级锁,是InnoDB的最大特色。行锁大幅度提高了多用户并发操作的性能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
虽然MySQL里的存储引擎不只是MyISAM与InnoDB这两个,但常用的就是两个,两种存储引擎的大致区别表现在:
i. InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
ii. MyISAM适合查询以及插入为主的应用;InnoDB适合频繁修改以及涉及到安全性较高的应用。
iii. InnoDB支持外键,MyISAM不支持,从MySQL5.5.5以后,InnoDB是默认引擎。
iv. InnoDB不支持FULLTEXT类型的索引。
v. InnoDB中不保存表的行数
vi. InnoDB支持行锁
- MySql连接池对比
l 维护一定数量的数据库连接,减少创建连接的时间降低资源消耗 ;
l 可以是程序有更快的响应时间
l 便于对数据库连接的统一管理
- 简单说一说drop、delete与truncate的区别
区别
a) SQL中的drop、delete、truncate都表示删除,但是三者有一些差别
b) delete和truncate只删除表的数据不删除表的结构,而drop则会直接删除表的结构
c) 速度,一般来说: drop> truncate >delete
d) delete语句是dml,这个操作会放到rollback segement中,事务提交之后才生效;
e) 如果有相应的trigger,执行的时候将被触发. truncate,drop是ddl, 操作立即生效,原数据不放到rollback segment中,不能回滚. 操作不触发trigger.
应用场景:
a) 不再需要一张表的时候,用drop
b) 想删除部分数据行时候,用delete,并且带上where子句
c) 保留表而删除所有数据的时候用truncate
- union和union all有什么不同?
UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。 UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。 从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL。
- JOIN执行计划
内连接的连接查询结果集中仅包含满足条件的行,内连接是SQL Server缺省的连接方式,可以把INNERJOIN简写成JOIN,根据所使用的比较方式不同,内连接又分为等值连接、自然连接和不等连接三种;
- MySQL 高并发环境解决方案
l MySQL 高并发环境解决方案 分库 分表 分布式 增加二级缓存。。。。。
l 需求分析:互联网单位 每天大量数据读取,写入,并发性高。
l 现有解决方式:水平分库分表,由单点分布到多点数据库中,从而降低单点数据库压力。
l 集群方案:解决DB宕机带来的单点DB不能访问问题。
l 读写分离策略:极大限度提高了应用中Read数据的速度和并发量。无法解决高写入压力。
- 如何优化查询语句?
1.建索引 2.减少表之间的关联 3.优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据 量大的表排在前面 4.简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据 5.尽量用PreparedStatement来查询,不要用Statement
- 几种表连接方式
内连接、自连接、外连接(左、右、全)、交叉连接。内连接:只有两个元素表相匹配的才能在结果集中显示。 外连接: 左外连接:左边为驱动表,驱动表的数据全部显示,匹配表中不匹配的不会显示。 右外连接:右边为驱动表,驱动表的数据全部显示,匹配表中不匹配的不会显示。 全外连接:连接的表中不匹配的数据也会全部显示出来。交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。。自连接是一种特殊的内连接,它是指相互连接的表在物理上为同一张表,但可以在逻辑上分为两张表。
- 非关系型数据库和关系型数据库区别
非关系型数据库的优势:
1. 性能:NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。
2. 可扩展性:同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
关系型数据库的优势:
1. 复杂查询:可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询。
2. 事务支持:使得对于安全性能很高的数据访问要求得以实现。
- 数据库崩溃时事务的恢复机制
Undo Log是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用了Undo Log来实现多版本并发控制(简称:MVCC)。
Undo Log的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到UndoLog。然后进行数据的修改,如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
之所以能同时保证原子性和持久化,是因为以下特点:
更新数据前记录Undo log。为了保证持久性,必须将数据在事务提交前写到磁盘。只要事务成功提交,数据必然已经持久化。Undo log必须先于数据持久化到磁盘,那么不管数据是否保存到磁盘发生了错误或者执行回滚操作,都能利用Undo log中的备份将数据恢复到事务开始之前的状态。
缺陷:每个事务提交前将数据和Undo Log写入磁盘,这样会导致大量的磁盘IO,因此性能很低。
Redo Log
原理和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log进行持久化即可,不需要将数据持久化。如果系统崩溃,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容将所有数据恢复到最新的状态。
以上是关于数据库的主要内容,如果未能解决你的问题,请参考以下文章