您的位置:首页 > 数据库 > Oracle

oracle学习笔记 SQL语句执行过程剖析讲课

2016-07-17 17:46 302 查看
oracle学习笔记

SQL语句执行过程剖析讲课

这节课通过讲述一条SQL语句进入数据库

和其在数据库中的整个的执行过程

把数据库里面的体系结构串一下。

让大家再进一步了解oracle数据库里面的各个进程、存储结构以及内存结构的关联关系。

首先来讲整个体系中有客户端、实例和数据库

数据库里有三类文件

控制文件ctl、数据文件dbf、日志文件log

实例中SGA有六大池子

第一大内存区shared pool即共享池

第二大内存区buffer cache

第三块是redo log

我们主要讲上面的三大池它们容易出问题,

特别是shared pool和buffer cache。

另外三大池不会出问题。

接下来的几个章节主要讲shared pool ,buffer cache。

一)shared pool

用户连接上实例,

实例会专门针对这个连接开一个进程,

这个进程叫前台进程也叫服务器进程,翻译成英文叫server process。

它是实例的进程,

oracle会单独的给它分配一个PGA空间。

在客户端录入一条sql,

输入后回车,

如:

SQL> select * from dba_data_files;

执行后获得一堆数据。

这条语句在客户端输入,

然后通过客户端到实例的链接送给了server process。

在服务端,

sql语句通过网络送给oracle,被oracle的server process接受和接待。

server process接受到这个sql语句

然后做的事情

1、这条语句oracle认识,但不能直接运行

oracle需要将sql语句解析成执行计划然后才能执行。

2、解析后oracle拿着执行计划去执行。

解析的过程应该说是比较复杂的,

包括很多步骤

server process首先会判断sql语句语法有没有问题,如果有问题不会执行后面的操作。

还看一下,sql语句所涉及的表、视图在数据库里到底有没有。

接下来看一下输入sql语句的用户对sql语句所涉及的表和视图有没有权限。

还有一个重要的工作,

判断sql语句到底该怎么执行。

一条sql语句可以有N种执行方案,

这n中执行方案中有的执行方案是好的,有的是不好的。

这时候serverprocess要从这条sql语句的n个执行方案中找一个最优的执行方案。

然后生成执行计划。

在选择最优执行方案的过程中,它要访问很多对象,访问很多数据,

否则它不能凭空的判断哪个方案最优秀。

这时需要消耗很多的计算机资源

最主要消耗cpu资源,其次是IO资源,再者是内存资源。

既然解析会消耗资源,这时候会想到另外一个问题

A用户执行一条sql语句

这条sql语句需要解析,解析完生成执行计划。

A用户执行了。

B用户连上以后和A用户做相同的业务,

比如两个营业员都做的是取款,业务相同。

有可能执行相同的sql语句。

A用户执行时生成的执行计划,如果能够缓存起来的话,

B用户上来后,如果能够找到这个缓存的执行计划,

它就不需要经过解析了,可以直接拿着执行计划去执行。

在数据库里面就提到一个问题,

我们有没有必要对sql语句和sql语句所对应的执行计划进行缓存?

现在看有必要。

sql语句和sql语句所对应的执行计划我们缓存在shared pool中。

回顾一下:

一条sql语句在客户端输入,

通过网络到达oracle实例,

实例中server process来接收这条语句,

server process接收到后会拿着sql语句

首先进到shared pool里面,

要看一下这条sql语句在shared pool中有没有缓存。

如果有缓存,

这时server process会在shared pool中找到这条sql语句以及所对应的执行计划,

然后再去执行。

减少了解析的步骤。

如果server process在sharedpool中没有找到这条sql语句以及对应的执行计划,

这时server process 就会将sql进行解析,最终生成执行计划。

然后接着下一步去执行。

server process拿到sql语句要执行的第一件事情是:

找,

如果找不找它会去解析。

这两个过程都是server process所做的。

shared pool最主要的一个事情就是缓存sql语句和sql语句所对应的执行计划。

对shared pool的访问以及对sharedpool的修改这些操作都是serverprocess进程进行的。

二)buffer cache

SQL语句解析完,生成执行计划,接着要执行。

sql语句执行时,要去取数据

如语句:

select * from dba_data_files

要从dba_data_files表中取数据。

表的数据都在磁盘dbf文件里面,

这时还是server process要根据这个sql语句的执行计划去执行。

这个sql语句的执行计划从dbf里面取出数据,然后返给用户。

buffer cache 就是用来缓存dbf的数据。

非常有必要缓存。

因为A用户访问了某个表,B用户访问这个表的可能性也比较大。

A用户再来访问这个表的机会也比较大。

如果没有buffer cache的话,

每次访问dbf时,都要发生物理IO,数据库的性能会非常低。

当一个进程访问dbf访问我们的数据的时候,

如要访问一个表的数据,

因为server process知道有缓存buffer cache这个概念,

首先到buffer cache里面找这个表所对应的数据在buffer cache里面有没有。

如果有,server process直接访问buffer cache,

把所有的数据取出来,通过网络再返给客户端。

如果buffercache中没有它要找的数据,这个时候它就到磁盘dbf去找。

从dbf中把数据取出来,取出来不是直接返回给我们的用户,

取出来以后放到buffer cache里面去,

然后再从buffercache中返给我们的用户。

对oracle来讲,从dbf里面取数据,取到buffercache里面,为物理读,

这个操作是serverprocess来完成的。

讲两个概念:

逻辑IO

logic IO

物理IO

Physical IO

逻辑IO,

serverprocess执行sql语句的时候

从buffercache里面读,叫逻辑读,也叫内存读。

物理IO,

buffercache中找不到数据,

它就到磁盘上去读,这个读叫物理读,也叫磁盘读。

我们希望逻辑读多一些,物理读少一些。

这样会大大减少物理读的数量,进而提高数据库的访问速度。

命中率的概念

命中率在缓存里面时刻被提出来,

在buffercache里面有命中率,计算方法L/L+P,就是:逻辑读/逻辑读+物理读

命中率越高,说明逻辑读相对比较大,物理读相对比较小。

这是相对。

我们希望命中率高相对好一些。

命中率高意味着物理读少,逻辑读相对多一些。

物理读高IO就会很繁忙,数据库的速度就会比较慢。

比如:

oracle发生100次读,其中只有一次物理读99次逻辑读。

算法 99/99+1

命中率为99%。

这个时候我们就说,buffercache的命中率为99%。

oracle读数据100次 只有一次物理读,99次逻辑读。

大幅的提高了数据库的读的性能。这是好事。

对oracle数据库来讲,

命中率低肯定有问题。

命中率高不一定没有问题。

举例:

逻辑读10万,物理读1万

在一个时间段里面物理读也挺高。

计算命中率的时候我们发现,

因为逻辑读非常的大,命中率也很高,

但是数据库整体的服务速度也很慢。

所以说命中率低肯定有问题,命中率高不一定没有问题

有可能是因为逻辑读非常高,即使是物理读比较高,计算命中率也会很大。

命中率大我们就认为没问题,但不见得,我们要关心每秒的物理读。

其实有linux命令可以监控系统设备性能

1、vmstat 

vmstat是一个很全面的性能分析工具,

可以观察到系统的进程状态、内存使用、虚拟内存使用、磁盘的IO、

系统(中断、上下文切换)、CPU使用等

[oracle@redhat4 ~]$ vmstat

procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----

 r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa

 3  0    204  61596  39456 669880    0    0    13    35  303   174 48 22 30  0

2、iostat

iostat主要用于监控系统设备的IO负载情况,运行时显示系统的各项统计信息

[oracle@redhat4 ~]$ iostat

Linux 2.6.9-78.ELsmp (redhat4)  2016年07月14日

avg-cpu:  %user   %nice    %sys %iowait   %idle

          47.79    0.05   22.11    0.43   29.61

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn

sda               6.37        51.81       142.53    3267484    8989120

sda1              6.17        51.01       137.64    3216970    8680600

sda2              0.18         0.44         3.86      27814     243424

sda3              0.02         0.34         1.03      21716      65096

从这些数据可以知道 服务器整体是否繁忙。

不仅看命中率反馈问题,还要看物理读量的问题。

serverprocess在执行sql语句的时候,

需要从磁盘上dbf读数据的时候,

这个数据serverprocess从dbf里面读,

然后读到buffercache,然后从buffercache再返给用户。

三)DBWn LGWR进程

sql语句目前是对某个表进行读,

也有可能对某个表进行修改,进行删除,

sql分增删改查

我们以改为例,假设我们要修改某个表的数据

serverprocess还跟以前一样,把这个表读到内存里面去。

修改也要读到内存里面去,

serverprocess在内存里面对表进行修改。

修改的时候,oracle数据库对dbf数据库所有的修改都会产生日志。

日志也是serverprocess产生的。

产生日志以后会写到redologbuffer里面去。

修改完了要提交,

因为修改的是内存里面的数据,

内存的数据和dbf里面的数据就不一样了,

不一样就需要写回dbf,

是谁负责数据从内存写到硬盘,

不是serverporcess,是另外一个进程,叫dbwrite即DBWn进程

这个进程负责把serverprocess修改的数据写回磁盘,

是谁负责将redlog buffer里面的日志 写到redlog日志文件里面去

也不是serverprocess,是logwrite即LGWR进程

DBWn和LGWR都叫后台进程,

serverprocess叫前台进程。

serverprocess只是负责读出来数据在内存buffercache里面修改,

然后产生日志写到redologbuffer里面去,

它只负责这些事情。

它不负责把修改后的数据,写回磁盘,把日志写回磁盘,

由DBWn,LGWR负责。

为什么serverporcess只负责读不负责写入磁盘呢,

这其实是oralce设计的时候一个技巧所在。

serverprocess是直接为用户服务的,

用户把sql语句给了serverprocess,

serverprocess做几件事情,

对sql语句进行解析,然后执行,然后获取数据,获取数据后把结果返给用户。

serverprocess始终在和用户打交道,

如果serverprocess慢了,这时候用户会感到数据库慢。

我们就希望让serverprocess去做最有意义的工作,

对一些serverprocess可以不做的事情,交给别人去做。

这样用户会得到最好的用户体验。

serverprocess负责把数据读出来。

然后修改完了,把修改完的结果返给用户。

它对修改的结果,什么时候写回磁盘,它不去管,让DBWn去做。

因为什么时候写回磁盘,用户不关心,

用户只关心,我修改某个数据,然后告诉我数据修改好了,它只关心这个问题。

用户所关心的就是serverprocess所关心的。

所以我们把一些后台能够做的事情,

尽量的不给serverprocess去做,

让后台进程专门去做。

所以oracle数据库里面就有了后台进程的概念。

后台进程的特点是用户不知道,它在后面悄悄的做,

用户只关心我输入一个sql语句然后快速的得到结果。

serverprocess不关心一些写磁盘操作,

是后台进程去做。

所以产生了DBWn、LGWR这些进程。

所以有前台和后台进程。

我们在数据库优化,和数据库性能监控的时候,

我们主要关心的是serverprocess。

我们并不过多的关心DBWn和LGWR这些。

serverprocess的快慢直接反馈到数据库的快慢。

直接反馈到用户对数据库的一个感受。

不管后台进程有多忙,只要serverprocess快速轻松

用户就会感到快速轻松。

用户就会感到数据库很快。

可能这时后台进程非常的繁忙,这是我们理想的一个结果。

后台进程很轻松,但是serverprocess很忙

用户感到数据库很慢,

你发现数据库的cpu占用率不高。

这是一个比较不好的结果。

在oracle数据库里面我们非常关心的一个进程是serverprocess。

以后优化的时候,我们经常去看那个serverprocess目前很忙。

哪个serverprocess目前很慢。

这是我们的一个下手点。

四)CKPT进程、SMON、PMON

还有一个检查点进程,也是oracle的一个进程。

五大后台进程之一。

这个进程是周期性运行的,

DBWn和LGWR也是周期运行,但频率比较高,负载相对比较大,都比较忙。

特别是DBWn很忙。

但是CKPT(检查点进程)这个进程它比较轻松,

只是周期性运行,

把数据库当前的一些状态信息写到控制文件和数据文件的头部。

每个数据文件的头部都记录着一些这个数据文件的状态信息。

checkpoint这个进程,它负责更新控制文件和数据文件的头部。

它的负载是比较轻的。

几乎没有什么事可干。

还有两个进程

SMON(系统监视器)

这个进程是对数据库实例进行维护的

举一个例子

共享池里面放的sql语句和执行计划

用的时间长了,里面可能出现很多碎片。

这时SMonitor会对这些碎片进行整合。

也就是说SMonitor负责对数据库实例内部进行清理和维护的。

它主内。

PMON(进程监视器)

它主外

主内是指对SGA内部进行一些维护。

主外是对serverprocess进行维护。

例子

客户网络突然断了,serverprocess还一直为用户启着。

PMonitor会周期性的启动,

启动后发现某个serverprocess它所对应的客户已经死掉了,

他会把这个serverprocess进行清理。

包括把这个serverprocess进程关掉,

把这个serverprocess所对应的PGA内存空间,给它清理。

PMonitor主外 SMonitor主内

现在讲了五大进程。

五)ARCn进程

数据库文件还有一种归档日志文件。

oracle数据库里面有很多日志

[oracle@redhat4 jiagulun]$ ls

control01.ctl  example01.dbf  redo03.log    temp01.dbf

control02.ctl  redo01.log     sysaux01.dbf  undotbs01.dbf

control03.ctl  redo02.log     system01.dbf  users01.dbf

可看到数据库里面有很多.log日志。

oracle有redolog,它又分成多组,默认分成三组

首先oracle使用第一组日志,往里记日志,时间长了第一个日志文件满了。

它开始用第二组,第二组满了用第三组,

第三组满了它反过来用第一组。

就把第一组覆盖了。

oracle最多只能保持三组日志。

想保留更多的日志,

因为日志的作用有很多,

oracle就产生了一个归档的一个工作模式。

先写第一组日志,写满了这时候

oracle会启动一个进程叫ARCn。

这个进程会把日志归档到另外一个目录底下去,另外起一个名字,

大小和它一样。

然后开始写第二个日志log文件,第二个写满切到第三个的时候,

这个进程把第二个log日志写到归档到的那个目录下。

然后写第三个、第四个。

在归档这个位置,

保留了oracle所有的日志

我们要找较早的数据较早的日志会从归档中找。

我们通过讲一条sql语句,

讲了从请求进来到获取数据到返给用户的一个工作流程。

进一步的oracle实例结构,给大家粗略的讲了一下,后面还会详细的讲。

六)buffercache中的数据块

服务器进程它首先会从数据库数据文件里面读数据出来,

同时服务器进程找数据的时候首先在内存里面找,在buffercache里面找。

服务器进程还会修改里面的数据。

修改完的数据是DBWn负责写;

服务器进程它会对buffercache进行读进行写,对磁盘数据文件只进行读。

buffercache写回数据文件需要DBWn。

缓冲区里面的数据,有几种情况。

已连接

干净

空闲或未使用



dbf中的数据读到内存SGA,

buffercache中的数据和磁盘dbf文件中的数据是一致的,

叫这个数据是干净的。

里面还有一些内存空间没有使用

这是空闲或未使用的。

还有对这个数据块,

serverprocess在内存里面把它的数据修改了,

内存里面的数据,和磁盘中的数据就不一致了。

这时的内存里面的数据叫脏数据。

脏数据就需要写回dbf文件。

写回来以后它俩又一致了,又成干净数据了。

还有在内存里面的数据

目前serverprocess正在对它读或者正在对它进行写,

那个瞬间,这个数据块叫pin住了。

翻译叫连接了。

写完以后马上成了脏数据了。

PIN是读写一瞬间,

对内存的读写瞬间速度非常快。

已连接就是pin住。

随着数据库的运行,

buffercache慢慢在被使用,

其内数据块有脏的、干净的、空闲的

再次把dbf中的一个数据调到内存的时候,它优先使用空闲的没使用过的。

如果buffercache中所有的数据都使用过了,没有空闲的,

它接着使用干净的。

因为干净的数据意味着磁盘上有一个和它一样的数据。

这样新数据可以覆盖掉干净的块。

再需要原来干净数据块时,可以再把原干净数据调入内存。

也就是说对buffercache来讲

干净的或者空闲的这些数据,内存数据是可以被重用的。

对脏的能不能不直接覆盖?

不能!

我们为了使用这个脏的数据块占用的内存空间,

比如说里面全是脏的,

我还需要再使用内存的时候,

就会触发DBWn,将脏块写回磁盘。

写回磁盘后原块就成干净的了,

干净的就可以被重用了。

这是buffercache中数据块的几个状态。

七)总结

前面给大家讲了一条sql语句进入oracle的一个整体的执行流程。

进一步将数据库的内存和进程结构,

以及一些物理结构的一些信息给大家讲了。

这就是oracle的一个整体的体系结构。

以后的课我们一块块的去讲。

包括物理结构、内存结构、进程结构等。

内存结构里面还有一块块内容,我们也会分开去讲。

oracle本身是计算机的一个软件,

和其它软件的结构其实是一样的,尽管某些部分各有各的特点。

计算机程序的结构,

只包括两部分:

数据部分 和 处理数据的代码。

这两个部分再根据需要和程序的目的,发生不同的变化。

程序最终的目的都是为了处理数据。

数据库的数据部分所占比例较大,

一般程序数据部分所占比例较小,

但都是为了处理它。

程序员把绝大部分精力都放在了代码上,但都是为了呈献最终的数据。

2016年7月17日 

文字:韵筝
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: