数据库知识梳理

2023-05-16

概述:

对数据库索引、数据库锁、数据库事务、MySql优化等基础知识梳理。

1、数据库范式

(1)第一范式:列不可分,eg:【联系人】(姓名,性别,电话),一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF;

(2)第二范式:有主键,且其他属性完全依赖主键。eg:订单明细表【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName),Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID,不符合2NF;

(3)第三范式:无传递依赖(非主键列A依赖于非主键列B,非主键B依赖于主键情况)。eg:订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID),CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。

2、数据库索引

索引是对数据库表中一个或多个的值进行排序数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B_Tree及其变种.索引加速了数据访问,因为存储引擎不会再去扫描整张表得到需要的数据;相反他从根节点开始,根节点保存了子节点的指针,存储引擎根据指针快速寻找数据。

 

上图显示了一种索引方式。左边是数据库中的数据表,有col1和col2两个字段,一共有15条记录;右边是以col2列为索引列的B_TREE索引,每个节点包含索引的键值和对应数据表地址的指针,这样就可以通过B_TREE在O(logn)的时间复杂度内获取相应的数据,这样明显地加快了检索的速度。

2.1索引底层实现及优化

在数据结构中,我们最为常见的搜索结构就是二叉搜索树和AVL树(高度平衡的二叉搜索树,为了提高二叉搜索树的效率,减少树的平均搜索长度)了。然而,无论二叉搜索树还是AVL树,当数据量比较大时,都会由于树的深度过大而造成I/O读写过于频繁,进而导致查询效率低下,因此对于索引而言,多叉树结构成为不二选择。特别地,B-Tree的各种操作能使B树保持较低的高度,从而保证高效的查找效率。

2.1.1 B-Tree(平衡多路查找树)

B_Tree是一种平衡多路查找树,是一种动态查找效率很高的树形结构。B_TREE中所有结点的孩子结点的最大值称为B_TREE的阶,B_TREE的阶通常用m表示,简称为m叉树。一般来说,应该是m>=3。一颗m阶的B_TREE或是一颗空树,或者是满足下列条件的m叉树:

(1)树中每个节点最多有m个孩子节点

(2)若根节点不是叶子节点,则根节点至少有两个孩子节点。

(3)除根节点外,其他结点至少有(m/2的上界)个孩子节点。

(4)结点结构如下图:其中,n为结点中关键字个数,(m/2的上界)-1<=n<=m-1;di(1<=i<=n)为该节点n个关键字值的第i个,且di<d(i+1);ci(0<=i<=n)为该结点孩子结点的指针,ci所指向的节点的关键字均大于等于di且小于d(i+1)。

 

(5)所有叶节点都在同一层上,且不带信息(可以看做是外部节点或查找失败的结点,实际上这些节点不存在,指向这些节点的指针为null)

案例:

下图是一棵4阶B_TREE,4叉树结点的孩子结点的个数范围[2,4]。其中,有2个结点有4个孩子结点,有1个结点有3个孩子结点,有5个结点有2个孩子结点。

 

B_TREE的查找类似二叉排序树的查找,所不同的是B-树每个结点上是多关键码的有序表,在到达某个结点时,先在有序表中查找,若找到,则查找成功;否则,到按照对应的指针信息指向的子树中去查找,当到达叶子结点时,则说明树中没有对应的关键码。由于B_TREE的高检索效率,B-树主要应用在文件系统和数据库中,对于存储在硬盘上的大型数据库文件,可以极大程度减少访问硬盘次数,大幅度提高数据检索效率。

2.1.2 B+Tree:(InnoDB存储引擎的索引实现

B+Tree是应文件系统所需而产生的一种B_TREE树的变形树。一棵m阶的B+树和m阶的B_TREE的差异在于以下三点:

(1)n棵子树的结点中含有n个关键字;

(2)所有的叶子结点中包含了全部关键码的信息,及指向含有这些关键码记录的指针,且叶子结点本身依关键码的大小自小而大的顺序链接。

(3)非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键码。

案例:

下图为一棵3阶的B+树。通常在B+树上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点。因此可以对B+树进行两种查找运算:一种是从最小关键字起顺序查找另一种是从根节点开始,进行随机查找。

B+树上进行随机查找、插入和删除的过程基本上与B-树类似。只是在查找时,若非终端结点上的关键码等于给定值,并不终止,而是继续向下直到叶子结点。因此,对于B+树,不管查找成功与否,每次查找都是走了一条从根到叶子结点的路径。

 

2.1.3 为什么说B+tree比B树更适合实际应用中操作系统文件索引和数据库索引?

1)B+tree的磁盘读写代价更低:B+tree的内部结点并没有指向关键字具体信息的指针(红色部分),因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多,相对来说IO读写次数也就降低了;

2)B+tree的查询效率更加稳定:由于内部结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引,所以,任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当

3)数据库索引采用B+树而不是B树的主要原因:B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,B树只能中序遍历所有节点,效率太低。

2.1.4 文件索引和数据库索引为什么使用B+树?

1)文件与数据库都是需要较大的存储,也就是说,它们都不可能全部存储在内存中,故需要存储到磁盘上。而所谓索引,则为了数据的快速定位与查找,那么索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数,因此B+树相比B树更为合适。

2)数据库系统巧妙利用了局部性原理与磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入,而红黑树这种结构,高度明显要深的多,并且由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性。

3)最重要的是,B+树还有一个最大的好处:方便扫库B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query非常方便,而B树不支持,这是数据库选用B+树的最主要原因。

2.2索引优点

(1)大大加快数据的检索速度,这也是创建索引的最主要的原因;

(2)加速表与表之间的连接

(3)在使用分组和排序子句进行数据检索时,同样可以减少查询中分组和排序的时间;

(4)通过创建唯一性索引,可保证数据表中每一行数据的唯一性。

2.3什么情况下设置了索引但无法使用?

(1)“%(表示任意0个或多个字符)”开头的LIKE语句,模糊匹配;

(2)Or语句前后没有同时使用索引。

(3)数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型);

(4)对于多列索引,必须满足最左匹配原则(eg:多列索引col1、col2和col3,则 索引生效的情形包括 col1或col1,col2或col1,col2,col3)。

2.4什么样字段适合创建索引?

1)经常作为查询选择的字段。

2)经常作为表连接的字段。

3)经常出现在order by,group by,distinct后面的字段。

2.5 创建索引时需要注意什么?

1)非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂你应该用0、一个特殊的值或者一个空串代替空值;

2)取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;

3索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

2.6索引缺点?

(1)时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度;

2)空间方面:索引需要占物理空间。

2.7索引分类?

(1)普通索引和唯一性索引:索引列的值的唯一性。

(2)单个索引和复合索引:索引列所包含的列数。

(3)聚簇索引与非聚簇索引:聚簇索引按照数据的物理存储进行划分的对于一堆记录来说,使用聚集索引就是对这堆记录进行堆划分,即主要描述的是物理上的存储。正是因为这种划分方法,导致聚簇索引必须是唯一的。聚集索引可以帮助把很大的范围,迅速减小范围。但是查找该记录,就要从这个小范围中Scan了;

非聚集索引是把一个很大的范围,转换成一个小的地图,然后你需要在这个小地图中找你要寻找的信息的位置,最后通过这个位置,再去找你所需要的记录。

2.8主键、自增主键、主键索引与唯一索引概念区别?

1)主键:指字段唯一、不为空值的列;

2)主键索引:指的就是主键,主键是索引的一种,是唯一索引的特殊类型。创建主键的时候,数据库默认会为主键创建一个唯一索引

3)自增主键:字段类型为数字、自增、并且是主键;

4)唯一索引:索引列的值必须唯一,但允许有空值。主键是唯一索引,这样说没错;但反过来说,唯一索引也是主键就错误了,因为唯一索引允许空值,主键不允许有空值,所以不能说唯一索引也是主键。

2.9主键是聚集索引吗?主键与索引有什么区别?

主键是一种特殊的唯一性索引,其可以是聚集索引,也可以是非聚集索引。SQLServer中,主键的创建必须依赖于索引,默认创建的是聚集索引,但也可以显式指定为非聚集索引。

InnoDB作为MySQL存储引擎时,默认按照主键进行聚集,如果没有定义主键,InnoDB会试着使用唯一的非空索引来代替。如果没有这种索引,InnoDB就会定义隐藏的主键然后在上面进行聚集。所以,对于聚集索引来说,你创建主键的时候,自动就创建了主键的聚集索引。

3、数据库事务

事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。

3.1事务的特征

(1)原子性(Atomicity):事务所包含的一系列操作要么全部成功执行,要么全部回滚。

(2)一致性(Consistency):事务的执行结果必须使数据库从一个状态到另一个一致性状态。

(3)隔离性(Isolation):并发执行的事务之间不能相互影响。

(4)持久性(Durability):事务一旦提交,对数据库中数据的改变时永久性的。

3.2事务并发带来的问题?

(1)脏读:一个事务读取了另一个事务未提交的数据。

(2)不可重复读:重点时候修改,同样条件下两次读取结果不同。也就是说,读取的数据可以被其他事务修改。

(3)幻读:重点在于新增或删除,同样条件下两次读出来的记录数不一样。

3.3隔离级别?

隔离级别决定了一个session中的事务可能对另一个session中的事务的影响,ANSI标准定义了4个隔离级别Mysql的InnoDB都支持,分别是:

(1)READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取另一个事务还没commit的数据,这样可能会提高性能,但是会导致脏读问题;

(2)READ COMMITTED:在一个事务中只允许对其它事务commit的记录可见,该隔离级别不能避免不可重复读问题;

(3)REPEATABLE READ:在一个事务开始后,其他事务对数据库的修改在本事务中不可见,直到本事务commit或rollback。但是,其他事务的insert/delete操作对该事务是可见的,也就是说,该隔离级别并不能避免幻读问题。在一个事务中重复select的结果一样,除非本事务中update数据库。

(4)SERIALIZABLE:最高级别隔离,只允许事务串行。

3.4 Mysql的事务支持

Mysql的事务支持不是绑定在Mysql服务器本身,而是与存储引擎相关;

(1)MyISAM:不支持事务,用于只读程序提高性能。

(2)InnoDB:支持ACID事务、行级锁、并发;

(3)Berkeley DB:支持事务。

4、实践中如何优化MySQL

MySQl的优化主要涉及SQL语句及索引的优化、数据表结构的优化、系统配置的优化和硬件的优化四方面,如下图所示:

 

4.1 SQL语句及索引的优化

1、SQL语句优化:

SQL语句优化主要包括三个问题,即如何发现问题的SQL、如何分析SQL执行计划如何优化SQL。

1)如何发现问题SQL?(通过MySQL慢查询日志对由效率问题的sql进行监控)

MySQL的慢查询日志MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10s以上的语句。慢查询日志的相关参数如下所示:

 

通过MySQL的慢查询日志,我们可以查询出执行的次数多占用的时间长的SQL、可以通过pt_query_disgest(一种mysql慢日志分析工具)分析Rows examine(MySQL执行器需要检查的行数)项去找出IO大SQL以及发现未命中索引SQL,对于这些SQL,都是我们优化的对象。

(2)通过explain查询分析SQL的执行计划

使用EXPLAIN关键字可以知道MySQL是如何处理你的SQL语句的,以便分析查询语句或是表结构的性能瓶颈。通过explain命令可以得到表的读取顺序、数据读取操作的操作类型、哪些索引可以使用、哪些索引被实际使用、表之间的引用以及每张表有多少行被优化器查询等问题。当扩展列extra出现Using filesort和Using temporay,则往往表示SQL需要优化了。

(3)SQL语句的优化

1)优化insert语句:一次插入多值;

2)尽量避免 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描;

3)应尽量避免在 where 子句中对字段进null值判断,否则将导致引擎放弃使用索引而进行全表扫描;

4)优化嵌套查询子查询可以被更有效率的连接(Join)替代;

5)尽量用exists代替in。

2、索引优化:

建议在经常作查询选择的字段、经常作表连接的字段以及经常出现在order by、group by、distinct 后面的字段中建立索引。但必须注意以下几种可能会引起索引失效的情形:

1)以“%(表示任意0个或多个字符)”开头的LIKE语句,模糊匹配;

2)or语句前后没有同时使用索引;

3)数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型);

4)对于多列索引,必须满足最左匹配原则(eg,多列索引col1、col2和col3,则 索引生效的情形包括col1或col1,col2或col1,col2,col3)。

4.2 数据库表结构优化

数据库表结构优化包括合适的数据类型、表的范式的优化、表的垂直拆分和表的水平拆分。

1、选择合适的数据类型

1)使用较小的数据类型解决问题。

2)使用简单地数据类型(mysql处理int要比varchar容易)

3)尽量使用not null 定义字段;

4)尽量避免使用text类型,非用不可时最好考虑分表;

2、表的范式优化

一般情况下,表的设计应该遵循三大范式。

3、表的垂直拆分

把含有多个列的表拆分成多个表,解决表宽度问题,具体包括以下几种拆分手段:

(1)把不常用的字段单独放在同一个表中;

(2)把大字段独立放入一个表中;

(3)把经常使用的字段放在一起; 

这样做的好处是非常明显的,具体包括:拆分后业务清晰,拆分规则明确、系统之间整合或扩展容易、数据维护简单。

4、表的水平拆分

表的水平拆分用于解决数据表中数据过大的问题,水平拆分每一个表的结构都是完全一致的。一般地,将数据平分到N张表中的常用方法是:对ID进行hash运算,如果要拆分成5个表,mod(id,5)取0~4个值;针对不同的hashID将数据存入不同的表中;

表的水平拆分会带来一些问题和挑战,包括跨分区表的数据查询、统计及后台报表的操作等问题,但也带来了一些切实的好处:

(1)表分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度;

(2)表中数据本来就有独立性,例如表中分别记录各个地区的数据或不同时期的数据,特别是有些数据常用,而另外一些数据不常用。

(3)需要把数据存放到多个数据库中,提高系统的总体可用性(分库,鸡蛋不能放在同一个篮子里)。

4.3 系统配置的优化

1)操作系统配置的优化:增加TCP支持的队列数。

2)mysql配置文件优化:Innodb缓存池设置(innodb_buffer_pool_size,推荐总内存的75%)和缓存池的个数innodb_buffer_pool_instances)

4.4 硬件优化

1)CPU:核心数多并且主频高。

2)内存:增大内存。

3)磁盘配置和选择:磁盘性能。

5、NOSQL数据库 —— Redis

Redis是一个基于内存的且持久化、高性能的Key-Value NoSQL 数据库其支持丰富数据类型(string,list,set,sorted set,hash),常被用作缓存的解决方案。Redis具有以下显著特点:

1)速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

2)支持丰富数据类型,支持string,list,set,sorted set,hash;

3)支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行;

4)丰富的特性:可用于缓存消息key设置过期时间,过期后将会自动删除。

 

Redis作查询缓存需要注意考虑以下几个问题,包括防止脏读序列化查询结果为查询结果生成一个标识怎么使用四个问题,具体如下:

(1)防止脏读

对一张表的查询结果放在一个哈希结构里,当对这个表进行修改、删除或者更新时,删除该哈希结构。对这张表所有的操作方法,使用注解进行标记,例如:

 

我们缓存了查询结果,那么一旦数据库中的数据发生变化,缓存的结果就不可用了。为了实现这一保证,可以在执行相关表的更新查询(update,delete,insert)查询前,让相关的缓存过期。这样下一次查询时程序就会重新从数据库中读取新数据缓存到redis中。那么问题来了,在执行一条insert前我怎么知道应该让哪些缓存过期呢?对于Redis,我们可以使用Hash结构,让一张表对应一个Hash所有在这张表上的查询都保存到该Hash下。这样当表数据发生变动时,直接让Set过期即可。我们可以自定义一个注解,在数据库查询方法上通过注解的属性注明这个操作与哪些表相关,这样在执行过期操作时,就能直接从注解中得知应该让哪些Set过期了。

(2)序列化查询结果

利用JDK自带的ObjectInputStream/ObjectOutputStream将查询结果序列化成字节序列,即需要考虑Redis的实际存储问题。

(3)为查询结果生成一个标识

被调用的方法所在的类名,被调用的方法的方法名,该方法的参数三者共同标识一条查询结果。也就是说,如果两次查询调用的类名、方法名和参数值相同,我们就可以确定这两次查询结果一定是相同的(在数据没有变动的前提下)。因此,我们可以将这三个元素组合成一个字符串做为key,就解决了标识问题。

(4) AOP 方式使用Redis

①方法被调用之前,根据类名、方法名和参数值生成Key;

②通过Key向Redis发起查询;

③如果缓存命中,则将缓存结果反序列化作为方法调用的返回值 ,并将其直接返回;

④如果缓存未命中,则继续向数据库中查询,并将查询结果序列化存入redis中,同时将查询结果返回。

例如,插入删除缓存逻辑如下:

 

6、什么是存储过程?有哪些优缺点?

存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合。进一步地说,存储过程是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查)然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。存储过程具有以下特点:

(1)存储过程只在创建时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行效率;

(2)sql有变动时,可以只修改数据库中的存储过程而不必修改代码;

(3)减少网络传输,在客户端调用一个存储过程当然比执行一串SQL传输的数据量要小;

(4)通过存储能够能够使没有权限的用户在控制之下间接地存取数据库,从而确保数据的安全。

7、简单说一说drop、delete与truncate的区别?

SQL中的drop、delete、truncate都表示删除,但是三者有一些差别:

(1)Delete用来删除表的全部或者一部分数据行,执行delete之后,用户需要提交(commmit)或者回滚(rollback)来执行删除或者撤销删除, delete命令会触发这个表上所有的delete触发器;

(2)Truncate删除表中的所有数据,这个操作不能回滚,也会触发这个表上的触发器TRUNCATE比delete更快,占用的空间更小;

(3)Drop命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的DML触发器也不会被触发,这个命令也不能回滚。

因此在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate。

8、什么叫视图?游标是什么?

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

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

在操作mysql的时候,我们知道MySQL检索操作返回一组称为结果集的行。这组返回的行都是与 SQL语句相匹配的行(零行或多行)。使用简单的 SELECT语句,例如,没有办法得到第一行、下一行或前 10行,也不存在每次一行地处理所有行的简单方法(相对于成批地处理它们)。有时,需要在检索出来的行中前进或后退一行或多行。这就是使用游标的原因。游标(cursor)是一个存储在MySQL服务器上的数据库查询,它不是一条 SELECT语句,而被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。

9、什么是触发器?

触发器是与表相关的数据库对象,满足定义条件时触发,并执行触发器中定义的语句集合。触发器的这种特性可以协助应用在数据库端确保数据库的完整性。

10、MySQL中的悲观锁与乐观锁的实现

悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念。

10.1 悲观锁

(1)悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为所有的操作均会导致并发安全问题,因此要先确保获取锁成功再进行业务操作。通常来讲,在数据库上的悲观锁需要数据库本身提供支持即通过常用的select … for update操作来实现悲观锁。当数据库执行select … for update时会获取被select中的数据行的行锁,因此其他并发执行的select … for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。

这里需要特别注意的是,不同的数据库select… for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外,mysql还有个问题是: select… for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此,如果在mysql中用悲观锁务必要确定使用了索引,而不是全表扫描。

10.2 乐观锁

乐观锁的特点先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过,若未被更新过,则更新成功;否则,失败重试。乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号或者时间戳,然后按照如下方式实现:

 

乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据对比版本号确认与之前获取的相同,并更新版本号,即可确认这其间没有发生并发的修改。如果更新失败,即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。

10.3 乐观锁与悲观锁的应用场景

一般情况下,读多写少更适合用乐观锁,读少写多更适合用悲观锁乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能。

11、JDBC 对事务的支持

对于JDBC而言,每条单独的语句都是一个事务,每个语句后都隐含一个commit。实际上,Connection 提供了一个auto-commit的属性来指定事务何时结束。auto-commit为true时,当每个独立SQL操作的执行完毕,事务立即自动提交,也就是说,每个SQL操作都是一个事务;当auto-commit为false时,每个事务都必须显式调用commit方法进行提交,或者显式调用rollback方法进行回滚。auto-commit默认为true。

 

为了能够将多条SQL当成一个事务执行,必须首先通过Connection关闭auto-commit模式,然后通过Connection的setTransactionIsolation()方法设置事务的隔离级别,最后分别通过Connection的commit()方法和rollback()方法来提交事务和回滚事务。

12、MySQL存储引擎中的MyISAM和InnoDB区别详解

MySQL 5.5之前,MyISAM是mysql的默认数据库引擎,其由早期的ISAM(Indexed Sequential Access Method:有索引的顺序访问方法)所改良。虽然MyISAM性能极佳,但却有一个显著的缺点:不支持事务处理。不过,MySQL也导入了另一种数据库引擎InnoDB,以强化参考完整性与并发违规处理机制,后来就逐渐取代MyISAM。

InnoDB是MySQL的数据库引擎之一,其由Innobase oy公司所开发,2006年五月由甲骨文公司并购。与传统的ISAM、MyISAM相比,InnoDB的最大特色就是支持ACID兼容的事务功能类似于PostgreSQL。目前InnoDB采用双轨制授权,一是GPL授权,另一是专有软件授权。具体地,MyISAM与InnoDB作为MySQL的两大存储引擎的差异主要包括:

(1)存储结构:每个MyISAM在磁盘上存储成三个文件:第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义,数据文件的扩展名为.MYD(MYData),索引文件的扩展名是.MYI(MYIndex)。InnoDB所有的表保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

(2)存储空间:MyISAM可被压缩,占据的存储空间小,支持静态表、动态表、压缩表三种不同的存储格式。InnoDB需要使用更大的的内存分配和存储,它会在主内存中建立其专用的缓冲池,用于创建高速缓冲数据和索引。

(3)可移植性、备份及恢复:MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便,同时在备份和恢复时也可单独针对某个表进行操作。InnoDB免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

(4)事务支持:MyISAM强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持InnoDB提供事务、外键等高级数据库功能,具有事务提交、回滚和崩溃修复能力。

(5)AUTO_INCREMENT:MyISAM中,可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,它可以根据前面几列进行排序后递增。InnoDB中必须包含只有该字段的索引,并且引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。

(6)表锁差异:MyISAM只支持表级锁,用户在操作MyISAM表时,select、update、delete和insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。InnoDB支持事务和行级锁。行锁大幅度提高了多用户并发操作的新能,但是InnoDB的行锁,只是在WHERE的主键是有效的非主键的WHERE都会锁全表的。

(7)全文索引:MyISAM支持 FULLTEXT类型的全文索引;InnoDB不支持FULLTEXT类型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。

(8)表主键:MyISAM允许没有任何索引和主键的表存在,索引都是保存行的地址。对于InnoDB,如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。

(9)表的具体行数:MyISAM保存表的总行数,select count() from table;会直接取出出该值;而InnoDB没有保存表的总行数,如果使用select count() from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。

(10)CURD操作:MyISAM中,如果执行大量的SELECT,MyISAM是更好的选择。对于InnoDB,如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令

(11)外键:MyISAM不支持外键,而InnoDB支持外键。

通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、存储过程、视图、行级锁、外

键等等。尤其在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外,必须需要注意的是,任何一种表都不是万能的,合适的才是最好的,才能最大的发挥MySQL的性能优势。如果是不复杂的、非关键的Web应用,还是可以继续考虑MyISAM的,这个具体情况具体考虑。

 

参考文章:

https://blog.csdn.net/justloveyou_/article/details/78308460

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据库知识梳理 的相关文章

  • 嵌入式第一课

    GPIO实例应用 include 34 stm32f10x h 34 ifndef LED H define LED H void LED Init void endif include 34 led h 34 void LED Init
  • 范式通俗理解:1NF、2NF、3NF和BNCF

    范式通俗理解 xff1a 1NF 2NF 3NF和BNCF 准备知识超键 候选键 主键函数依赖部分依赖传递依赖 范式1NF2NF3NFBCNF 参考 准备知识 超键 候选键 主键 超键 超键 super key xff1a 在关系中能唯一标
  • 基于springboot的小区社区物业管理系统

    一 基于springboot的小区社区物业管理系统 此社区物业管理系统融合了大多数功能 xff0c 具有管理员和住户两种角色 管理系统可以使小区的管理水平有很大的提升 xff0c 使小区的管理更加方便便捷 社区管理员具有 xff0c 车位管
  • 基于springboot的电影推荐网站管理系统

    一 基于springboot的电影推荐网站管理系统 普通用户 浏览电影列表查看电影预告与详情查看收录的电影网站查看最新电影动态 管理员 管理电影预告与详情管理收录的电影网站管理最新电影动态管理网址信息管理友情链接 二 技术框架 这是一款基于
  • 代码优化-减少if else

    写在前面 不知大家有没遇到过像 横放着的金字塔 一样的 if else 嵌套 xff1a 我并没夸大其词 xff0c 我是真的遇到过了 xff01 嵌套 6 7 层 xff0c 一个函数几百行 xff0c 简 xff01 直 xff01 看
  • iapp裕v3语言浏览器教程

    如果你要写简单的浏览器的话 你可以这么做qwq 创建好应用后先添加浏览器 他的属性为 width span class token operator 61 span span class token operator span span c
  • VMOS-Pro一款虚拟机app。

    vmos分为两个版本 xff1a 安卓vmos 安卓vmospro 两个的差距在于界面 xff0c 可以说vmospro是重磅更新了 xff0c 让我们了解这一款虚拟机吧 xff01 首先这两款虚拟机都是安卓系统 xff0c 你要ios上红
  • UTM虚拟机-首款iOS虚拟机

    utm虚拟机 xff1b 非越狱安装方法 utm虚拟机是一款ipa为后缀的文件 xff0c 需要爱思助手安装 越狱安装方法 使用uncover越狱后在安装ipa文件 utm介绍 他跟bochs limbo qemo apq等app一样 xf
  • 所有小米机型 解BT+刷Magisk并ROOT+躲避应用ROOT环境检查教程

    废话章节 xff0c 可以不看 时隔一年又回来了 上一篇文章还是在2021年更新的 xff0c 因为学业问题我这是1年1更显然不行 xff0c 那我这次为啥不更新iApp了 xff1f 因为忘得差不多了 我也没想到我有一天回过头来看自己的文
  • 【Minecraft】【ModPC】【我的世界】 我的世界电脑版如何进入网络游戏?

    我的世界电脑版如何进入网络游戏 xff1f 须知 看看就好 xff0c 不要频繁使用modpc xff0c 破坏游戏玩家体验 xff01 不知道为什么Win11会用着用着就会闪退 降级到Win10就什么事也没有 下载 ModPC下载 包含普
  • WindwosServer系统一些设置【网卡驱动修复】【安装UWP应用】【服务器管理取消开机自启动】

    WindwosServer系统一些设置 这里以2022为例 xff1a 第一 网卡驱动丢失修复 此教程只针对I219 V LM网卡 xff01 小知识 xff1a 当电脑没网时 xff0c 将手机和电脑用USB数据线连接 打开设置 xff1
  • dp最长不上升子序列 二分upper lower+贪心

    题意 找出最长不上升子序列长度 再找出最长不下降子序列最大长度 写法运用了指针 减少了代码量 include lt iostream gt include lt algorithm gt using namespace std const
  • 小米平板5ProWIFI(elish)刷ArrowOS

    文章目录 警告下载奇兔刷机系统本体及Recovery 清除数据刷入AospRec开始刷入警告 完成设置输入法 变砖头了qwq又是警告 芝士截图Root方法结尾 警告 此文章只针对 小米平板5Pro Wifi版本 xff08 elish xf
  • 【宝塔】【Windows】【Blessing-Skin】【我的世界】用宝塔Windows搭建皮肤站

    文章目录 前言所需环境相关链接安装宝塔安装步骤访问宝塔同意协议 安装环境安装WNMP添加站点 开始安装皮肤站配置网站配置Nginx URL重写规则 xff08 即 伪静态 xff09 配置PHP 安装皮肤站 一些小调整安装插件常见问题 插件
  • ping的详细过程学习笔记

    pc1 ping pc2 也就是pc1 xff1a 192 168 1 1 ping pc2 xff1a 192 168 1 2 属于同一网段的ping过程 步骤1 ping开始 即后台运行192 168 1 1 ping 192 168
  • FTPClient上传文件内容为空/损坏/缺失

    项目场景 xff1a 项目场景 xff1a 本地项目联调OA系统的时候 xff0c 在发送审批时会传送相关附件 xff0c 该附件由本地项目上传至FTP xff0c OA系统会根据我们提供的路径和文件名去FTP中找到该文件 问题描述 xff
  • Debian9桌面设置

    本文由荒原之梦原创 xff0c 原文链接 xff1a http zhaokaifeng com p 61 665 新安装的Debian9桌面上啥都没有 xff0c 就像这样 xff1a 图 1 虽然很简洁 xff0c 但是用着不是很方便 x
  • 爬虫遇到Cloudflare问题

    网址 xff1a https opensea io rankings sortBy 61 seven day volume 返回代码 xff1a 403 遇到的问题 xff1a Access denied api opensea io us
  • java servlet写的网页猜数小游戏

    几年前 xff0c 用java servlet 写了个猜数的网页小游戏 xff1b 今天看了觉得有点意思 xff0c 贴出来怀旧一下 xff1a 1 代码如下 xff1a package cn wzb import java io impo

随机推荐

  • 安卓-system.img镜像文件过大问题

    3126 5 1SDK预置过多apk时导致编译otapackage时报错处理 xff1a 1 修改prebuilts python linux x86 2 7 5 lib python2 7 zipfile py文件中为ZIP64 LIMI
  • 使用Tesseract-OCR识别图片中的文字并生成双层PDF

    识别图片中的文字并不是很困难 如果自己训练一个文字识别的深度学习程序去识别也是可以 xff0c 但是太费劲 Tesseract OCR是一个开源的文字识别引擎 xff0c 并且支持包括中文在内的多国语言 只要将语言配置上去 xff0c 就可
  • iptables(三)iptables命令详解

    一 语法规则 iptables t table COMMAND chain CONDITION j ACTION t table 是指 39 操作的表 39 filter nat mangle或raw 39 默认使用filter 39 CO
  • 单调栈lllll

    单调栈 xff0c 就是一个栈 xff0c 不过栈内元素保证单调性 即 xff0c 栈内元素要么从小到大 xff0c 要么从大到小 而单调栈维护的就是一个数前 后第一个大于 小于他的数 例题 xff1a P5788 模板 单调栈 例题就是一
  • cmake(六)Cmake添加工程子目录

    重点 xff1a 39 cmake3 39 和 39 make 39 命令 39 输出 39 的 39 深刻解读 39 备注 xff1a 当前阶段暂时不使用 39 IDE 39 工具 先 39 熟悉各指令 39 一 ADD SUBDIREC
  • nginx(二十七)长连接和短连接

    一 长连接和短连接 概念 1 39 HTTP 39 的长连接和短连接 39 本质 39 上是 39 TCP 39 长连接和短连接 2 在 39 HTTP 1 0 39 中默认使用 39 短 39 连接 解读 xff1a 客户端和服务器 39
  • nginx(七十四)nginx与跨域细节探究

    一 nginx配置跨域 知识铺垫 强调 xff1a 跨域是 39 浏览器 39 行为 39 不是 39 服务器行为 43 43 43 43 43 43 43 43 43 43 43 43 43 43 34 跨域的两种解决手段 34 43 4
  • HTTP1.1(一)HTTP协议

    一 HTTP协议定义 RFC7230定义 说明 xff1a 关注 39 红色关键字 39 无状态 解读 xff1a 连续的 39 两个 39 请求 后续的请求 39 不能依赖 39 前一个请求 各个请求是 39 相互独立 39 基于请求 相
  • nginx(七十五)nginx与Vary响应头细节探讨

    一 Vary nginx与Vary有关联的地方 nginx源码分析处理Vary响应头的逻辑 CORS和缓存 gzip vary 1 gzip vary on 如果设置为 39 开启 39 2 服务器 39 返回数据 39 时会在头部带上 3
  • JDK1.8之Lambada表达式一

    一 lambada表达式简介 我们知道对于Java变量可以赋给其一个值 而如果想将 34 一块代码 一个完整的方法 34 赋给一个Java变量 如下所示 xff0c 怎么做呢 xff1f 你可能认为 就是下面的方式来实现 很显然 xff0c
  • Oracle(三)

    一 概述 1 DML xff08 data manipulation language 数据操作语言 xff09 insert update delete 2 DDL data definition language 数据定义语言 crea
  • 项目中权限控制系统的设计

    RBAC 权限 xff1a 权利 能做的 和限制 不能做的 xff0c 在权限范围内做好自己的事情 xff0c 不该看的不看 机密 xff0c 不该做的不做 xff01 最开始真正有权限的概念是在Linux上关于文件和目录的权限 xff0c
  • 每天一个Linux命令之(read)

    一 概述 read命令特点 xff1a 1 接收 39 标准输入 键盘 39 的输入 或其它 39 文件 描述符 39 的输入 2 得到输入后 然后将数据 39 保存 39 一个 39 变量 39 中 核心点 xff1a 39 数据源 39
  • LInux shell之(for in 用法总结)

    一 语法 for 变量名 in 列表 do 程序段 command done 注意1 xff1a 是变量名 而不是 变量 xff01 注意2 xff1a 列表 可以做文章 xff01 二 应用 第一类 xff1a 数字性循环 gt seq
  • 一次性将所有变成 long long

    include lt bits stdc 43 43 h gt using namespace std const int N 61 100000 43 100 define int long long define fir i a b f
  • Linux基础命令(二十一)Linux中的磁盘管理(终)

    一 逻辑卷管理器 Logical Volume Manager 需求引入 xff1a 最初规划主机的时候 xff0c 只给了 home 100G的 xff0c 但是随着业务量的增大 xff0c 导致用户的增多 xff0c 这个文件系统不够
  • 【机器学习】DBSCAN聚类算法(含Python实现)

    文章目录 一 算法介绍二 例子三 Python实现3 1 例13 2 算法参数详解3 3 鸢尾花数据集 一 算法介绍 DBSCAN xff08 Density Based Spatial Clustering of Applications
  • Zookeeper深度解析(概念、原理机制、应用场景)

    1 Zookeeper是什么 xff1f 分布 开源的应用程序协调服务 它是集群的管理者 监视着集群中各个节点的状态 xff0c 根据节点的反馈进行下一步合理操作 主要解决分布式应用经常遇到的数据管理问题 如 xff1a 统一命名服务 状态
  • 计算机操作系统知识梳理

    1 进程和线程以及它们的区别 xff08 1 xff09 进程是对 运行时程序的封装 是系统进行资源 调度和分配的 基本单位 实现操作系统 的 并发 xff08 2 xff09 线程是进程的 子任务 是CPU调度和分派的基本单位 用于保证程
  • 数据库知识梳理

    概述 xff1a 对数据库索引 数据库锁 数据库事务 MySql优化等基础知识梳理 1 数据库范式 xff08 1 xff09 第一范式 xff1a 列不可分 eg 联系人 xff08 姓名 xff0c 性别 xff0c 电话 xff09