数据库
Mysql
数据库三范式
第一范式(1NF)
无重复的列:数据库表的每一列都是不可分割的基本数据项,同一列中不能同时有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。
举例1:一张学生表Student(stuNo,stuName,age,age,sex)是不符合第一范式的,因为有重复列age属性。去除重复列age以后的Student(stuNo,stuName,age,sex)是符合第一范式的。
第二范式(2NF)
属性完全依赖于主键【消除部分子函数依赖】:数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是唯一的,因此每个员工可以被唯一区分。这个唯一属性列被称为主关键字或主键、主码。实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。简而言之,第二范式就是属性完全依赖于主键。
这里说的主关键字可能不只有一个,有些情况下是存在联合主键的,就是主键有多个属性。
第三范式(3NF)
属性不依赖于其它非主属性【消除传递依赖】:一个数据库表中不包含已在其它表中已包含的非主关键字信息。
InnoDB 和 MyISAM 存储引擎的区别
基本区别:
- MyISAM 类型不支持事务处理等高级处理,而 InnoDB 类型支持、外键、行级锁等高级数据库功能。
- MyISAM 类型的表强调的是性能,其执行速度比 InnoDB 类型更快。
具体区别:
- InnoDB 不支持 FULLTEXT 类型的索引。
- InnoDB 中不保存表的具体行数,也就是说,执行 select count( * ) from table 时,InnoDB 要扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数即可。注意:当count( * ) 语句包含 where 条件时,两种表的操作是一样的。
- 对于 AUTO_INCREMENT 类型的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM 表中,可以和其他字段一起建立联合索引。
- DELETE FROM table 时,InnoDB 不会重新建立表,而是一行一行的删除。
- LOAD TABLE FROM MASTER 操作对 InnoDB 是不起作用的,解决方法是首先把 InnoDB 表改成 MyISAM 表,导入数据后再改成 InnoDB 表,但是对于使用的额外的 InnoDB 特性(例如外键)的表不适用。
- InnoDB 表的行锁也不是绝对的,假如在执行一个 SQL 语句时 MySQL 不能确定要扫描的范围, InnoDB 表同样会锁全表,例如 update table set num=1 where name like “%aaa%”
索引分类(主键、唯一索引、全文索引、覆盖索引等等),最左前缀原则,哪些条件无法使用索引
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
为表设置索引付出的代价:
- 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
优点:
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
- 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
- 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
- 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
一般来说,应该在这些列上创建索引:
- 经常需要搜索的列上,可以加快搜索的速度。
- 作为主键的列,强制该列的唯一性和组织表中数据的排列结构。
- 经常用在连接的列,这些列主要是一些外键,加快连接的速度。
- 经常需要根据范围进行搜索的列,因为索引已经排序,其指定的范围是连续的。
- 经常需要排序的列,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询速度。
- 经常使用在WHERE子句中的列,加快条件的判断速度。
一般来说,不应该创建索引的的这些列具有下列特点:
- 查询中很少使用或者参考的列。
- 只有很少数据值的列。因为这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
- 定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
- 当修改性能远远大于检索性能时。因为修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。
三种索引:唯一索引、主键索引和聚集索引
唯一索引:唯一索引是不允许其中任何两行具有相同索引值的索引。当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中创建重复键值的新数据。例如,如果在employee表中职员的姓(lname)上创建了唯一索引,则任何两个员工都不能同姓。
主键索引:数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。
聚集索引:在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。
如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。
B树、B+树区别,索引为何使用B+树
根据B-Tree的定义,可知检索一次最多需要访问h个节点。利用磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。
为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。
B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)。一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小(通常不超过3)。
而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,所以红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差很多。
综上所述,用B-Tree作为索引结构效率是非常高的。
聚集索引与非聚集索引(使用非聚集索引的查询过程)
事务的ACID(原子性、一致性、隔离性、持久性)
原子性(Atomicity):整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Correspondence):在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。(实体完整性、参照完整性、用户自定义完整性)
隔离性(Isolation):隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性(Durability):在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
7.事务隔离级别和各自存在的问题(脏读、不可重复读、幻读)和解决方式(间隙锁及MVCC)
8.乐观锁和悲观锁、行锁与表锁、共享锁与排他锁(inndob如何手动加共享锁与排他锁)
如果现在只有一张火车票,怎么让所有人都看见但是只有一个人能购买成功 (这里就是悲观锁乐观锁的应用处理并发问题)
9.MVCC(增加两个版本号)及delete、update、select时的具体控制
10.死锁判定原理和具体场景
11.查询缓慢和解决方式(explain、慢查询日志、show profile等)
drop、truncate、delete区别
基本区别:
- drop 直接删掉表;
- truncate 删除表中数据,再插入时自增长 id 又从1开始;
- delete 删除表中数据,可以加 where 字句。
具体区别:
- delete 语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。truncate 则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。
- 表和索引所占空间。当表被 truncate 后,这个表和索引所占用的空间会恢复到初始大小,而DELETE操作不会减少表或索引所占用的空间。drop语句将表所占用的空间全释放掉。
- 一般而言,drop > truncate > delete
- 应用范围。truncate 只能对 table,delete 可以是 table 和 view
- truncate 和 delete 只删除数据,而 drop 则删除整个表(结构和数据)。
- truncate 与不带 where 的 delete:只删除数据,而不删除表的结构(定义)。
- drop 将删除表的结构被依赖的约束(constrain)、触发器(trigger)、索引(index),依赖于该表的存储过程/函数将被保留,但其状态会变为 invalid。
- delete 是 DML(data maintain Language),这个操作会被放到 rollback segment中,事务提交后才生效。如果有相应的 tigger,执行的时候将被触发。
- truncate、drop 是 DLL(data define language),操作立即生效,原数据不放到 rollback segment中,不能回滚。
- 在没有备份情况下,谨慎使用 drop 与 truncate。要删除部分数据行采用 delete 且注意结合 where 来约束影响范围。回滚段要足够大。要删除表用 drop;若想保留表而将表中数据删除,且与事务无关,用 truncate 即可实现;如果与事务有关,或想触发 trigger,还是用 delete。
- truncate 速度快,而且效率高,因为 truncate 在功能上与不带 where 子句的 delete 语句相同:二者均删除表中的全部行。但 truncate 比 delete 速度快,且使用的系统和事务日志资源少。delete 语句每次删除一行,并在事务日志中为所删除的每行记录一项。truncate 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
- truncate 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用的计数值重置为该列的种子。如果想保留标识计数值,请改用 delete。如果要删除表定义及其数据,请使用 drop 语句。
- 对于由 FOREIGN KEY 约束引用的表,不能使用 truncate,而应使用不带 where 子句的 delete 语句。由于 truncate 不记录在日志中,所以它不能激活触发器。
查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序
集合查询有哪些
union:并操作
intersect:交操作
except:差操作
union
查询计算机系的所有学生和年龄大于19岁的学生的并集:
1 | SELECT * FROM student WHERE dept='CS' |
等价于:
1 | SELECT * FROM student |
intersect
查询计算机系中年龄大于19岁的学生:
1 | SELECT * FROM student WHERE dept='CS' |
等价于:
1 | SELECT * FROM student |
except
查询计算机系中年龄大于19岁的学生:
1 | SELECT * FROM student WHERE dept='CS' |
等价于:
1 | SELECT * FROM student |
注意:MySQL 中没有求交集和差集的功能,只能用其他关键字达到类似功能。
求交集:
1 | SELECT a.member_id, a.name FROM a |
求差集:
1 | SELECT t1.* FROM t1 |
UNION 和 UNION ALL 的区别
UNION 将多个查询结果合并起来,系统自动去掉重复元组,在排序时会按照字段的顺序。
UNION ALL 则会保留重复的元组,在排序时只是简单的将两个结果合并后就返回。