数据库语言SQL:事务,锁,索引

目录

1. 事务

1.1 事务的作用

1.2 提交事务

1.3 事务的状态和性质(原子,一致,隔离,持久)

2. 锁

2.1 锁的机制

2.2 常见锁举例

2.3 锁等待和死锁

2.4 锁争用

3. 索引

3.1 索引查找数据的过程

3.2 索引原理

3.3 索引分类和比较

3.4 索引使用


1. 事务

1.1 事务的作用

(1)如何保护数据库里的数据?

我们需要防止非法用户的操作对数据库造成故意的破坏,比如非法的修改数据,非法的窃取数据等。此时可以通过用户管理,权限管理等方法来控制。

还防止合法用户的操作对数据库造成意外的破坏,比如防止有逻辑关系的一组DML操作半途而废,或由于并发存取而导致的对数据一致性的破坏。由于更新数据而导致对数据完整性的破坏或由于故障而导致的数据破坏等。

(2)事务的控制机制,能够对数据进行更有效安全的操作。

(3)事务:transaction,是用户定义的一组操作序列,由一条或多条相关SQL语句组成

(4)SQL通常会隐性地开始事务(也可以显性),但必须显式地结束事务

(5)结束事务的两种方法:

Commit:提交。如果所有的操作都完成了,可以结束事务,可以向系统对事务进行提交,提交之后,所有的修改都会生效,在没有提交之前,所有的修改都可以作废。

RollBack:回滚。回滚会结束当前事务,并且放弃自事务开始以来的所有操作,回到事务开始的状态。注意,可以在事务内设置一些保留点(Save Point),这样可以根据需要RollBack到某个保留点,不必放弃整个事务。

1.2 提交事务

在用DML语句对数据库进行操作后,如果要在数据库中永久性保存操作结果,就需要使用commit命令来提交事务。提交成功后,其他会话就可以查看到操作后的数据了。

1.3 事务的状态和性质(原子,一致,隔离,持久)

一个事务从开始到成功的完成(或者因故中止),中间经历了如下几个状态

事务初态

活动状态

失败状态

中止状态

提交状态

(1)原子性

一个事务中的所有操作,要么都被成功地做完,要么都不做。

(2)一致性

是指在语句/事务开始处理之前,数据库中的所有数据都是满足已经设置的各种约束条件或业务规则的。在语句/事务处理完成后,这些数据虽有些不同,但仍满足这些约束条件或业务规则。

比如,当一条DML语句的最终操作结果使数据库出现不一致现象(比如违反主键的唯一性约束条件)时,该操作就会失败。根据原子性,这个事务会被全部退回,所有的操作都会被放弃,数据库继续保持原来的一致性。

(3)隔离性

是指一个事务的执行,不能受到其他事务的干扰。即一个事务内部的操作和使用的数据,对其他事务是隔离的,并发执行的各个事务之间不能相互干扰。在提交之前,只有该事务的用户才能够看到正在修改的数据,而其他事务的用户只能看到修改之前的数据。

3种读现象如下

1)脏读:dirty read,一个事务读到另一个事务中还没有提交的更改过的数据,其效果就像是打开了其他人正在更改的文档,不是最后定稿的文档。这种情况下,数据可能不是一致性的。

2)不可重复读:non-repeatable read,当一个事务读取了某些数据后,另一个事务修改了这些数据并进行提交。此时,当该事务再次读这些数据时,发现这些数据已经被修改。

3)幻像读:phantom read,但一个事务读取了某些数据后,另一个事务又插入或删除了符合查询条件的某些行。此时,当该事务再次读这些数据时,发现符合查询条件的记录变多或者变少了。

4种事务的隔离等级,用于指定在并发事务情况下可能出现的可防止的读现象的处理能力。

4种隔离等级对3种读现象的处理能力如下:

 Oracle中,提供了读已提交 Read Committed,串行化 Serializable这两种SQL92标准的隔离等级,还有只读 Read only 隔离等级。默认使用 Read Committed。

1)Read Committed:一个事务所操作的数据是所有已经提交的数据,无论这些数据是在本事务中还是在其他事务中被提交的。这个隔离等级能够保持默认时Oracle数据库不会发生读取到赞数据的现象,即不会读取到未提交的数据。

2)Serializable:一个事务只能够操作(select, insert, update, delete)在该事务开始之前已经提交的数据,并且可以在该事务 中操作这些数据。在这个隔离等级下,不会发生脏读,不可重复读,幻像读现象。

3)Read only:一个事务只能查看(select)到在该事务开始之前已经提交的数据,但不能再该事务中操作(insert, update, delete)这些数据。在这个隔离等级下,也不会发生脏读,不可重复读,幻像读现象。当数据库处于Read Committed隔离等级时,在默认情况下数据库提供的是语句级的读一致性。所以,要得到事务级的读一致性,就需要显式地将数据库设置成Serializable隔离等级。

(4)持久性

是指一个事务一旦提交成功,它对数据库中数据所做的修改也就永久性的保存下来了。并且这些修改不会由于系统故障或错误而消失。

2. 锁

2.1 锁的机制

(1)为什么需要锁?

同一时刻多个用户同时操作数据库中的数据,这会导致数据库混乱,因此引入了锁。

1)能够保证数据完整性。

2)能够保证数据一致性。

锁的存在防止并发操作带来的争用相同的资源,实现先来后到。用于管理对共享资源的并发访问。

但是锁会影响系统的性能,因此在认识锁的机制的同时,需要考虑如何优化数据库的性能。

(2)锁按照级别分类

1)排它锁:exclusive lock, 即x锁。该模式的锁用作数据的修改。

2)共享锁:share lock, 即S锁。该模式锁下的数据只能被读取,不能被修改。

Oracle为了使数据库实现高度的并发访问,使用了不同类型的锁来管理并发会话对数据对象的操作。重点了解DML锁,该类型的锁被称为数据锁,用于保护数据,保证了并发访问时数据的完整性和一致性。

3)行级锁:当修改表中某行记录时,需要对将要修改的记录加行级锁,防止两个事务同时修改相同的记录,事务结束后,该锁也会释放,是粒度最细的锁。

2.2 常见锁举例

(1)共享行级锁

(2)独占行级锁

(3)表级锁 TM

(4)表级排它锁

2.3 锁等待和死锁

(1)锁等待

某些情况下,由于占用的资源不能及时释放而造成锁等待,也叫锁冲突。

锁等待会严重地影响数据库性能和日常工作。

出现锁等待的情况时应尽快找出错误原因并处理,避免影响数据库性能。

示例演示锁等待的现象:(略,稍后补)

(2)死锁

死锁是锁等待的一种特例。通常发生在两个或多个会话之间。

比如,一个会话要修改两个资源,修改这两个资源的操作在一个事务当中,当修改第一个对象时,需要对其锁定,然后等待第二个对象。此时如果另外一个会话也要修改这两个资源,并已经锁定了第二个对象。此时,就会发生死锁。两个会话都不能得到想要的对象。

发生死锁后,Oracle自动做出处理,重新回到锁等待的情况。

示例演示死锁的现象:(略,稍后补)

(3)产生锁等待的几种常见原因:

1)用户忘记提交事务,导致长时间占用资源。

2)操作的记录过多,操作过程中没有很好的分组。

3)逻辑错误,两个会话都想得到已被占有的资源。

2.4 锁争用

(1)系统锁简介

高水位标记:如果频繁出现等待事件,很可能是因为有大量的插入操作

空间事务:出现在老版本的数据库中

序列缓存:sequence caceh

用户锁:开发者手工调用dbms_lock包,实现锁

(2)尽量避免锁等待

并行环境中对位图索引的操作,OLTP环境中不建议使用位图索引。

过少的事务槽,会引起锁等待。

事务槽:每个书就开的头会留一点点空间,默认的应该是两个事务槽,同时对数据库的操作不能超过两个,超过两个就会有等待,一个数据块8K,可能有几百条记录,其中各一个操作是对里面一条记录做update, 另一个操作是对里面一条记录做delete。这时候如果还有第三个进程想对这个书库块里的记录做操作,它就必须等待了,因为之后两个事物槽。

没有索引的外键,会导致子表中删除任何一条记录都会锁定父表中的全部记录。

并行的直接路径插入。即使为了提高效率单元不能影响其他人的操作。

(3)锁的策略和使用场景

悲观锁:很早就先锁定,全部操作结束后再释放。不会失败,但是会长期锁表。适合数据仓库。好处是无需重试,减少失败。劣势是增加了锁的时间和争用,等待的可能性高,影响性能。

乐观锁:真正操作表之前再锁定。容易失败,适合高并发的OLTP。优势是提高了并发性和吞吐量,劣势是可能会增加重试次数。

(4)锁的监控和分析

1)常用的动态视图

2)常见的等待事件

row lock contention;DML造成的行锁

index contention:索引块分裂造成的锁等待

contention:其他锁等待,系统锁

Allocate ITL entry:事务槽不够,导致新的事务无法操作。可能是因为事务的提交和回滚太慢

3)事务槽的解决方案

减少长事务,增加commit/rollback的频率

增加事务槽:initrans和maxtrans。前者决定初始的事务槽个数,后者决定最大数量。

延迟块清除

3. 索引

3.1 索引查找数据的过程

(1)使用索引的目的是加快查询速度。

(2)索引如何加快查询速度?

索引是建立在表中的某一个或几个列上的,这样的列称为索引列。

在创建索引时,数据库服务器将对索引列的数据进行排序,并将排序的结果存储在索引所占的存储空间中。

在查询数据时,数据库服务器首先在索引中查询,然后再到表中查询,因为索引中的数据事先进行了排序,所以只需要很少的查询次数就可以找到需要的数据。

(3)示例解析:略

(4)按照索引列的值是否允许重复,索引可分为:

唯一性索引

非唯一性索引

(5)按照索引列中列的数目,索引可分为:

单列索引

复合索引

(6)按照索引列的数据组织方式,索引可分为:

B*树索引

位图索引

反向索引

基于函数的索引

(7)补充:索引的利弊

合理的使用索引可提高数据库的查询能力。

但不合理的索引反而降低数据库的性能,尤其是在进行DML操作时。创建索引时,表中的数据将被排序,如果对表进行DML操作,表中的数据发生了变化,这时索引中的数据将被重新排序,如果在表上建立了多个索引,那么每个索引中的数据都要被重新排序。这种排序的开销很大,尤其表格数据非常大的时候。

(8)索引是关系型数据库系统用来提高性能的有效方法之一。

索引的使用可以减少磁盘访问的次数,从而提高了系统性能。

如果在表上进行的主要操作是查询,那么可以考虑建立索引。

如果进行频繁的DML操作,那么索引的开销反而很大。

(9)创建索引的原则

如果每次查询仅选择表中的少量行,应该建立索引;

如果在表上需要进行频繁的DML操作,不要建立索引;

尽量不要在有很多重复值的列上建立索引;

不要在太小的表上建立索引。

3.2 索引原理

(1)现有的主流数据库都提供了索引这一概念,Oracle也不例外。

(2)一旦在数据表的某列上建立了索引,Oracle将另辟新的空间,以存储该列上所有值与其记录的rowid的对应关系,当用户试图以索引列作为搜索条件时,Oracle将利用索引来获得相应的rowid,并捕获该记录。

(3)示例演示:略

3.3 索引分类和比较

(1)B*树索引

B*树索引是Oracle的默认索引类型。结构类似一棵倒立的树。

B*树索引包含一个或多个分支节点层以及一个叶子节点层。

一个分支节点包含了下一层分支节点所覆盖的值范围。

根节点和叶子节点之间的分支节点层的数目叫做索引深度。

叶子节点包含实际的索引值以及相关行的rowid,rowid指向数据所在的具体位置。(即在哪个Oracle数据文件,文件中哪一个盘区,盘区中哪一个数据块),叶节点还保存着指向前一个叶节点和后一个叶节点的指针,用于从两个方向遍历,执行范围类扫描。

由于B*树索引结构不包括一些较高层次的分支节点,因为读取B*树索引结构的I/O操作相对来说较少。另外,由于所有的叶子节点都在索引的同一深度,因为获取任意索引项都需要相同数量的I/O操作,这就使得索引的性能比较统一。

B*的深度取决于叶子节点项的数目,深度月神,分支节点的层次越多,那么定位并访问叶子节点额I/O操作数量就越多。

对于具有高看选择性的列来说,采用B树形式的索引来定位数据是比较好的选择。

(2)反向键索引

反向键索引,即自动反转存储在索引中的键值字节顺序。比如行的键值为abcd, 那么该行的反向键索引是dcba。

这种反转是叶子节点范围内的各项分布更加均匀。一定程度上解决了B*树不均衡的问题。

反向索引的目的就是要修正由于对标准B*树索引连续增加递增值而导致的不平衡。

(3)位图索引

在标准B*树索引中,rowid是存放在索引的叶子节点中。

在位图索引中,索引的每一位都代表一个rowid。

如果某行包含某个值,那么在对应这个值的为图中,该行的位就会被“打开”。

由一个映射函数将位转换成响应的rowid。位图索引可包含null值的项。

如果索引中的值不是狠毒哦,那么位图索引占用的空间要比标准B*树索引少得多。

就应用场景而言,位图索引更适合于数据仓库类的系统,其使用范围是表中列的取值较少但行数为长达的表,比如性别列,只有男女两项。

使用位图索引的好处:可以减少索引所占用的磁盘空间,表中的每行数据在位图索引的每个位图中只占用一个二进制位,而位图的数量取决于表中索引列上不重复值的多少。可以加快查询速度。

(4)基于函数的索引

B*树索引和位图索引都是基于列值构建的。

基于函数的索引是基于SQL函数的结果构建的。

用户可以构建一个非常复杂的函数,然后常见一个基于该函数的索引,这样可以极大的改善利用该函数进行查询的性能。但是,函数索引也存在一定的问题。如果表中的数据发生更改,索引中的数据在同步时就需要调用这个函数来进行维护,性能损失比B*树索引大。一个韩硕索引只能解决这个函数在查询中存在的调用问题,如果换成另外一个函数调用,则这个函数索引将会失效。

是否使用函数索引,需要考虑以下问题:

是否需要函数索引?数据库分析设计中列的设计是否存在问题,为什么列需要用函数来处理?

索引导致的空间存储增加是否值得?

函数索引的增加会对该表上执行的DML语句带来性能上的负面影响是否可接受

(5)不可见索引

通常情况下,所有的索引都会被优化器使用。用户可以通过让索引下线或者删除索引的方式让优化器忽略索引,但是,日后用户需要将索引应用于数据库环境中时,必须采取一系列操作将索引更新为最新状态。

如果用户只是希望让优化器在一段时间内忽略索引,那就有了不可见索引。索引可以被相关的访问步骤所忽略,但是对底层数据进行的更新和删除操作仍然可以应用于索引。

(6)存储索引

存储索引是Exadata Storage的一个结构,由Exadata Storage Server软件自动创建。

存储索引用来跟踪在1MB存储节中访问最频繁的列的最高值和最低值。

这些高值和低值被存储在内存中,用于确定1MB的块是否应该作为SQL操作的一部分来访问。

在1MB最初被访问时,便建立了存储索引。

存储索引在数据分类和加载时,效果最优。但这种处理将闲置用于排序的列值范围,这将大大减少访问的评率。存储索引不会对任何SQL产生不利影响,但可能会对基于数据存储特征的语句产生其他影响。

(7)各种类型索引的比较和选择

Oracle数据库支持几种类型索引,可以用于提高数据库的性能。

1)B-tree索引:默认和最常用的索引类型

2)B-tree集群索引:为集群定义的索引

3)Hash集群索引:为Hash集群定义的索引

4)全局和局部索引:将分区表和索引关联起来的索引

5)逆序键索引:对于Oracle真正应用集群应用的最有用的索引

6)位图索引:对于小型数据最有用的索引

7)基于函数的索引:包含函数/表达式的索引

8)域索引:对于应用和桥可以应用的索引

索引在物理和逻辑上依赖于表中的数据。

作为独立的结构,需要存储空间的支持。

管理人员可以创建或删除索引,而不需要影响后台的表格,数据库应用和其他索引。

在插入,更新和删除表中的数据时,数据库将自动维护索引。

日常的数据库管理中,注意以下事项:

1)插入表数据后,创建索引

2)读正确的表和列,创建索引

3)为了提高性能,对索引列排序

4)限制每个表索引的数量

5)删除没有使用的索引

6)定义索引块空间的使用情况

7)估计索引的大小,并设置存储参数

8)为每个索引定义表空间

9)考虑创建并索引

10)考虑创建索引的成本和效益

(8)集群

集群是一个能够改善数据获取性能的数据结构。

集群和索引一样,不会影响表的逻辑视图。

集群提供了一种把磁盘上相关数据存储在一起的方法。

集群有一个或多个表组成。包括一个集群索引。

3.4 索引使用

(1)索引的重要性

索引是表的一个概念部分,用来提高检索数据的效率。

数据库性能优化中,索引绝对是一个重量级(60%)的因素。

如果索引使用不当,其他优化措施将没有意义。

(2)添加,修改,删除数据对索引的影响

添加数据对索引的影响

修改数据对索引的影响

删除数据对索引的影响

(3)利用索引提高数据库性能

示例演示:略

(4)如何使用索引

即使在表上创建了索引,Oracle也不是机械地为在该表上的所有查询都使用索引,会根据查询的具体情况决定是否使用索引。

Oracle对查询语句的执行过程:解析,优化,代码生成,执行代码4个步骤。

在解析过程中,Oracle会对该查询语句进行语法检查和语义分析等操作,通过解析的查询语句才是可以运行的查询语句。

在运行查询语句之前,一般先对其进行优化。优化的目标就是找到运行该查询语句的最佳途径。

Oracle会使用两种优化器:一种是RBO(基于规则的优化器),一种德海CBO(基于开销的优化器)。

RBO优化器基于一组指出执行查询的优选方法的静态集合。

CBO优化器根据统计分析信息来选择执行路径。

而在决定最优执行路径时,将会使用表的行数据,数据及大小等信息。

在优化器选择了最优执行路径后,Oracle会将其格式化成实际的执行代码,然后由系统的执行引擎执行代码。

当优化器进行全表扫描时,它一次会读取一批数据块。

Oracle是否会使用索引是由优化器根据用户表中的数据量决定的。

此外,如果查询语句会读取全表5%-20%以上,那么优化器就会执行全表扫描而不使用索引。

(5)小结

创建主键和唯一索引的主要目的,除了数据的完整性和一致性之外,还具有提高查询速度的作用。

(1)何时使用索引

对于只从总行数中查询2%~4%的表,可以考虑创建索引。

创建索引的基本原则:

以查询关键字为基础,表中的俄航随机排序。

包含的列数相对比较少的表。

表中的大多数查询都包含相对简单的where从句。

对于经常以查询关键字为基础的表,并且该表中的行遵从均匀分布。

缓存命中率低,并且不需要操作系统权限。

小数据量的表不宜使用索引。

频繁使用插入,修改,删除等DML操作的数据表不宜使用索引。

(2)索引列和表达式的选择

创建索引是选择索引列的原则如下:

where从句频繁使用的关键字。

SQL语句中频繁用于进行表连接的关键字。

可选择性搞(重复性少)的关键字。

对于取值较少的额关键字或表达式,不要采用标准的B树索引,可以考虑建立位图索引。

不要将那些频繁修改的列作为索引列。

不要使用包含操作符或函数的where从句中的关键字作为索引项,如果需要的话,可以考虑建立函数索引。

如果大量并发的insert, update, delete语句访问了父表或子表,则考虑使用完整性约束的外部键作为索引。

选择索引列时,还要考虑该索引所引起的insert, update, delete操作是否值得。

(3)选择复合索引主列

多列索引也叫做复合索引,复合索引有时比单列索引有更好的性能。

如果在建立索引时采用了几个列作为索引,那么在使用时也要按照建立时的顺序来描述,即,主列时最先被选择的列。

选择符合索引的关键字时,要遵循下列原则:

如果某些关键字在where从句中的使用频率较高,则考虑创建索引。

如果某些关键字在where从句中的使用频率相当,则创建索引时考虑按照从高到低的顺序来说明关键字。

如果几个查询都选择相同的关键字集合,则考虑创建组合索引。

创建索引以后是的where从句所使用的关键字能够组成前导部分。

应该选择在where从句条件中频繁使用的关键字,并且这些关键字由AND操作符连接。

(4)避免全表扫描大表

全表扫描就是值不加任何条件或没有使用索引的查询语句。

以下情况经常使用全表扫描:

所查询的表没有索引。

需要返回所有行。

带like并使用 % 这样的语句就是全表扫描。

对索引主列有条件限制,但使用了函数,则Oracle使用全表扫描。

带有is null, is not null, != 等字句也导致全表扫描。

(5)监视索引是否被使用

如果创建了索引而没有被使用,那么这些不被使用的索引将起到阻碍性能的作用。

为了辨别是否被使用,从Oracle9i开始,用户可以对索引进行监视。

语法:alter index 索引名 monitoring usage;

(6)索引使用误区

使用比较运算符不当

函数的使用

联合索引

猜你喜欢

转载自blog.csdn.net/sulia1234567890/article/details/121692532