Oracle 技术网

使用 OCI 开发基于 Oracle Database 11g 的 C 和 C++ 应用程序

<不要删除此文本,因为它是在浏览器中运行时生成的“主要”标题列表的占位符>

目的

在本教程中,您将在几个阶段中分析并执行 C 程序以了解 OCI 的特性和功能。

您将学习如何创建和使用报告(ADDM 报告 — Automatic Database Diagnostic Monitor,以及 AWR 报告 — Automatic Workload Repository)以对示例应用程序的性能和瓶颈问题进行分析。随着报告的运行,您分几个阶段来分析和优化示例程序。最终将产生一个高效的应用程序。

所需时间

大约 60 分钟。

前提条件

开始本教程之前,您应该:

1.

安装 Oracle Database 11g 第 2 版(如果尚未安装)

2.

安装 ODBC 驱动程序。

3.

下载 ocilab.zip 文件并将其解压缩到您的工作目录(即 /home/oci/ocilab)中。

概述

在本教程中,您将采用分步方式分几个阶段来运行和优化应用程序。从未经过优化的代码开始,每个阶段通过使用语句缓存、客户端结果集缓存等特性为这个未经优化的阶段添砖加瓦,最终使程序性能得以改善。几个阶段展示了 LOB 处理以及通过引用游标进行获取等特性。

AWR 报告和 ADDM 报告

Automatic Workload Repository (AWR) 是每个 Oracle Database 中内置的一个信息库。Oracle Database 定期生成所有重要统计信息和负载信息的快照并将这些快照存储在 AWR 中。

Automatic Database Diagnostic Monitor (ADDM) 能让 Oracle Database 对自身的性能进行诊断并确定可以解决所发现问题的方法。每次进行 AWR 统计捕获之后会都会自动运行该监视程序,从而使性能诊断数据随时可用。

要运行这些报告,可以使用本教程提供的 reports.sql 脚本。在您要查看的每个阶段中,由相应的 C 文件生成的可执行文件以及一些额外的参数将传递给该脚本 (reports.sql)。

使用 OCI 驱动程序开发 C 应用程序

OCI 概述

这里为了进行 OCI 分析所使用的 C 源代码文件名为 stage1.c、stage2.c、stage3.c、stage4.c、stage5.c、stage6.cstage7.c,另外还有一个名为 helper.c 的通用库文件,这里所有的阶段都将使用它。这些文件存放于 /home/oci/ocilab 位置。.

在本节中,您将查看一个 OCI 应用程序的 7 个阶段。阶段 2、3、4、5 展示与性能有关的 OCI 特性,而阶段 6 和阶段 7 展示 OCI 中的 PLSQL 和(安全)LOB 支持。通过对示例应用程序生成 ADDM 和 AWR 报告,您可以对性能和瓶颈问题进行分析。 将对阶段 1、2、3、4 和 5 生成这些报告。

每个阶段基于上一阶段进行的代码更改而构建。要查看代码更改,可使用 tkdiff 实用程序对照上一阶段的代码查看当前阶段的代码。

示例应用程序

示例应用程序使用 ocihol/welcome 模式。它生成随机编号,模拟 Web 输入来更新和查询 MYEMP 表。

ocihol 模式中定义了以下对象:

MYEMP 表的定义为:

CREATE TABLE myemp (
 empno number(4) primary key,
 ename varchar2(10),
 job varchar2(9),
 mgr number(4),
 hiredate date,
 sal number(7,2),
 comm number(7,2),
 deptno number(2))
; 
为了演示客户端结果缓存特性,除了上表外,还使用以下对象:
CREATE TABLE regions (
 region_id NUMBER CONSTRAINT region_id_nn NOT NULL,
 region_name varchar2(25)) ; 
CREATE OR REPLACE VIEW empview as
 select * from myemp
;

为了演示 LOB 特性,定义了下表:

CREATE TABLE lob_table (
 lobid number primary key,
 lobcol clob) LOB(lobcol) 
  STORE AS SECUREFILE (TABLESPACE SYSAUX COMPRESS low CACHE)
;

在该 OCI 应用程序中使用了以下三个过程:

其主要的 C 函数为:

要对各个阶段的源代码进行编译和链接,可以使用 make 实用程序。

第 1 阶段:准备

本节不进行任何优化。这里 main 线程生成所请求数量的线程,并且以一个线程函数 (thread_function()) 作为每个线程开始时应调用的初始例程。“main”线程生成新线程。

每个线程执行以下操作:

1 .

打开一个终端窗口。

转到 /home/oci/ocilab 目录下,启动 SQL*Plus。以 system 用户身份登录。使用口令“manager”。

查看 stage1.c 文件的内容。可使用一个文本编辑器来查看内容。

注意:如果当前的工作环境为 Linux,可能需要更改权限以便执行 stagen 文件。为此,在命令提示符处执行以下命令:


chmod 777 stage*
exit 

2 .

使用 gmake 实用程序生成 stage1 源代码的 C 可执行程序和库。打开一个终端窗口,转到(用“cd”命令)阶段文件所在位置 (/home/oci/ocilab),执行 gmake 实用程序。

cd $HOME/oci/ocilab
gmake stage1 

 

3 .

reports.sql 脚本存放在 $HOME/oci/ocilab/sql 目录中。在一个新的终端会话中,转到 $HOME/oci/ocilab/sql 目录。

cd $HOME/oci/ocilab/sql 

启动 SQL*Plus。在您的 SQL*Plus 会话中,运行 reports.sql 脚本。将 stage1 文件传递给该脚本。添加参数,指定迭代 10 次以增加负载并生成结果。

(注意:我们有意将迭代次数设置为 10 这么一个较低的值,目的是节省此练习的时间。而对于此阶段生成的固有的报告,迭代次数设置为 500。)

@reports.sql "../stage1 -i 10" 

报告运行时会显示完成百分比。

4 .

当提示输入报告名称时,请输入:
stage1_oci 

这会生成两个报告,它们保存在当前目录中:

    • stage1_oci_addm.txt — ADDM 报告。
    • stage1_oci_awr.html — AWR 报告。

每个阶段都会为您提供生成的示例结果。这些文件位于 /home/oci/ocilab/doc 子文件夹下。这些示例结果文件名为:

    • stage1_results_addm.txt — ADDM 报告。
    • stage1_results_awr.html — AWR 报告。

注意:由于环境不同,您的结果可能会与提供的示例结果不同。为了本教程内统一起见,我们查看的是生成的示例结果。

 

5 .

查看 stage1_results.txt 报告内容。

(您可以在一个文本编辑器中打开该文件,也可以在您的 SQL*Plus 会话中向上滚动查看该文件。)

注意 Summary of Findings 部分。

 

6 .

查看 stage1_results_awr.htm 报告内容。

找到 stage1_results_awr.htm 文件。双击文件名,在浏览器中打开该文件(或右键单击并选择 Open with "Web-Browser" 选项)。

查看该报告。

向下滚动到 Main Report。单击 SQL Statistics 链接。

注意 Elapsed Time 统计信息 和 SQL 执行次数。随着您经历每个阶段并采用不同的调优方法,这些数值将改变(将改善)。

 

第 2 阶段:使用数组 Fetch 和数组 DML

本节将针对数组 fetch 和数组 DML 进行 C 代码优化。使用一个数组执行多行获取,该数组针对每次获取可保存 ARRAY_SIZE 行。

注意:此示例使用常规的前向滚动游标。OCI 还支持只读可滚动游标,从而允许在任何方向(前向、后向)以随机访问方式执行 fetch。结果集基于查询执行时的快照。您须在 OCIStmtExecute() 中设置一个特殊的模式以将查询结果集标记可滚动的。然后使用 OCIStmtFetch2() 滚动结果。详情参见 OCI 文档。

1 .

查看 stage2.c 文件内容,将其与 stage1.c 文件内容比较。您可以使用 tkdiff 实用程序查看两者间的不同之处。

执行以下命令查看 stage2.cstage1.c 文件。

tkdiff stage1.c stage2.c 

注意这两个文件的不同之处。在 stage2.c 中使用了数组 DML 和数组 fetch。

I

 

2 .

使用 gmake 实用程序生成 stage2 源代码的 C 可执行程序和库。打开一个终端窗口,转到(用“cd”命令)阶段文件所在位置 (/home/oci/ocilab),执行 gmake 实用程序。

cd $HOME/oci/ocilab
gmake stage2

 

3 .

在您的 SQL*Plus 会话中,运行 reports.sql 脚本。将 stage2 文件传递给该脚本。添加参数,指定迭代 500 次以增加负载并生成结果。

@reports.sql "../stage2 -i 500"

报告运行时会显示完成百分比。

4 .

当提示输入报告名称时,请输入:
stage2_oci

这会生成两个报告,它们保存在当前目录中:

    • stage2_oci_addm.txt — ADDM 报告。
    • stage2_oci_awr.html — AWR 报告。

每个阶段都会为您提供生成的示例结果。这些文件位于 /home/oci/ocilab/doc 子文件夹下。这些示例结果文件名为:

    • stage2_results_addm.txt — ADDM 报告。
    • stage2_results_awr.html — AWR 报告。

注意:由于环境不同,您的结果可能会与提供的示例结果不同。为了本教程内统一起见,我们查看的是生成的示例结果。

 

5 .

查看 stage2_results.txt 报告内容。

(您可以在一个文本编辑器中打开该文件,也可以在您的 SQL*Plus 会话中向上滚动查看该文件)

注意 Summary of Findings 部分。

注意 Finding 2 建议使用中间层连接池。我们将在第 3 阶段进行此优化。

 

6 .

查看 stage2_results_awr.htm 报告内容。

找到 stage2_results_awr.htm 文件。双击文件名,在浏览器中打开该文件(或右键单击并选择 Open with "Web-Browser" 选项)。

查看该报告。

向下滚动到 Main Report。单击 SQL Statistics 链接。

注意 Elapsed Time 统计信息 和 SQL 执行次数。随着您经历每个阶段并采用不同的调优方法,这些数值将改变(将改善)。

 

第 3 阶段:OCI 客户端会话池

此阶段将启用 OCI 会话池,除此之外与第 2 阶段相同。这可通过在新方法 create_session_pool() 中使用 OCISessionPooling API 动态设置以下配置选项来实现。

thread_function() 中,每个线程经每次迭代获得一个会话时,该会话来自会话池而不是每个线程每次迭代都创建和删除会话(以及连接)。

注意:


1 .

查看 stage3.c 文件内容,将其与 stage2.c 文件内容比较。您可以使用 tkdiff 实用程序查看两者间的不同之处。

执行以下命令查看 stage3.cstage2.c 文件。

tkdiff stage2.c stage3.c 

注意这两个文件的不同之处。在 stage3.c 中使用了 OCI 会话池。

注意:如果当前的工作环境为 Linux,可能需要更改权限以便执行 stagen 文件。为此,在命令提示符处执行以下命令:


chmod 777 stage*
exit 

2 .

使用 gmake 实用程序生成 stage3 源代码的 C 可执行程序和库。打开一个终端窗口,转到(用“cd”命令)阶段文件所在位置 (/home/oci/ocilab),执行 gmake 实用程序。

cd $HOME/oci/ocilab
gmake stage3

 

3 .

在您的 SQL*Plus 会话中,运行 reports.sql 脚本。将 stage3 文件传递给该脚本。添加参数,指定迭代 1000 次以增加负载并生成结果。

@reports.sql "../stage3 -i 1000

报告运行时会显示完成百分比。

4 .

当提示输入报告名称时,请输入:
stage3_oci

这会生成两个报告,它们保存在当前目录中:

    • stage3_oci_addm.txt — ADDM 报告。
    • stage3_oci_awr.html — AWR 报告。

每个阶段都会为您提供生成的示例结果。这些文件位于 /home/oci/ocilab/doc 子文件夹下。这些示例结果文件名为:

    • stage3_results_addm.txt — ADDM 报告。
    • stage3_results_awr.html — AWR 报告。

注意:由于环境不同,您的结果可能会与提供的示例结果不同。为了本教程内统一起见,我们查看的是生成的示例结果。

 

5 .

查看 stage3_results.txt 报告内容。

(您可以在一个文本编辑器中打开该文件,也可以在您的 SQL*Plus 会话中向上滚动查看该文件)

注意 Summary of Findings 部分。

在第 2 阶段中,Finding 2 为“Session Connect and Disconnect”— 它建议减少连接和断开连接次数。在第 3 阶段中,您现在看不到这个减少连接和断开连接次数的建议了(即已启用了连接池)。

 

6 .

查看 stage3_results_awr.htm 报告内容。

找到 stage3_results_awr.htm 文件。双击文件名,在浏览器中打开该文件(或右键单击并选择 Open with "Web-Browser" 选项)。

查看该报告。

向下滚动到 Main Report。单击 SQL Statistics 链接。

注意 Elapsed Time 统计信息。随着您经历每个阶段并采用不同的调优方法,这些数值将改变(将改善)。

 

第 4 阶段:启用了客户端语句缓存特性的 OCI

此阶段将启用客户端语句缓存特性,除此之外与第 3 阶段相同。这将通过在 OCI Session Pool 上设置语句缓存大小并在 OCISessionPoolCreate() 调用中指示使用此特性来实现。

调用了 OCIStmtPrepare2() 之后,会检查客户端缓存中是否存在该 SQL 文本。每个客户端会话有一个缓存。如果未找到匹配项,则会转到服务器端进行一次(软)解析调用并缓存此语句。(应用程序中同一线程)在同一会话中进行下一次 OCIStmtPrepare2() 调用时将重用这个经过解析的语句。这可减轻服务器上的软解析负载。


1 .

查看 stage4.c 文件内容,将其与 stage3.c 文件内容比较。您可以使用 tkdiff 实用程序查看两者间的不同之处。

执行以下命令查看 stage4.cstage3.c 文件。

tkdiff stage3.c stage4.c

注意这两个文件的不同之处。在 stage4.c 中启用了 OCI 语句缓存特性。

注意:如果当前的工作环境为 Linux,可能需要更改权限以便执行 stagen 文件。为此,在命令提示符处执行以下命令:


chmod 777 stage*
exit 

2 .

使用 gmake 实用程序生成 stage4 源代码的 C 可执行程序和库。打开一个终端窗口,转到(用“cd”命令)阶段文件所在位置 (/home/oci/ocilab),执行 gmake 实用程序。

cd $HOME/oci/ocilab
gmake stage4

 

3 .

在您的 SQL*Plus 会话中,运行 reports.sql 脚本。将 stage4 文件传递给该脚本。添加参数,指定迭代 1000 次以增加负载并生成结果。

@reports.sql "../stage4 -i 1000"

报告运行时会显示完成百分比。

4 .

当提示输入报告名称时,请输入:
stage4_oci

这会生成两个报告,它们保存在当前目录中:

    • stage4_oci_addm.txt — ADDM 报告。
    • stage4_oci_awr.html — AWR 报告。

每个阶段都会为您提供生成的示例结果。这些文件位于 /home/oci/ocilab/doc 子文件夹下。这些示例结果文件名为:

    • stage4_results_addm.txt — ADDM 报告。
    • stage4_results_awr.html — AWR 报告。

注意:由于环境不同,您的结果可能会与提供的示例结果不同。为了本教程内统一起见,我们查看的是生成的示例结果。

 

5 .

查看 stage4_results.txt 报告内容。

(您可以在一个文本编辑器中打开该文件,也可以在您的 SQL*Plus 会话中向上滚动查看该文件)

注意 Summary of Findings 部分。

 

6 .

查看 stage4_results_awr.htm 报告内容。 将 AWR 中的解析调用与上一阶段的解析调用进行比较,可以看出调用次数大幅减少。这是因为启用了客户端语句缓存特性。

找到 stage4_results_awr.htm 文件。双击文件名,在浏览器中打开该文件(或右键单击并选择 Open with "Web-Browser" 选项)。

查看该报告。

向下滚动到 Main Report。单击 SQL Statistics 链接。

注意 Elapsed Time 统计信息。随着您经历每个阶段并采用不同的调优方法,这些数值将改变(将改善)。

 

第 5 阶段:启用 OCI 客户端结果集缓存特性

此阶段将启用客户端结果集缓存特性,除此之外与第 4 阶段相同。为此,我们将:

注意:

  1. 需要使用如下初始化参数在服务器上启用客户端结果缓存特性:
    • CLIENT_RESULT_CACHE_SIZE
    • CLIENT_RESULT_CACHE_LAG
    • COMPATIBLE 设置为 11.2.0.0.0(以获取对视图的缓存),否则,将 compatible 设置为 11.1.0.0.0 就足够了。注意,一旦以更高的值 11.2.0.0.0 启动了数据库,您就无法将 compatible 更改为 11.1.0.0.0 了。
  2. 您可通过执行以下语句来更改对 regions 表的结果缓存设置:
    “alter table regions result_cache (mode default)”
    这会使 OCI 客户端查找任何存在的查询级提示,但由于不存在查询级提示,当前不会对 query_salary() 中的查询结果进行缓存。
  3. 查询级提示将覆盖表批注:
    • /*+ no_result_cache */ — 这将确保不对查询进行缓存。默认为不进行缓存,除非存在
    • /*+ result_cache */ — 查询级提示,或者查询中的所有表被批注为结果查询。
  4. method query_salary( ) 添加了一个额外的 fetch 调用以捕获 OCI_NO_DATA 错误。这是为了确保我们获取了所有的记录行,从而使缓存的结果集可用于后续缓存匹配。

1 .

您需要使用 alter table DDL 语句对 regions 表建立结果缓存。stage5.sql 脚本包含以下语句:

-- STAGE 5
-- annotate table for result caching so queries on it can be cached on
-- client result cache
-- Doing below part of stage5 in separate script so can see
-- performance difference in AWR reports.
ALTER TABLE regions result_cache (mode force); QUIT;

在 SQL*Plus 会话中,以 ocihol/welcome 用户身份进行连接并运行 stage5.sql 脚本:

CONNECT ocihol/welcome
@stage5.sql

 

2 .

查看 stage5.c 文件内容,将其与 stage4.c 文件内容比较。您可以使用 tkdiff 实用程序查看两者间的不同之处。

执行以下命令查看 stage5.cstage4.c 文件。

tkdiff stage4.c stage5.c

注意这两个文件的不同之处。在 stage5.c 文件中启用了 OCI 客户端结果集缓存特性。

注意:如果当前的工作环境为 Linux,可能需要更改权限以便执行 stagen 文件。为此,在命令提示符处执行以下命令:


chmod 777 stage*
exit 

3 .

使用 gmake 实用程序生成 stage5 源代码的 C 可执行程序和库。打开一个终端窗口,转到(用“cd”命令)阶段文件所在位置 (/home/oci/ocilab),执行 gmake 实用程序。

cd $HOME/oci/ocilab
gmake stage5

 

4 .

在您的 SQL*Plus 会话中,运行 reports.sql 脚本。将 stage5 文件传递给该脚本。添加参数,指定迭代 1000 次以增加负载并生成结果。

@reports.sql "../stage5 -i 1000"

报告运行时会显示完成百分比。

5 .

当提示输入报告名称时,请输入:
stage5_oci

这会生成两个报告,它们保存在当前目录中:

    • stage5_oci_addm.txt — ADDM 报告。
    • stage5_oci_awr.html — AWR 报告。

每个阶段都会为您提供生成的示例结果。这些文件位于 /home/oci/ocilab/doc 子文件夹下。这些示例结果文件名为:

    • stage5_results_addm.txt — ADDM 报告。
    • stage5_results_awr.html — AWR 报告。

注意:由于环境不同,您的结果可能会与提供的示例结果不同。为了本教程内统一起见,我们查看的是生成的示例结果。

 

6 .

查看 stage5_results.txt 报告内容。

(您可以在一个文本编辑器中打开该文件,也可以在您的 SQL*Plus 会话中向上滚动查看该文件)

注意 Summary of Findings 部分。

 

7 .

查看 stage5_results_awr.htm 报告内容。

找到 stage5_results_awr.htm 文件。双击文件名,在浏览器中打开该文件(或右键单击并选择 Open with "Web-Browser" 选项)。

查看该报告。

向下滚动到 Main Report。单击 SQL Statistics 链接。

注意,在 AWR 的“SQL Ordered by Executions”部分,对以下两者在服务器上的执行次数减少了:

i. 具有查询级提示的 SQL:

select /*+ result_cache */ empno, ename
from empview where empno > :EMPNO order by empno

ii.使用结果缓存表批注的查询:

select region_id, region_name from regions where region_id = :regionID

与服务器上 20 个线程 * 1000 次迭代 = 20,000 次执行相比,上述两种查询表现出少得多的服务器上执行次数。这有利于 SQL 网络流量和 CPU 使用。

另请注意,这里有更新,但其频度已从 20,000 减少到 200(即每个线程每 100 次迭代更新一次)。实际上,客户端上缓存的结果集不是经常失效。

如果您提高对表 myemp 的更新频度(例如,每个线程每次迭代进行一次),您将看到上述查询 i (具有 empview 视图上的查询级提示)在服务器上的执行次数增加,又回到了 20,000。我们不建议这样做,因为客户端结果缓存将用于只读或读取大多数数据。不然会导致对结果集进行缓存和使之失效方面的更多开销。

 

第 6 阶段:使用 PL/SQL 过程和引用游标

在此阶段中,我们将展示 OCI 中对 PLSQL 调用的支持。这里的存储过程定义于 createtables.sql 脚本中并且将为此阶段中新添的以下 C 方法所使用。