删除命令从数据库中移除表,包括所有数据行、索引和权限,而且这个命令无法撤销。
因此,当不再需要一张表时,使用删除;若想删除部分数据行,则使用删除;若要保留表而删除所有数据,则使用截断。
隔离等级脏读不可重复读虚读 READ-UNCOMMITTED未提交读 READ-COMMITTED提交读 REPEATABLE-READ可重复读 SERIALIZABLE可串行化读
MySQL InnoDB存储引擎默认支持的隔离等级是 REPEATABLE-READ(可重复读)
需要注意的是:与 SQL标准有所不同的是,InnoDB存储引擎在 REPEATABLE-READ(可重复读)事务隔离等级下使用的是 Next-Key Lock锁算法,从而可以避免虚读的发生,这与其他数据库系统(如 SQL Server)有所不同。因此,InnoDB存储引擎默认支持的隔离等级是 REPEATABLE-READ(可重复读)已足以完全保障事务的隔离性需求,即达到了 SQL标准的SERIALIZABLE(可串行化)隔离等级。
因为隔离等级越低,事务请求的锁越少,所以大部分数据库系统的隔离等级都是READ-COMMITTED(读取提交内容):,但是要知道的是InnoDB存储引擎默认使用 REPEATABLE-READ(可重复读)并不会有任何性能损失。
InnoDB存储引擎在分布式事务的情况下通常使用SERIALIZABLE(可串行化)隔离等级。
主要原因:B+树只需遍历叶子节点就能实现整棵树的遍历,而且在数据库中基于范围的查询非常频繁,而B树只能中序遍历所有节点,效率太低。
文件与数据库都需要较大的存储空间,也就是说,它们都不可能全部存储在内存中,所以需要存储到磁盘上。而所谓索引,则是为了数据的快速定位与查找,因此索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数,因此B+树相比B树更为合适。数据库系统巧妙地利用了局部性原理与磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入,而红黑树这种结构,高度明显要深得多,并且由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性。
最重要的是,B+树还有一个最大的好处:便于扫描库。
B树必须用中序遍历的方法按序扫描库,而B+树直接从叶子节点挨个扫描一遍就完了,B+树支持range-query非常方便,而B树不支持,这是数据库选用B+树的最主要原因。
B+树查找效率更加稳定,B树有可能在中间节点找到数据,稳定性不足。
B+tree的磁盘读写代价更低:B+tree的内部节点并没有指向关键字具体信息的指针(红色部分),因此其内部节点相对B树更小。如果把所有同一内部节点的关键字存放在同一块盘中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多,相对来说IO读写次数也就降低了;
B+tree的查询效率更加稳定:由于内部节点并不是最终指向文件内容的节点,而只是叶子节点中关键字的索引,所以,任何关键字的查找必须走一条从根节点到叶子节点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当;
视图是一种虚拟的表,通常是有一个表或者多个表的行或列的子集,具有和物理表相同的功能游标是对查询出来的结果集作为一个单元来有效处理。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。
而在 MySQL中,恢复机制是通过回滚日志(undo log)实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后在对数据库中的对应行进行写入。当事务已经被提交之后,就无法再次回滚了。
回滚日志作用:1)能够在发生错误或者用户执行 ROLLBACK时提供回滚相关的信息 2)在整个系统发生崩溃、数据库进程直接被杀死后,当用户再次启动数据库进程时,还能够立刻通过查询回滚日志将之前未完成的事务进行回滚,这也就需要回滚日志必须先于数据持久化到磁盘上,是我们需要先写日志后写数据库的主要原因。
InnoDB
MyISAM
总结
数据库并发会引发脏读、幻读、丢弃修改、不可重复读这四个常见问题,其中:
脏读:在第一个修改事务和读取事务进行的时候,读取事务读到的数据为100,这是修改之后的数据,但是之后该事务满足一致性等特性而做了回滚操作,那么读取事务得到的结果就是脏数据了。
幻读:一般是T1在某个范围内进行修改操作(增加或者删除),而T2读取该范围导致读到的数据是修改之间的了,强调范围。
丢弃修改:两个写事务T1 T2同时对A=0进行递增操作,结果T2覆盖T1,导致最终结果是1而不是2,事务被覆盖
不可重复读:T2读取一个数据,然后T1对该数据做了修改。如果 T2再次读取这个数据,此时读取的结果和第一次读取的结果不同。
第一个事务首先读取var变量为50,接着准备更新为100的时,并未提交,第二个事务已经读取var为100,此时第一个事务做了回滚。最终第二个事务读取的var和数据库的var不一样。
T1读取某个范围的数据,T2在这个范围内插入新的数据,T1再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
T1和 T2两个事务都对一个数据进行修改,T1先修改,T2随后修改,T2的修改覆盖了 T1的修改。例如:事务1读取某表中的数据A=50,事务2也读取A=50,事务1修改A=A+50,事务2也修改A=A+50,最终结果A=100,事务1的修改被丢失。
T2读取一个数据,T1对该数据做了修改。如果 T2再次读取这个数据,此时读取的结果和第一次读取的结果不同。
T2获取一个数据,T1对该数据进行了变更。若T2再次获取这个数据,此时获取的数值与首次获取的数值存在差异。
悲观锁定,先锁定资源,再执行业务操作,通常使用诸如SELECT… FOR UPDATE等语句对数据进行锁定,以防止其他事务意外更改数据。当数据库执行SELECT… FOR UPDATE时,会锁定被SELECT中的数据行的行锁,SELECT FOR UPDATE获取的行锁会在当前事务结束时自动解除,因此必须在事务中执行。
乐观锁定,先执行业务操作,仅在最后实际更新数据时检查数据是否被更改。Java并发包中的AtomicFieldUpdater类似,也是利用CAS机制,不会对数据加锁,而是通过对比数据的时间戳或版本号,实现乐观锁所需的版本判断。
分库与分表的目的是为了减轻数据库单库单表的负担,提升查询性能,缩短查询时间。
通过分表,可以减轻数据库单表的负担,将压力分散到不同的表上,同时由于不同表上的数据量减少,可以提高查询性能,缩短查询时间,此外,还可以大大缓解表锁的问题。分表策略可以概括为垂直拆分和水平拆分:
水平分表:取模分表属于随机分表,而时间维度分表则属于连续分表。如何设计好垂直拆分,我的建议:将不常用的字段单独拆分到另外一张扩展表。将大文本的字段单独拆分到另外一张扩展表,将不经常修改的字段放在同一张表中,将经常变更的字段放在另一张表中。对于海量用户场景,可以考虑取模分表,数据相对均匀,不容易出现热点和并发访问的瓶颈。
库内分表仅解决了单表数据过大的问题,但并没有将单表的数据分散到不同的物理机上,因此并不能减轻MySQL服务器的压力,仍然存在同一个物理机上的资源竞争和瓶颈,包括CPU、内存、磁盘IO、网络带宽等。
分库与分表带来的分布式难题与应对策略数据迁移与扩容问题——一般做法是通过程序先读取数据,然后按照指定的分表策略将数据写入到各个分表中。分页与排序问题——需要在不同的分表中将数据进行排序并返回,并将不同分表返回的结果集进行汇总和再次排序,最后再返回给用户。
不可重复读的关键在于修改,幻读的关键在于新增或删除。
视图是虚拟的表,与包含数据的表不同,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的SQL操作,隐藏具体细节,保护数据;视图创建后,可以使用与表相同的方式使用它们。
视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by则对视图再次order by将被覆盖。
创建视图:create view xxx as xxxx
对于某些视图如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。
B+tree的磁盘读写成本更低,B+tree的查询效率更加稳定数据库索引采用B+树而不是B树的主要原因:B+树只需遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询非常频繁,而B树只能中序遍历所有节点,效率太低。
B+树的特点
在最频繁使用的、用以缩小查询范围的字段,需要排序的字段上建立索引。不宜:1)对于查询中很少涉及的列或者重复值比较多的列 2)对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等。
如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。
我们知道在InnoDB存储引擎中,如果不是主键索引,叶子节点存储的是主键+列值。最终还是要“回表”,也就是要通过主键再次查找,这样就会比较慢。覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!
举例:
学号姓名性别年龄系别专业 20020612李辉男20计算机软件开发 20060613张明男18计算机软件开发 20060614王小玉女19物理力学 20060615李淑华女17生物动物学 20060616赵静男21化学食品化学 20060617赵静女20生物植物学
主键为候选键的子集,候选键为超键的子集,而外键的确定是相对于主键的。