Oracle体系结构(一):内存结构
实例的概念
下图是整个Oracle数据库的体系:
我们的Oracle数据库要跑起来,当然需要有Oracle软件+数据文件,一个需要内存空间,一个需要硬盘空间。对应着实例与数据库文件。
实例就是Oracle软件在内存中的主要工作区域。所有与客户端的沟通,所有的SQL语句(DML,DDL....)和RDBMS的命令(startup,shutdown......)都在这个区域中运行,所以数据库的性能如何,40%是由实例决定的(提升性能,当然要加内存和升级CPU)
实例(INSTANCE) = 内存结构 + 后台进程
一、内存组成
1 、内存基本结构
内存结构主要由SGA和PGA构成,最大的区别是,SGA是共享的,PGA是非共享的内存区域
它们空间的分配时机:
当实例启动时分配SGA
当server process启动时分配PGA
每个版本Oracle的体系都有些差异,下图仅作参考。下面的UGA是在大池(large pool)中的,因为是在共享服务器模式下
1、PGA[程序/进程全局区]
PGA作用与结构
PGA是server process的的专有内存区域,主要服务于会话的操作,其中有一个内存区域叫UGA,是用来保存会话(session)的一些信息(在共享服务器模式,UGA是在SGA中的)
在ORACLE数据库中PGA只有一个,但是没有会话会拿到PGA的一个完整的结构克隆体,去进行独立且私有的操作(独占模式下)
如果是共享模式,那么有些PGA的结构会建立在SGA中当然再调用相关结构的时候依旧是会话独占的
类似JAVA中的类与对象,Oracle中的PGA是一个完整的结构,而且它有一定的空间,但是每一个会话链接的时候,是不允许使用这个大的PGA的,为什么?
因为太危险了,实例PGA(大PGA)如果被这个会话被弄挂了,其他的会话怎么办?
PGA中的栈与堆
PGA中有堆区和栈区
栈区(STACK AREA)
ORACLE所有代码均由C/C++开发的。
C与C++的共性,所有的变量都在栈这个内存对象用进行赋值与销毁。
所以ORACLE栈区主要负责:
1)对SQL语言出现的变量进行快速赋值
2)对PLSQL中出现的变量进行快速赋值
3)对ORACLE数据库中相关的进程进行变量赋值和进程内存持久化操作
处理sql语句过程
1、user process 与server process 建立session
2、 用户发出一条select语句
3、 sql语句交由sp处理
---------- SQL语句解析 ----------
4、 UGA中的语法解析
5、私有sql区中的语义解析
6、SQL工作区真正运行
---------- 分支1 :Oracle标准读 ----------
7、server process读数据块到buffer cache中
8、server process从buffer cache读出来传到session中,返回结果集
9、server process把结果集放到share pool的结果集缓存中
---------- 分支2:Oracle直接路径读 ----------
7、server process直接读数据到PGA的特定区域内(临时结果集缓存,不在体系结构内,是独立的内存区域)
8、server processPGA中读数据到session,用户收到数据
9、不会产生结果集缓存
标准读在数据量较大的情况发生,直接路径读是在数据量较小的时候发生
是由Oracle优化器自主选择的
多数人选择关闭直接路径读
包含单个服务器进程所需的数据与控制信息。比如每个人session传入的sql绑定变量,如果session进行了排序或者hash链接操作,也会使用PGA中的内存。
1)UGA:语法解析
请看下面
2)私有SQL区:语义解析
不要混淆在UGA中的私有SQL区
21C的说法标准:
分为解析区与运行区
优化器(CBO)就在运行区里
SGA中有share pool分为库缓存、字典缓存、其他等。
persistent area持久区,但是新的叫法脚解析区
这个地方非常复杂,Oracle从业人员最不愿意碰的地方
主要对SQL的语义解析
功能:
# 1 判断对定义名里的对象是否有权限
首先要判断能不能连上来
为什么不发生在语法解析里?就是上一步的UGA里?而是跟到了语义解析里?
因此语句已经到解析区了,如果权限不够,就等待赋权。
赋权后,再执行一次这条语句,其实是重新激活在解析区的这条语句。
不激活的话,某个时间后(60秒)就不存在了
# 2 SQL的HASH转换
这一步将SQL语句转换成HASHCODE,进而发生软解析和硬解析判断。
在oracle和mysql都使用了软硬解析判断,来判断SQL语句是否发生过,
但是oracle软硬解析判断发生在语义解析过程,mysql的软硬判断在sql刚提交的时候。mysql是不需要进行hash转换的,而是直接判断ASCII码。而oracle是要发生语句转换的,转换成hashcode来加速软硬解析判断的速度。
hashcode的优点
hash时间复杂度O(1),key-->value
为什么mysql与oracle不一样?
mysql效率为王,mysql的体系结构不复杂
软硬解析判断过程
HASH算法来自于操作系统而不是数据库。
在PGA的私有SQL区中,把要执的SQL语句转换为HASHCODDE ,转换好后,server prcess将hashcode从PGA中与SGA 的share pool中的库缓存中进行hashcode对比,看看是否之前已经执行过。
执行过的话,将执行过语句的执行计划树直接拿到PGA中交由该语句直接到SQL运行区中直接执行即可(这是软解析) 。如果没有的话,那么server process会通知该语句接着向后执行(硬解析)
问题:HASHCODE放在什么地方?
放在SGA的share pool的库缓存里。
问题:HASHCODE保留多久?
按照库缓存大小和LRU算法进行判断
问题:一条SQL语句,如果where后的量变化的话。我们怎么保证软解析的发生?
使用绑定变量:
select * from where id = &id;
# 3 视图映射
将视图映射回基表上
# 4收集统计信息
最好收集统计信息
# 5 优化器介入
看使用了哪一种优化器RBO/CBO
RBO:基于规则的优化器
9i之前的优化器,Oracle官方模拟不同情况,写好的一种规则
金蝶,用友推荐使用RBO,在ERP系统中语句是比较固定的
CBO:基于开销的优化器
oracle,mysql都在使用
# 6 根据统计信息生成直方图
# 7 根据直方图指定可能的SQL执行方案,生成柱状图
生成柱状图
# 8 从柱状图中找到开销最小的那个执行计划
# 9 生产最终执行计划
并交到SQL运行区中,调用server process安装最终执行计划开始生产执行SQL。
其实也不是真正的执行计划,真正执行的时候会根据实际情况调整,真正的执行计划是发生在sql执行后的
-- 真正的执行计划
set autotrace on explain
PLSQL按F5生产的是解析计划,是发生在sql语句执行前的
3)SQL工作区 SQL Work Areas
SQL真正发生运行的地方,也分为了几个区
哈希区
hash区:如果sql语句产产生hash链接的话,这里将缓冲部分数据。如果该区域被用完了,那么就会使用临时表空间进行相关操作
sql语句一共有几种连接方式?
hash链接,笛卡尔积,排序合并,nest join
排序区:
如果sql语句产生排序,这里会缓冲部分数据。
位图区:
我们在创建索引和建表的时候需要调用系统表,那你使用系统表的时候,就会产生位图索引以及位图索引需要临时国建的数据。当然直接创建位图索引直接使用该区域。
如果该区域不够的话就会使用临时表空间。
谁是SQL工作区的补充?
临时表空间
2、SGA
1)数据库缓冲区缓冲 database buffer cache
DB buffer cache是SGA中最大的一部分,是用来存放从数据文件中读取到的数据块的副本,所有连接到同一数据库实例的用户,都可以访问得到。
这个缓冲区具有的一些结构:默认池(db_cache_size),保持池(buffer_pool_keep),回收池(db_pool_recycle)
缓存的作用
优化物理I/O
是Oracle执行SQL的区域。存数据块的拷贝信息
从数据文件没读一次到buffer cacha 就有一次IO
减少物理读(物理读:从数据文件里读),如果buffer cahe有的话就从内存里取,就不用IO了
数据库更新缓存中的数据块,并将有关更改的元数据存储在重做日志缓冲区。提交之后,数据库将重做缓冲区写入磁盘,但不一定会立即将数据块写入磁盘。相反,数据库写入器 (DBWn) 在后台执行惰性,写入操作
优化性能
显而易见的:将频繁访问的块保持在缓冲区高速缓存中,而将不常存取的块写到磁盘
数据块
数据文件中数据块是8k大小,读取到buffer中也是8k
在内存中的管理方式
数据一次读取到内存中,只要不被换出,就会一直在缓冲区中存在,等待下一次读取。
Oracle通过写入列表和LRU列表来管理这些缓存块。
写入列表:管理脏块,即已经发生修改,但未写入到数据文件中
LRU列表:包含FREE的buffer,命中的buffer已经未来得及写入的脏块。
注意数据的命中率(直接读db buffer cache的概率)
2)重做日志缓冲
是一个循环写的缓冲区
作用:存储改变信息
执行delete语句的时候,会先生成一条redo log,会先放在redo log buffer里
commit的时候,才会写到 redo log(文件)里
redo如何获得数据:
redo log buffer是SGA中一块循环使用的内存区域,保存数据库变更的信息。这些信息以重做条目(redo entries )形式存储。redo entries包含重构、重做数据库变更的重要信息,这些变更包括 INSERT UPDATE DELETE CREATE ALTER DROP 等
redo entries的内容被oracle数据库进程从用户的PGA中复制到SGA中redo log buffer中。
这解释了为什么redo buffer在SGA中,又是怎么获取用户的DML DCL语句的
redo entries 在内存中占用连续的顺序空间
redo log 是循环使用的,通过LGWR进程不断把redo log buffer的内容写到redo log file 中,redo log file 同样是循环使用的
为什么不直接写到文件中?
写入到磁盘之前要先在buffer中临时缓存这些数据。因为内存到内存的速度比内存到磁盘的速度快多了,因此使用buffer 可以加快数据操作
实际上数据在buffer中不会停留太长,LGWR会自动刷新(flush)
3)共享池 share pool
关键词:执行计划、硬解析、软解析
主要组成部分:
1)库缓存
库缓存是存放可执行SQL和PLSQL代码的内存结构。
包含共享SQL和PLSQL区。
在共享服务体系结构中,还包含私有SQL区
可以手动删除共享池中的所有信息:
ALTER SYSTEM FLUSH SHARED_POOL
2)数据字典缓存区:
数据字典是数据库表和视图的集合,其中包含有关数据库及其结构、用户等参考信息。
部分v$视图,dba_*视图 all、user视图就存放在这里。
Oracle 数据库在解析 SQL 语句期间,会频繁访问数据字典Oracle 数据库如此频繁地访问数据字典,所以指定了以下这些特别的内存位置来保存字典数据:
数据字典缓存:此缓存保存有关数据库对象的信息。此缓存也称为 行缓存,因为它按行、而不是按缓冲区保存数据
库缓存:存放用过的sql和plsql
3)结果集缓存
与缓冲池保存数据块不同, 服务器结果缓存保存的是结果集。服务器结果缓存包含 SQL 查询结果缓存和 PL/SQL 函数结果缓存,它们共享相同的基础结构。
SQL结果集
数据库能在 SQL 查询结果高速缓存中存储查询和查询片段的结果,将此缓
存结果用于将来的查询和查询片段。大多数应用程序受益于这种性能改善。
例如,假设应用程序将重复执行相同的 SELECT 语句。如果结果会被缓存,
则数据库会将其立即返回。通过这种方式,数据库避免了重读块和重计算结
果等昂贵操作。每当事务修改了数据或用于构造该缓存结果的数据库对象元
数据时,数据库自动使其高速缓存结果无效
用户可以为查询或查询片断添加 RESULT_CACHE 提示,以指示数据库应将
其结果存储在 SQL 查询结果缓存中。由 RESULT_CACHE_MODE 初始化参
数确定 SQL 查询结果缓存将用于所有查询(如果可能) 还是仅用于添加了
注释的查询。
补充:硬解析与软解析
在执行 SQL 语句时,数据库将尝试重用以前执行过的代码。如果在库缓存中存在该 SQL 语句的已解析表示形式,并且是可以共享的,则数据库会重用该代码,这称为 软解析或 库缓存命中。否则,数据库必须为应用程序代码建立一个新的可执行版本,这称为 硬解析或 库缓存未命中
作用
语法分析,编译,生产执行计划,运行执行计划。
共享,就是保存共享的执行计划
3、UGA[会话全局区]
会话全局区,也叫会话游标全局区,主要存放session的信息,还有打开的游标,执行语句中的私有变量等。UGA也分为两大部分,一个叫会话区;一个叫持久区,也叫游标持久区。
会话区
会话区的作用
保留会话产生的所有信息:客户端的ID,客户端进程状态,sever process的ID,sever process的状态,session ID,会话状态等。
如果你想知道那台机器连上了数据库,可以在会话区里找到。
会话区还做了其他事,也会校验相关的权限(用户的权限,能不能连),相当于MYSQL的链接池
持久区,游标持久区
游标的概念,在ORACLE数据库中有两种游标
1、程序游标,就是PLSQL中的cursor,只是一个程序体,负责采集结果集,并将结果集数据一一读出。
2、可执行游标,在ORACLE数据中所有可执行的SQL与PLSQL程序都被称为游标,在持久区中的游标就是一种可执行游标。
我们持久区中的游标是指:可执行游标
可执行游标分类:
父游标:游标(SQL/PLSQL)的明文语句。
子游标:父游标执行过程中产生的细节描述和最终由优化器产生的执行计划
持久区的主要功能:
检验SQL语法是否正确,以及你访问的相关对象是否存在 。
持久区不是不会区访问表和视图是不是真的存在,而是让持久区守护进程去让sever process访问系统表,去验证表或视图是否存在。
持久区还有一个隐藏功能:
判断事务与非事务的语句,事先判断是否发生事务
SQL语法过程
ORACLE数据库的SQL解析,真正意义上的第一个步,发生在UGA持久区中的语法解析:
1 判断SQL语法是否正确
判断关键字与关键字组合是否正确,不会判断定义名
2 判断定义名是否存在
3 预先判断是否发生事务