你可能相对较短的时间就掌握了书写基本SQL语句的技术。然而,写出高效运行的复杂SQL语句这项技能是需要你超越那些期基础知识的,因为你写的SQL能完成工作并不代表它们完成筣很好,本文将揭开SQL的神秘面纱来看看它从内到外是如何来执行的。本文将阐述基本的Oracle架构并介绍基于成本的查询优化器。你将会了解到为什么构造SQL语句的方法会影响优化器制定出最高效的执行计划及其是如何影响的。你可能已经知道了该做什么,但理解SQL是如何执行工作的将会有助于你使Oracle耗费更短的时间及资源来得出预想结果。
Oracle架构基础
要想真正发挥SQL的全部能力,你需要理解它的工作原理,也就是说你需要理解自己所写的SQL语句赖以执行的基础架构。
通常,术语“Oracle数据库”既用来指存储在硬盘上的内部存有数据的数据库文件,也指用来管理这些文件的内存结构。事实上,术语“数据库”归属于数据文件而“实例”则归属一内存结构。一个实例由系统全局内存区域(system global area,SGA)以及一系后台进程组成。每一个连接到数据库的用户都是通过一个客户端进程来进行管理的。客户端进程是与服务器进程相联结的,每一个服务器进程都是会被分配一块私有的内存区域,称为程序共享内存区域(Program global area)或进程共享内存区域(process grobal area,PGA),如下图。
SGA—共享池
共享池是内存中最关键的部分之一,特别对于SQL的执行来说,你写SQL语句的方法并不仅仅会影响到这一句SQL语句本身,数据库中正在执行的所有SQL语句结合在一起将会因为它们对共享池的影响而对总的性能和可扩展性带来巨大的影响。
共享池是Oracle缓存程序数据的地方。执行过的每一句SQL语句在共享池中都存有解析后的内容。共享池中存储这些语句的地方称为库高速缓存(library cache).即使在解析每一句之前,Oracle都会检查库高速缓存看其中是否已存在同样的语句,如果存在,Oracle就会直接从缓存中读取并使用该信息而不是将同样的语句再解析一遍。对于你运行的任何PL/SQL代码,情况也是这样的。非常妙的一点是,不管有多少个用户想要执行同样的SQL语句,Oracle通常都会只解析该语句一次,然后在所有想要使用的用户之间共享。也许从中你可以看出共享池是如何得名的。
你所写的SQL语句并不是存放共享池中的唯一内容,Oracle所使用的系弘参数也将存放在其中,在一块被称为数据字典高速缓存(dictionary cache)的区域,Oracle还会存储所有数据库的对象信息。一般来说,Oracle将你所能想到几乎所有东西都存在共享池中,正如你所想象的那样,这使得共享池成为一块非常繁忙和重要的内存区域。
因为分配给共享池的内存区域是有限的,所以当新语句执行时,原先已经加载的语句就不能长时间地放在其中,有种算法叫做最近最少使用算法(Least Recently Used,LRU),它可以用来管理共享池中的对象。其基本思想是保留那些使用最频繁的以及最近使用的语句。
当你写SQL语句的时候,需要牢记于心的一点是:为了最高效地使用共享池,语句需要可以共享,如果你所写的每一句语句都是唯一的,基本上就违背了设立共享池的初衷。语句其共享性越差,你将看到对于响应时间的影响也就会越大。
库高速缓存
在执行每一句语句时必然会发生的事情就是它必须被解析并载入到库高速缓存中,正如前面所提到地那样,库高带缓存是共享池中用来保存存之前已经解析过的语句区域。解析包括验证句的语法、检验提及的对象,以及确认该对象的用户权限。如果这些检查都通过了,下一个步骤就是要看看这个语句之前是不是执行过。如果是,Oracle将取回之前解析的信息并重用。这种类型的解析被称为软(soft)解析。如果该语句之前没有被执行过,那么Oracle就将执行所有的工作来为当前的语句生成执行计划,并且将它存在缓存中以便将来重用。这种类型的解析被称为硬(hard)解析。
硬解析比软解析需要的Oracle做工作要多得多,每次进行硬解析的时候,在能够实际执行语句之前,Oracle必须收集它所需要的所有信息。为了得到所需要信息,Oracle需要对数据字典进行一连串的查询。想要看到Oracle在硬解析过程都干了些什么,最简单的办法就是打开扩展的SQL追踪,执行一个语句然后查看追踪数据。扩展的SQL追踪能抓取执行过程所发生的每一个活动,因此你不仅能看到你所执行的语句,还能看到Oracle必须要的执行每一个语句。
下表是对查询select * from employees where department_id=60进行硬析过程中需要查询的系统表列表。
在硬解析过程中总共需要执行59次对系统对象的查询。而同样一个语句软解析不需要对系统对象进行任何查询,因为在初始的硬解析过程中所有的事情都已经做过了。硬解析需要占用的运算时间是0.060374秒,而软解析为0.000095秒。因此,正如你所看到的,软解析比硬解析要更令人向往。
为了确定一条语句是不是之前执行过,Oracle会去检查库高速缓存看是不是存在同样的语句。你可以通地查询v$sql视图来查看当前存放在库速缓存中的语句。这个视图列出了共享SQL区域的统计信息,并且包含了最初输入的SQL文本每个子成员的一行。如下图展示出了对employees表的3条不同的查询语句,紧接着列出了对v$sq视图的查询,展示了这3条语句分别在库高速缓所存在的信息。
未完待续....