关系型数据库

felix.shao2025-02-09数据库

关系型数据库

概念

如何通俗地理解三个范式?
  • 第一范式:每个列都不可以再拆分。
  • 第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
  • 第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

范式化设计优缺点:
优点:可以尽量得减少数据冗余,使得更新快,体积小
缺点:对于查询需要多个表进行关联,减少写得效率增加读得效率,更难进行索引优化

反范式化:
优点:可以减少表得关联,可以更好得进行索引优化
缺点:数据冗余以及数据异常,数据得修改需要更多的成本

数据库的基本关系(基本表)?

 数据库中有三种关系,分别是:基本关系(又称基本表或基表),查询表,视图表。
 基本表是实际存在的表,查询表是查询结果对应的表,视图表是由基本表和其他视图表导出的表,是虚表,不对应实际存储的数据。
 基本表所具有的 6 条性质如下:

  • 列是同质的,即每一列中的分量都是同一类型的数据,来自同一个域。
  • 不同的列可以来自同一个域,每一列又称之为属性,不同的属性要有不同的属性名。
  • 列的顺序无关紧要。
  • 行的顺序也无关紧要。
  • 任意两个元组的候选码不能取相同的值(如主键不能相同)。
  • 分量必须要取原子值,即一个表中的某一项不能再拆成好几项。
游标是什么?

 游标:是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。

什么是存储过程?用什么来调用?

 存储过程是一个预编译的 SQL 语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次 SQL,使用存储过程比单纯 SQL 语句执行要快。可以用一个命令对象来调用存储过程。

SQL

什么是 SQL?

 结构化查询语言(Structured Query Language)简称 SQL,是一种数据库查询语言。
 作用:用于存取数据、查询、更新和管理关系数据库系统。

SQL 语言包括哪几部分?每部分都有哪些操作关键字?

 SQL 语言包括数据定义(DDL)、数据操纵(DML)、数据控制(DCL)和数据查询(DQL)四个部分。

  • 数据定义:Create Table,Alter Table,Drop Table, Craete/Drop Index 等。
  • 数据操纵:Select,insert,update,delete。
  • 数据控制:grant,revoke。
  • 数据查询:select。
SQL 注入漏洞产生的原因?如何防止?

 SQL 注入是用户的输入信息,在连接 SQL 语句的过程中,跨越了数据本身,变成了 SQL 语句逻辑的一部分,随后被拼凑的 SQL 语句被数据库运行,造成了难以挽回的损失。
防止 SQL 注入的方式:

  • 严格区分用户权限。在权限设计中,针对软件用户,没有必要给予数据库的创建、删除等管理权限。这样即便在用户输入的 SQL 语句种含有内嵌式的恶意程序,因为其权限的限定,也不可能执行。所以程序在权限设计时,最好把管理员与用户区别起来。这样能够最大限度的降低注入式攻击对数据库产生的损害。
  • 强制参数化语句。在设计数据库时,如果用户输入的数据并不直接内嵌到 SQL 语句中,而通过参数来进行传输的话,那麼就可以合理的预防 SQL 注入式攻击。运用这种方法能够避免绝大多数的 SQL 注入攻击。遗憾的是,如今适用参数化语句的数据库引擎并不多,但是数据库工程师在开发时要尽可能选用参数化设计语句。
  • 检验用户输入的信息。检测字符串的內容,只接纳需要的值;拒绝包括二进制、转义序列和注释內容,这有利于预防脚本注入。检测输入内容的大小和数据类型,强制执行适度的限定与变换,这有利于避免缓冲区溢出。
  • 利用专业的漏洞扫描工具。应用专业的漏洞扫描工具,能够协助管理人员来找寻有可能被 SQL 注入攻击的点。凭着专用工具,管理人员可以快速发觉 SQL 注入的漏洞,并采用积极主动的对策来预防 SQL 注入式攻击。
  • 利用陷阱账户。可以设定两个账户,即管理员账户和防注入账户。将防注入的账户伪装成管理员账户,如将名称设置为 admin,让检测软件产生错觉,在密码方面,可以设置成超长的中文字符(几千字),让攻击者的漏洞检测软件达到高负荷状态直至资源耗尽。
NULL 是什么意思

 NULL 这个值表示 UNKNOWN(未知):它不表示“”(空字符串)。对 NULL 这个值的任何比较都会生产一个 NULL 值。您不能把任何值与一个 NULL 值进行比较,并在逻辑上希望获得一个答案。
 使用 IS NULL 来进行 NULL 判断。

外连接、内连接与自连接的区别

 先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一个表的所有记录和另一个表中的所有记录一一匹配。

  • 内连接:则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合条件的记录不会出现在结果集中,即内连接只连接匹配的行。
  • 外连接:其结果集中不仅包含符合连接条件的行,而且还会包括左表、右表或两个表中的所有数据行,这三种情况依次称之为左外连接,右外连接,和全外连接。
  • 左外连接:也称左连接,左表为主表,左表中的所有记录都会出现在结果集中,对于那些在右表中并没有匹配的记录,仍然要显示,右边对应的那些字段值以 NULL 来填充。右外连接,也称右连接,右表为主表,右表中的所有记录都会出现在结果集中。左连接和右连接可以互换,MySQL 目前还不支持全外连接。
  • 自连接:表自己连接自己。

视图

什么叫视图?

 视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增、改、查、操作,视图通常是有一个表或者多个表的行或列的子集。它使得我们获取数据更容易,相比多表查询。

试述视图的优缺点?

优点:

  • 视图能够简化用户的操作。
  • 视图使用户能以多种角度看待同一数据。
  • 视图为数据库提供了一定程度的逻辑独立性。
  • 视图能够对机密数据提供安全保护。

缺点:

  • 性能差。
  • 复杂视图可能不支持修改。

约束

完整性约束包括哪些?

 数据完整性(Data Integrity)是指数据的精确(Accuracy)和可靠性(Reliability)。
分为以下四类:

  1. 实体完整性:规定表的每一行在表中是惟一的实体。
  2. 域完整性:是指表中的列必须满足某种特定的数据类型约束,其中约束又包括取值范围、精度等规定。
  3. 参照完整性:是指两个表的主关键字和外关键字的数据应一致,保证了表之间的数据的一致性,防止了数据丢失或无意义的数据在数据库中扩散。
  4. 用户定义的完整性:不同的关系数据库系统根据其应用环境的不同,往往还需要一些特殊的约束条件。用户定义的完整性即是针对某个特定关系数据库的约束条件,它反映某一具体应用必须满足的语义要求。

 与表有关的约束:
 包括列约束(NOT NULL(非空约束))和表约束(PRIMARY KEY、foreign key、check、UNIQUE)。

主键和候选键有什么区别

 表格的每一行都由主键唯一标识,一个表只有一个主键。
 主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键引用。

主键、外键和索引的区别?

 定义:
 主键:唯一标识一条记录,不能有重复的,不允许为空。
 外键:表的外键是另一表的主键, 外键可以有重复的, 可以是空值。
 索引:为了加速对表中数据行的检索而创建的一种分散的存储结构,主键是索引的一种形态。

 作用:
 主键:用来保证数据完整性。
 外键:用来和其他表建立联系用的。
 索引:是提高查询排序的速度。

 个数:
 主键:主键只能有一个。
 外键:一个表可以有多个外键。
 索引:一个表可以有多个索引。

数据库锁

什么是锁?

 锁(LOCKING)是最常用的并发控制结构。是防止其他事务访问指定的资源控制、实现并发控制的一种主要手段。锁是事务对某个数据库中的资源(如表和记录)存取前,先向系统提出请求,封锁该资源,事务获得锁后,即取得对数据的控制权,在事务释放它的锁之前,其他事务不能更新此数据。当事务撤消后,释放被锁定的资源。
 当一个用户锁住数据库中的某个对象时,其他用户就不能再访问该对象。

按照锁的粒度分数据库锁有哪些?
  • 行级锁:行级锁是 MySQL 中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 表级锁:表级锁是 MySQL 中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分 MySQL 引擎支持。最常使用的 MYISAM 与 INNODB 都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
  • 页级锁:页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。
什么是死锁?怎么解决?

 死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
 常见的解决死锁的方法:

  • 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
  • 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。

 另外如果业务处理不好可以用分布式事务锁或者使用乐观锁。

以下是 Java 并发死锁解决,原理类似:
形成死锁的四个必要条件是什么
* 互斥条件:线程(进程)对于所分配到的资源具有排它性,即一个资源只能被一个线程(进程)占用,直到被该线程(进程)释放。
* 请求与保持条件:一个线程(进程)因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
* 不剥夺条件:线程(进程)已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
* 循环等待条件:当发生死锁时,所等待的线程(进程)必定会形成一个环路(类似于死循环),造成永久阻塞。

如何避免线程死锁?
我们只要破坏产生死锁的四个条件中的其中一个就可以了。
* 破坏互斥条件
这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
* 破坏请求与保持条件
一次性申请所有的资源。
* 破坏不剥夺条件
占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
* 破坏循环等待条件
靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
锁的优化策略
  • 读写分离
  • 分段加锁
  • 减少锁持有的时间
  • 多个线程尽量以相同的顺序去获取资源

 不能将锁的粒度过于细化,不然可能会出现线程的加锁和释放次数过多,反而效率不如一次加一把大锁。

数据库的乐观锁和悲观锁是什么?怎么实现的?

 数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制。
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过 version 的方式来进行锁定。实现方式:乐观锁一般会使用版本号机制或 CAS 算法实现。

Last Updated 2/9/2025, 10:09:42 PM