Oracle体系结构2
Oracle体系结构
一、内存结构:
image.png1、SGA:系统全局区,是Oracle的进程共享的内存区域。
SGA中包含6大区域:(这些内存区域在Oracle实例运行期间,承担着不同的作用)
1.1、shared pool 共享池
image.png共享池包含:
概念理解:
一条SQL的执行流程:
客户端-->连接实例-->执行SQL语句(客户端)-->SQL发送给Oracle实例-->SQL解析-->产生所谓的执行计划-->数据库实例中的优化器会基于各方面的成本进行考虑,选择最优的执行计划-->最终执行SQL语句-->结果返回给客户端。
1.1.1、库高速缓存区
1.1.1.1、共享SQL区域:Oracle为了提升执行效率,将执行过的SQL的执行计划保存在共享SQL区域。一旦有后续的SQL需要执行,则先来共享SQL区域
中进行SQL对比。
select * from test; 此语句一旦执行,`共享SQL区域`会保存该SQL执行的执行计划。
select * from test; 如果有完全一样的SQL再次执行,则直接调用共享池(`共享SQL区域`)中的执行计划来执行, 获取最终结果。
软解析:直接应用`共享SQL区域`中的执行计划的解析方式。
select * from TEST; 重新解析SQL,重新生成执行计划,重新执行。
硬解析:当未匹配到完全一样的SQL的执行计划,则需要SQL进行完整解析,并重新确定执行计划。
1.1.2、数据字典高速缓存区(data dictionary)
update test set id=100 where name='zhangsan';
哪些情况会导致SQL执行失败:
1.test表不存在。如果遍历硬盘中的所有表,固然能够确定该表是否存在,但是这样操作效率太低。
数据库会自动维护数据字典,包含对象名称,为了提升查询数据字典的性能,数据字典默认缓存到内存中供进程访问。
2.id字段,name字段不存在。数据字典中会缓存表结构中基本字段信息。
3.zhangsan不存在。查询数据的操作是在表中完成的。
4.权限不足。
为了提高SQL的执行效率,数据库会自动维护数据字典信息,用于SQL对象确认,权限验证等操作。
1.1.3、控制结构
1.2、DB buffer cache 数据库缓冲区高速缓存
image.pngDB buffer cache:用于缓存数据块,提供逻辑IO,提升数据库性能。数据块是我们在建库时定义的数据库的基本IO单位。
注意:建库时可以定义数据块的大小,但是建库完成后不能修改。
SQL> show parameter block;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_block_buffers integer 0
db_block_checking string FALSE
db_block_checksum string TYPICAL
db_block_size integer 8192
db_file_multiblock_read_count integer 128
buffer cache中缓存的就是来自数据库文件的数据块。
select * from test;(涉及到test表的一个数据块)
Oracle实例会将test表对应的数据块从硬盘中加载到内存中,进行查询,将结果返回给客户端。
update test set id=100 where name='zhangsan';
Oracle 实例会将zhangsan数据所在的数据块加载到内存,对buffer cache 中的数据块进行修改,返回结果给客户端。
总结:无论是查看还是修改数据,都是先将数据所在的数据块加载到内存,然后执行查询/修改的操作。
1、脏数据:数据块刚被加载到内存,和硬盘中数据库文件中的数据块是一致的,但是一旦修改,则产生脏数据(脏块)。
注:数据保存在内存中是不安全的,所以需要脏块落盘,buffer cache中的脏块落盘,才能保证已修改的数据的安全,但是脏块直接落盘性能很差,oracle中提出redo来保证脏块数据安全。
思考:为什么不直接对硬盘进行修改操作?
1、进程直接修改硬盘上的数据,理论上是可行的,但是对于数据库软件需要定位到修改的行数据。
原id=99
update test set id=100 where name='zhangsan';
Oracle需要先定位99在硬盘上的位置,然后再将99改修为100。其实Oracle做不到这一点。
2、Oracle实例将数据块加载到内存中进行查询和修改。
Oracle实际直接修改硬盘数据。
这两个过程都是涉及到内存中的实例和硬盘中的数据块进行交互。
物理IO:内存和硬盘之间的数据交互。
逻辑IO:数据块在之前已经被加载到内存中,此时如果再查找此数据只需要将内存数据块进行修改即可。
undo回滚段:保存已修改但未提交的数据。
2、Oracle中undo回滚段作用:
1、支持事务rollback;
2、隔离级别RC中, undo解决脏读问题。
3、Oracle中redo重做日志作用:一旦事务提交,则redo落盘,相较于脏块直接落盘,redo落盘性能更好。
事务举例:
现在硬盘中内存中zhangsan的id都是99.
session1执行:
update test set id=100 where name='zhangsan';(不提交)
session2执行:
select id from test where name='zhangsan';
返回结果是99,此时内存中数据块已经被修改为100,为什么返回99,这是因为在内存中有对应的undo区域,undo保存已修改旦未提交的数据。
注:在当前会话中执行undate语句,又在此会话中执行select语句,查看到的是数据块当前值id=100;
在其他会话中进行select查询,查询到的都是undo中的快照值id=99.
这么做的目的就是为了保证事务之间是隔离的。
4、事务的隔离性:
Mysql的隔离级别:
名称 | 简写 | 解释 |
---|---|---|
读未提交 | RU | 脏读,读到了未提交的数据 |
读已提交 | RC | 解决了脏读问题(undo),出现幻读(读取到其他事务已提交数据,insert语句引起),不可重复读(读取到其他事务已提交的数据,delect、update语句引起) |
可重复读 | RR | 解决了幻读问题(间隙锁),解决了不可重复读问题(undo的MVCC),MVCC:多版本并发控制 |
序列化 | 串行执行事务,并发度太低,不使用 |
Mysql的隔离举例:
session1 | session2 |
---|---|
begin; | |
begin; | |
select id-->99 读数据块,发生物理IO | |
select id-->99 读数据块,发生逻辑IO | |
update id-->100 修改数据块,发生逻辑IO。 数据块-->100,undo-->99 | |
select id-->100 读数据块,发生逻辑IO | |
结果1:select id-->100 读数据块,发生逻辑IO。当隔离级别是“读未提交(RU)”时出现这个结果,读到了未提交(脏)数据 | |
结果2:select id-->99 读取undo数据块,发生逻辑IO。当隔离级别是“读已提交(RC)”时出现这个结果。解决了脏读问题 | |
commit;事务提交,100生效 | |
结果1:select id-->100 读取数据块,当隔离级别是“读已提交(RC)”时出现这个结果,发生了"不可重复读"(同一会话中连续读取的值不一致)。RC级别解决了脏读问题(undo),但是存在幻读与不可重复读问题 | |
结果2:select id-->99 读取数据块,当隔离级别是“可重复读(RR)”时出现这个结果,解决了幻读问题(间隙锁),解决了不可重复读问题(undo的MVCC),MVCC:多版本并发控制,在undo中保存之前的多个值 |
Oracle的隔离级别:
Oracle中也存在事务的概念,事务之间也应该存在隔离性,但是很少讨论Oracle的隔离级别。
名称 | 简写 | 解释 |
---|---|---|
读已提交 | RC | 默认隔离级别。解决了脏读问题(undo),出现幻读(读取到其他事务已提交数据,insert语句引起),不可重复读(读取到其他事务已提交的数据,delect、update语句引起) |
序列化 | 串行执行事务,并发度太低,不使用 | |
只读模式 | 只读模式的事务只能进行select操作,不能进行insert、update、delete操作 |
1.3、redo log buffer 重做日志高速缓冲区
image.pngredo log buffer重做日志缓冲区:用于缓存redo log(重做日志)
redo log 重做日志:实际上就是我们进行DML操作时,对数据块进行修改产生的日志信息。
注:一旦数据库崩溃/发生异常,内存中的脏块消失,启动数据库实例是可以使用硬盘中的数据页+redo重构脏页恢复数据。
对数据块修改:
1、脏块---->脏块保存在buffer cache中;
2、日志信息---->redo log---->redo log会被存放在redo log buffer中--->日志优先落盘
为什么日志优先落盘?
1、日志数据量小于数据块数据量;
2、顺序IO(日志落盘)性能高于随机IO(脏块落盘)。
注:buffer cache中的脏数据是异步落盘的;
redo log buffer中的redo log是同步落盘的。
在某种情况下,Oracle实例中的某些进程会将某些数据块刷新到硬盘。
举例:
原id是99,update id=100 后修改操作是发生在数据块中的。此时id变为100,id=100是脏数据,所在数据块脏块,脏块保存在内存中数据是不安全的,要求数据尽快落盘,又因为脏块直接落盘性能差,所以引入redo log的机制来代替脏块直接落盘。
在现在传统关系型数据库中,保证数据持久性,都是通过redo机制来保证的。
1.4、large pool 大型池
image.png1.4.1共享服务器:一对多的工作场景。与监听进程的工作机制相关。
服务器进程:客户端连接,在Oracle数据库服务器中产生服务器进程,服务器进程的工作室一对一的。一个服务器进程使用一块PGA空间,为一个用户连接/会话提供服务。
1.4.2备份恢复操作:后续解释。
1.5、java pool java池
1.6、stream pool 流池
2、PGA:进程全局区,是Oracle的服务器进程(前台进程)独占的内存区域。
image.pngPGA区域包含(这些内存区域在Oracle实例运行期间,承担着不同的作用):
2.1、堆栈空间
2.2、用户全局区(UGA)
UGA最主要作用:
1、保存会话信息;
2、用于查询排序。当用户执行查询操作并且对查询结果进行排序。
索引组织表和堆表区别:
1、Mysql --->InnoDB索引组织表
Mysql会自动基于主键创建聚簇索引,并且向表中插入数据时,数据会按照聚簇索引段/主键值进行排序存放。Mysql中存放的数据是有序的(主键值数据有序)。
2、Oracle ---> 堆表
Oracle数据表中存放的数据是不进行排序的,数据是无序的。堆表中的数据顺序取决于插入顺序。
例如:
select * from test order by id; 希望看到所有的行记录并且是按顺序显示。
怎么实现:我们对数据的排序操作,并不是在物理的数据块中直接进行的,而是先获取数据块中的数据,然后再进行排序操作。
排序区使用级别:
1、UGA--->数据量小时使用;
2、临时表空间--->数据量大时使用。
二、进程结构:
image.pngMysql和Oracle进程区别:
1、Mysql是典型的单进程多线程数据库。
Mysql实例中包含的进程只有一个“mysqld”,我们从操作系统层面也只能观察到进程层面的内容,Mysql实例真正进行操作的实际是mysqld进程中包含的很多线程。
2、Oracle是典型的多进程数据库。
Oracle实例运行起来后,会同时启动很多进程,用于执行用户操作。
2.1Oracle进程:
image.png2.1.1、实例中后台进程:是Oracle实例运行起来后自动运行的进程,完成Oracle的基本功能。
1、数据库写进程database write(DBWn):作用就是将内存中的脏块刷新到硬盘中。为了提高刷脏效率(脏块落盘效率),会存在多个DBW进程并发刷脏。
DBWn进程刷脏的两种场景:
1、DBWn进程刷脏操作跟事务是异步发生的,会以一定的频率进行异步刷脏;
2、触发检查点,立即进行刷脏(触发检查点:alter system checkpoint)。
检查点(checkpoint):
所谓检查点,就是在数据库中设置一个时间点,保证该时间点之前的脏块都落盘。一旦触发检查点,就会进行刷脏操作,保证该时间点的数据块数据一致。
检查点优点:
1、促进刷脏,在buffer cache中提供更多的可用空间,用于加载硬盘数据块;
2、推进检查点,能减少数据库恢复时间。
注:redo log如何保证数据安全?
真正的数据其实是在buffer cache中的脏块中。一旦故障启动数据库,数据库就会使用硬盘中数据块和redo log重构脏块。如果不进行积极落盘,buffer cache中存在大量脏块,一旦异常意味着大量的脏块需要重构,实例启动好费时间。
2、日志写进程Log write(LGWR):负责将sga中的redo log buffer中的redo log落盘到redo log file中。
image.pngredo log 工作机制:
英文名 | 中文名 | 归属区 |
---|---|---|
redo log buffer | 重做日志缓冲区 | 内存结构 |
lgwr | 日志写进程 | 进程结构 |
redo log file | 重做日志文件 | 文件结构 |
redo log设计目的?
redo log就是为了替代脏块落盘,脏块落盘性能差(数据量大、随机IO),redo log(数据量小、顺序IO)。所以redo log落盘性能好。
注:无论是脏块落盘还是redo log落盘,最终目的都是实现事务的持久化,保证数据的安全性。
redo log落盘和事务提交是同步的。当事务进行提交时,执行commit操作,只要redo log落盘成功后,就会给用户返回commit成功的结果。
在以下情况下lgwr会触发redo落盘操作:
1、事务提交commit;
2、重做日志缓冲区的三分之一已满时;
3、每3s redo log落盘;
4、每当redo log满1M。
总结:出发redo log落盘,对于现在的OLTP业务而言,都是一些比较简单比较小的事务,这些业务中事务的redo基本都是commit落盘。其他的机制更多的应用场景是保证数据库中大事务数据的安全。
3、检查点进程check point(CKPT):为了尽量缩短数据恢复时间。注意:一旦触发检查点,会发生脏块落盘。
image.png4、系统监督进程system monitor(SMON):smon进程管理其他进程。作用:1、在实例启动时执行恢复操作;2、清除不使用的临时段。
注:当kill掉smon会导致实例结束。当kill掉非smon实例不会结束,且会被自动运行起来。
image.png
查看Oracle实例进程时,仅需要查看smon进程即可,smon进程是整个Oracle实例的主进程。
Oracle实例中的进程都是独立运行的,这些进程的ppid都是1,简言之这些进程的父进程都是Linux操作系统的init。
如果数据库异常,则数据库实例启动时,可以基于数据块+redo进行脏页重构从而恢复数据。
5、进程监督进程process monitor(PMON):进程监视器进程(PMON) 在用户进程失败时执行进程恢复。PMON 负责清除数据库缓冲
区高速缓存和释放该用户进程占用的资源。例如,PMON 会重置活动事务处理表的状态,释放锁,并从活动进程列表中删除该进程ID。
举例解释:pmon:当用户进程发送update语句后,用户进程崩溃,导致用户进程并没有给服务器进程发送commit/rollback指令,此时服务器进程执行了update语句,也就意味着数据被修改,脏块产生。pmon此时检测到这种情况发生,会自动在服务器进程中进行回滚操作。也能够保证数据不受影响,释放锁。
注:本身当客户端发送exit(断开连接,结束会话)操作,意味着服务器进程结束+pga释放资源--->pmon则负责结束服务器进程并释放pga。
总结pmon作用:
1、保证数据不受异常影响,并且释放锁,负责结束服务器进程并释放pga资源。
2、pmon会检测会话的空闲时间,超过超时时间后,释放空闲会话占用的资源。
3、在监听中自动注册数据库实例。
image.png
注:smon/pmon本身作为监视器进程都会对其他进程进行监视。
6、归档进程archive(ARCn):归档进程负责将redo log file中的数据转储到归档日志文件。
archive log(数据)工作流程:当buffer cache(数据块)中数据块被修改后,会产生redo log(数据偏移量),此时redo log(数据)会被暂存在redo log buffer(内存)中,再由lgwr进程写入到redo log file文件中落盘。这个时候ARCn进程就可以将redo log file文件写入archive log file中。引入archive log file的目的是因为redo log file是循环覆盖。
2.1.2、前台进程:用户连接,在数据库中创建的进程,用于执行用户操作。
2.2Oracle中特殊进程介绍(守护进程):
1、监听进程(TNSLSNR进程):监听进程只是实例与Linux内核之间的桥梁,监听进程仅服务于实例,但不属于实例。数据库实例的启停不会影响监听进程。
2、GI进程(grid集群管理软件运行的进程):独立于Oracle实例进程之外。