下面分享一些非常详细的DML(Data manipulation language)语句的处理过程
首先,每一种语句都需要如下阶段:
- 第 1 步:Create a cursor 创建游标
- 第 2 步:Parse the statement 分析语句
- 第 5 步:Bind any variables 绑定变量
- 第 7 步:Run the statement 运行语句
- 第 9 步:Close the cursor 关闭游标
如果使用了并行功能,还会包含下面这个阶段:
- 第 6 步:Parallelize the statement 并行执行语句
如果是查询语句,则需要几个额外的步骤:
- 第 3 步:Describe results of a query 描述查询结果集
- 第 4 步:Define output of a query 定义查询输出数据
- 第 8 步:Fetch rows of a query 取出查询的行
下面对以上处理步骤进行详细的解释:
第 1 步:Create a cursor 创建游标
首先,什么是游标呢?游标就是sql语句的一个内存工作区,由系统或者用户以变量的形式创建。游标的作用就是将数据库数据块从磁盘中提取到临时存储,这样数据处理的速度会提高。
创建游标过程由程序接口调用创建一个游标(cursor)。任何SQL语句都会创建它,特别是在运行DML语句时,都是自动创建游标,不需要开发人员干预。多数应用中,游标的创建时自动的。然而,在预编译程序和存储过程中,游标的创建可能是隐含的,也可能是显式的创建。
第 2 步:Parse the statement 分析语句
在语法分析期间,SQL语句从用户进程传送到Oracle,SQL语句经语法分析后,SQL语句本身与分析的信息都被装入到共享sql区。在该阶段,可以解决许多类型的错误。关于什么是共享SQL区,可以具体参考这篇文章。
语法分析过程会分别执行下列操作:
- 翻译sql语句,验证它是否合法,即是否书写正确。
- 实现数据字典的查找,以验证是否符合表和列的定义
- 在所要求的对象上获取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义
- 验证为存取所涉及的模式对象所需的权限是否满足
- 决定该sql语句的最佳执行计划
- 将它装入共享sql区
- 对于分布的语句来说,把语句的全部或者部分路由到包含所涉及的数据的远程节点。
以上任何一步出错,都将导致语句报错,终止执行
但是对sql语句进行的语法分析会非常耗费资源,因此只有在sql共享池中不存在等价的sql语句的情况下,才对sql语句做语法分析。在这种情况下,数据库内核重新为该语句分配新的共享sql区,并对语句进行语法分析。
虽然语法分析验证的sql语句的正确性,但是语法分析只能识别sql语句执行前所能发现的错误(如书写错误,权限不足等)。因此有些错误通过语法分析是抓不到的。例如,在数据转换中的错误或者在数据中的错误(如企图在主键中插入重复的值)以及死锁等是只有在语句执行阶段才能遇到和报告的错误或情况。
第 3 步:Describe results of a query 描述查询结果集
描述阶段只有在查询结果的各个列是未知时才需要;例如,当查询需要由用户交互的输入的列名。在这种情况要用描述阶段来决定查询结果的特征(数据类型、长度和名字)。
第 4 步:Define output of a query 定义查询输出数据
在查询的定义阶段,需要由开发者指的与查询出的列值对应的接收变量的位置、大小和数据类型,这样我们通过接收变量就可以得到查询结果。如果必要的话,Oracle会自动实现数据类型的转换。这是将接收变量的类型与对应的列类型相比较决定的。
第 5 步:Bind any variables 绑定变量
经过前面几个步骤后,Oracle知道了sql语句的意思,但是仍然没有足够的信息用于执行该语句。Oracle需要得到在语句中列出的所有变量的值。它需要得到对指定列进行限定的值。得到这个值的过程就称为绑定变量。
在此过程中程序必须指出类找到该数值的变量名(该变量称为捆绑变量,变量名实质上是一个内存地址,相当于指针)。应用的最终用户可能并没有发觉他们正在指定捆绑变量,因为Oracle的程序可能只是简单的指示他们输入新的值。
因为你指定了变量名,在你再次执行之前无序重新捆绑变量。你可以改变绑定变量的值,而Oracle在每次执行时,仅仅使用内存地址来查找此值。
第 6 步:Parallelize the statement 并行执行语句
Oracle可以在SELECT,INSERT,UPDATE,MERGE,DELETE语句中执行相应的并行查询操作。除此之外,对某些DDL的操作,如创建索引,用子查询创建表、在分区表上的操作也都可以执行并行操作。并行操作可以是多个服务器进程为同一个SQL语句工作,使得该sql可以快速完成,但是会耗费更多资源
第 7 步:Run the statement 运行语句
在这个阶段,如果该语句为SELECT查询或者INSERT语句,则不需要锁定任何行,因为没有数据需要被改变。如果有数据需要被改变,比如UPDATE或DELETE语句,则该语句影响的所有行都被锁定,防止该用户提交或者回滚之前,别的用户对这些数据进行修改。这就可以保证数据的一致性。
对于某些语句,可以指定执行次数,这称为批处理。指定执行N次,则绑定变量与定义变量被定义为大小为N的数组的开始位置,这种方法可以减少网络开销,也是优化的技巧之一。
第 8 步:Fetch rows of a query 取出查询的行
在fetch阶段,行数据被取出来,每个后续的存取操作检索结果集中的下一行数据,直到最后一行被提取出来。批量的fetch是优化的技巧之一。
第 9 步:Close the cursor 关闭游标