数据库三大范式?
什么是关系型数据库?
答:是一种建立在关系模型基础上的数据库,关系模型表明了数据库中数据之间的联系(一对多、一对一、多对多等)。关系型数据库中数据被放在了各种表中,表中的每一行就标识一条数据。
大部分关系型数据库都使用SQL语句来操作数据库,并且基本都支持四大特性(ACID)
A:原子性:事务中的操作要么全做要么全不做;C:一致性,事务开始和结束时,数据库保持一致性,比如转账前后的总金额一致;I:隔离性:事务之间相互隔离,不会互相打扰。D:持久性,事务一旦提交就是永久性的。其中A和I是为了实现C和D。
char和varchar之间的区别是什么?
char是定长字符串,varchar是可变长字符串。char规定了长度之后会进行填充达到指定的长度,varchar只是指定了最大存储的长度,但存储的时候只会存数据大小的长度,并且记录数据的长度。varchar(100)和 varchar(10)都是变长类型,只是支持的最大长度不一样。
decimal和double的区别
decimal是定点数,可以存精确的小数,double只能存小数的近似值。和金钱相关的用decimal。
null和‘ ’之间的区别:
null表示确实或者不确定的值,而“”是空的字符串。
使用聚合函数时,null会被忽略,而count(*)时,又会被包含在里面。
在进行比较时,null只能用 is null 和is not null来判断,因为它不是一个具体的数据类型,而“”可以用等于或者不等于来判断。
SQL语句在MySQL中的执行过程
MySQL的基础架构主要包括server层和存储引擎层,存储引擎层主要负责对数据的存储和读取。server层包括连接器、查询缓存、分析器、优化器和执行器。
一条SQL开始执行时,首先会经过连接器验证用户的权限,如果具备权限的话建立连接,会查询缓存,缓存存在则直接返回结果,否则进行词法、句法分析,判断有无语法错误,然后经过优化器,选择合适的执行方案,比如利用什么索引,确定好执行方案之后,通过存储引擎执行对数据的操作。
MySQL的存储引擎,innodb与myisam之间的区别
默认的是innodb,5.5版本之前是myisam。它们两者之间的区别主要在于innodb支持事务,能够支持提交和事务回滚,myisam不支持。innodb支持行级锁和MVCC,而myisam不支持MVCC且只支持表级锁,因此性能没有innodb好。并且innodb崩溃后重启可以恢复到崩溃前的数据,myisam不支持。innodb支持外键,myisam也不支持。innodb使用聚簇索引,myisam使用非聚簇索引,即索引文件和数据文件是分开的。
总的来说就是:事务、MVCC、行级锁、外键、数据崩溃恢复、是否使用聚簇索引。
因此想要数据更稳定,支持数据崩溃恢复的话,innodb无疑是更好的。
事务有哪些特性:ACID 原子性、一致性 、隔离性、持久性
并行事务会发生哪些问题:
脏读:一个事务B读到了未提交事务A中的数据,如果事务A发生回滚,那就产生了脏读。
不可重复读:一个事务读取数据时得到的结果不一样,可能是在两次读取期间有别的事务作出修改并提交了。
幻读:一个事务中两次查询的结果集不一样,有可能是别的事物insert或者delete了数据。
MySQL中的隔离级别
MySQL中有四种不同的隔离级别,分别是读未提交:事务未提交时,做出的变更就能被看到;读已提交:事务提交之后,做出的变更才能被看到;可重复读:事务提交前能够读取的数据跟开启时的数据是一致的;串行化:通过加读写锁来控制对数据的访问和修改,强制任务串行执行。如果多个事务访问冲突,必须等前一个事务执行完成才能执行,隔离级别最高,可以完全解决幻读,但效率显然降低。
是否能解决 | 读未提交 | 读已提交 | 可重复读 | 串行化 |
提交之后才能看到变化 | 事务执行过程中的数据跟开启事务时的数据是一致的 | 对记录加上读写锁 | ||
脏读 | × | √ | √ | √ |
不可重复读 | × | × | √ | √ |
幻读 | × | × | × | √ |
innodb的默认隔离级别是可重复读,通过MVCC多版本控制和记录锁和间隙锁来解决大部分幻读问题。
针对快照读(select语句),用MVCC多版本控制来解决幻读。可重复读在事务开启之前会生成一个快照read_view,包含了几个字段,比如创建该快照的事务ID create_trix_id,当前事务开启时活跃的事务ID列表trix_ids,当前活跃事务的最小ID min_trix_id,和当前事务对应的下一个事务ID max_trix_id。此外数据行里面除了数据之外,还有两个额外的字段分别是,最后一次对数据作出修改的事务ID和指向该数据旧版本的指针地址。因此创建快照之后,我们可以根据快照的trix_id划分为,已提交的事务,正在活跃的事务,和尚未开启的事务。一个事务去访问数据的时候:
如果数据行的trix_id<min_trix_id,则记录可以访问;
如果trix_id>max_trix_id,说明记录是在开启该事务之后修改的,不可见,需要访问旧版本;
如果min_trix_id<trix_id<max_trix_id,去检查是否在trix_ids列表中,如果在的话,说明事务仍然活跃,数据不可见,需要通过指针查询旧版本数据,如果不在,说明已经提交了,可以访问该数据。
通过多个版本的控制来决定当前事务访问的都是开启事务时的数据,解决幻读问题。
chat的回答更好:
利用MVCC解决幻读,幻读是什么;MVCC为每行数据维护了多个版本;事务开始时会生成快照,快照中有几个字段;根据这个字段个数据行的事务ID来判断数据是否对当前事务可见。保证了在事务内部查询数据时总能保持一致的结果。
针对当前读(select for update、insert、delete、update等),是通过next_key lock(间隙锁+记录锁)解决幻读,执行当前读时会加上该锁,在这个范围内插入数据时会被阻塞,无法插入成功,这就很好地避免了幻读。
RR隔离级别没有解决幻读,只是在很大程度上避免了幻读。