« | October 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | |
| 公告 |
数据仓库&数据挖掘
对某一件事需要坚持方能真正完成这件事
薛 峰
2009.02.03 |
Blog信息 |
blog名称:数据仓库与数据挖掘 日志总数:85 评论数量:14 留言数量:0 访问次数:723930 建立时间:2005年3月17日 |

| |
[综合]AIX 性能调优-内存、CPU篇 文章收藏, 网上资源
薛 峰 发表于 2005/7/25 11:09:42 |
sar -P ALL cpu使用情况
sar -a 文件访问情况 dirblk/s 定位文件时被目录访问守护进程读取的快(512b)的个数 iget/s i节点查找系统进程被调用次数 lookuppn/s 目录查找进程找到v节点,并获取路径名的次数
sar -b buffer的活动情况,包括传输、访问、和命中率 bread/s、bwrit/s 块IO操作的数量 lread/s、lwrit/s 逻辑 IO请求的个数 pread/s、pwrit/s 裸设备IO操作数量 %rcache、%rwrit cache命中率,计算共式为:((lreads-breads)/lreads)*100
sar -c 系统调用情况 exec/s、fork/s 调用和执行系统调用总数 sread/s、swrit/s read/writ 系统调用次数 rchar/s、wchar/s 被read/writ系统调用的字符数量 scall/s 系统调用总数
sar -k 内核进程活动情况 kexit/s 中断的内核进程数 kproc-ov/s 由于进程数的限制无法创建内核进程的次数 ksched/s 被作业分派的内核进程数
sar -m 消息队列和信号灯活动情况 msg/s IPC消息队列活动情况 sema/s 信号灯活动情况
sar -d 磁盘读写情况
sar -q 队列统计信息 run-sz 内核线程处于运行队列的平均数 %runocc 最近时间段运行队列占用百分比 swpq-sz 内核线程等待 页面调度的平均数 %swpocc 交换队列最近活动情况
sar -r 页面调度信息 cycle/s 每秒中页面置换次数 fault/s 每秒中page fault次数 slots 在页空间中空闲页数量 odio/s 每秒中不使用页面空间的磁盘io数
sar -v 进程、内核线程、i节点、和文件表 的状态
sar-w 上下文切换次数
sar -y tty设备活动情况 canch/s tty输入队列中规范的字符数 mdmin/s tty modem 中断 outch/s 输出队列字符数 rawch/s 输入队列字符数 revin/s tty接收中断 xmtin/s tty传输中断
如果CPU的使用率接近100%(usr+system),可以视为是CPU瓶颈。而如果相当大的时间都花费在IO等待上,那就意味着cpu执行受到了磁盘IO的限制, 而IO瓶颈可能来自于文件访问或者没有足够的内存来分配页面。 注意:系统花费在等待远程文件访问的时间不会记入io 等待时间,如果CPU和IO等待的时间都相当的低,但是响应时间又不是很满意,那应该确认系统 花费多少时间在等待远程io,一直一来aix下没有命令对远程io进行分析,只能通过跟踪数据来观察。
vmstat
vmstat命令报告内核线程,虚拟内存、磁盘、陷阱、和CPU活动情况。 Kthr 线程活动情况 r 运行队列 b 等待队列
memory 虚拟和实际内存使用情况 avm 活动的虚拟页面 fre 空闲的页面,当系统内存大于64MB时,最小值MINFREE为120frames,当内存小于64MB时,最小值为内存以MB计的两倍 MINFREE和MAXFREE值可以通过vmtune命令来查看
page page fault和page活动情况,当在内存里分配一个页面时(非NFS或者永久文件页面),其被视为工作页面,工作页面通常包括应用堆栈、 数据和其他的共享内存段。因此当一个程序栈或者数据区域需要增长时,内存会被被访问,vvm会从ram和页面空间所在设备分配空间。这就意味着 在内存耗尽之前,页面空间会被使用。 re 页面输入输出列表,每秒中内存回收数量,当页面处于空闲列表且没有被再利用,它就会被回收应为没有新的IO会初始化它,也包括那些没有完成的IO操作但又被VMM使用 预先读取算法调入内存的页面。 pi 从页面空间page in的页面 po 从页面空间page out的页面
fr 页面空闲(页面重置) sr 页面被页面调度算法扫描次数 cy 页面调度算法进行调度的时钟周期
faults 陷阱和系统中断率 in 设备中断 sy 系统调用 cs 内核线程上下文切换
CPU cpu使用情况 usr 用户进程 sys 系统进程 id cpu空闲时间 wa 等待磁盘IO时间
准则: r<5,b≈0, 如果fre<MINFREE,将会出现连续不断的页面调度,将导致系统性能问题。 对于page列,re,pi,po,cy维持于比较稳定的状态,PI率不超过5,如果有pagin发生,那么关联页面必须先进行pageout 在内存相对紧张的环境下pagein会强制对不同的页面进行steal操作。如果系统正在读一个大批的永久页面,你也许可以看到po和pi列 会出现不一致的增长,这种情景并不一定表明系统负载过重,但是有必要对应用程序的数据访问模式进行见检查。在稳定的情况下,扫描率和重置率几乎相等,在 多个进程处理使用不同的页面的情况下,页面会更加不稳定和杂乱,这时扫描率可能会比重置率高出。
faults列,in,sy,cs会不断跳跃,这里没有明确的限制,唯一的就是这些值最少大于100
cpu列,us,sys,id和wa也是不确定的,最理想的状态是使cpu处于100%工作状态,单这只适合单用户的情况下。 如果在多用户环境中us+sys》80,进程就会在运行队列中花费等待时间,响应时间和吞吐量就会下降。wa>40表明磁盘io没有也许存在不合理的平衡,或者对磁盘操作比较频繁,
|
|
[综合]AIX学习笔记 网上资源
薛 峰 发表于 2005/7/22 13:22:47 |
AIX学习笔记
AIX学习笔记
http://blog.chinaunix.net/article.php?articleId=14542&blogId=2284
AIX学习笔记
一、系统安装完成后,手工安装以下fileset : 1、将AIX作系统的第一张CD插入CD-ROM 驱动器,在系统提示处输入快速路径smitty install_all。在Input device / directory for software 选项中按F4 选择/dev/cd0。在SOFTWARE to install选项中键入: bos.acct bos.data bos.rte.control perfagent.tools bos.dosutil bos.perf bos.net bos.sysmgt bos.adt 2、在安装完上述软件包后,需要给系统打补丁。使用随AIX系统盘所带的Update CD或从IBM得到的最新的补丁盘。插入CD-ROM 驱动器,在系统提示处输入快速路径smitty update_all,在 Input device / directory for software 选项中按F4 选择/dev/cd0,将COMMIT software updates?选择 no ,将SAVE replaced files? 选择 yes 。服务更新完毕后按F10 退出。这可以保证在新的补丁出现问题时,可以退回以前的版本。当此补丁稳定运行了一段时间后,可以commit它。 3、可用如下命令检查当前系统所打的补丁: # instfix -i | grep ML 二、磁带机清洁的检查命令:#/usr/lpp/diagnostics/bin/utape -cd rmt0 –n 显示结果为磁带机使用的小时数,若大于72小时,则不论磁带机黄灯是否亮都应用清洁带清洗。 三、AIX内核属于动态内核,核心参数基本上可以自动调整,因此当系统安装完毕后,应考虑修改的参数一般如下: A、单机环境 1、系统用户的最大登录数maxlogin maxlogin的具体大小可根据用户数设定,可以通过smitty chlicense命令修改,该参数记录于/etc/security/login.cfg文件,修改在系统重新启动后生效。
2、系统用户的limits参数 这些参数位于/etc/security/limits文件中,可以把这些参数设为-1,即无限制,可以用vi 修改/etc/security/limits文件,所有修改在用户重新登录后生效。 default: fsize = 2097151 ----》改为-1 core = 2097151 cpu = -1 data = 262144 ----》改为-1 rss = 65536 stack = 65536 nofiles = 2000
3、Paging Space 检查paging space的大小,在物理内存<2G时,应至少设定为物理内存的1.5倍,若物理内存>2G,可作适当调整。同时在创建paging space时, 应尽量分配在不同的硬盘上,提高其性能。利用smitty chps修改原有paging space的大小或smitty mkps增加一块paging space。
4、系统核心参数配置 利用lsattr -Elsys0 检查maxuproc, minpout, maxpout等参数的大小。maxuproc为每个用户的最大进程数,通常如果系统运行DB2或ORACLE是应将maxuproc调整,Default:128、调整到500,maxuproc增加可以马上起作用,降低需要AIX重起。当应用涉及大量的顺序读写而影响前台程序响应时间时,可考虑将maxpout设为33, minpout设为16,利用smitty chgsys来设置。
5、文件系统空间的设定 一般来说,系统的文件系统/、/usr、/var、/tmp的使用率不要超过80%,/tmp建议至少为300M,文件系统满可导致系统不能正常工作,尤其是AIX的基本文件系统,如/ (根文件系统)满则会导致用户不能登录。用df 查看。
# df -k (查看AIX的基本文件系统) Filesystem 1024-blocks Free %Used Iused %Iused Mounted on /dev/hd4 24576 1452 95% 2599 22% / /dev/hd2 614400 28068 96% 22967 15% /usr /dev/hd9var 8192 4540 45% 649 32% /var /dev/hd3 167936 157968 6% 89 1% /tmp /dev/hd1 16384 5332 68% 1402 35% /home
利用smitty chfs扩展文件系统的空间。
6、激活SSA Fast-Write Cache 利用smitty ssafastw来激活每一个逻辑盘hdiskn的Fast-Write Cache:选择硬盘后,把Enable Fast-Write一项改为Yes后回车即可。
7、激活AIO AIO通常只对文件系统起作用,对裸设备没有作用。最大为10X并行磁盘数<80,最小为最大的一半。
a、定义系统中的AIO设备 smit aio -> Configure Defined Asynchronous I/O 然后回车执行; b、激活系统中的AIO设备 smit aio -> Change / Show Characteristics of Asynchronous I/O回车出现AIO配置对话框,将对话框中〔STATE to be configured at system restart〕域选择为“available”,然后回车执行; 注:系统会提示只有在重起后才能生效。
8、rootvg镜像 因为rootvg损坏系统将无法运行,即使通过备份磁带恢复,也会造成系统停机,因此在磁盘空间充裕的情况下,可考虑对rootvg作镜像,同时在建立rootvg镜像时应尽量使用连接在不同SCSI 上的硬盘以做到负载均衡。利用smitty mirrorvg修改。
B、双机环境 在双机环境中,除了考虑上述参数设置外,还需考虑: 1、 High water mark for pending write I/Os per file(maxpout) 和Low water mark for pending write I/Os per file 它们缺省值为0,在双机环境中一般应设High water mark为33,Low water mark为24,这两个参数可用smitty chgsys来设置。
2、 syncd daemon的数据刷新频率 该值表示刷新内存数据到硬盘的频率,缺省为60,一般可改为20,也可根据实际情况更改。该参数通过vi /sbin/rc.boot更改,其中一行如下: nohup /usr/sbin/syncd 60 >/dev/null 2>&1 & 改为: nohup /usr/sbin/syncd 20 >/dev/null 2>&1 &
四、IBM RS/6000巡检内容及操作指导
1. IBM RS6000小型机机房要求: a. 机房的卫生状况,要求清洁,键盘、显示器、机柜上没有灰尘。 b. 温度(摄氏 ℃):10 ℃-40℃ ,湿度(%):8% -80%
2. 设备故障灯分类:主机故障灯 面板上不能有数字显示,如果有的话,说明系统有故障。 7133磁盘阵列故障灯 告警灯为黄色表示有故障 磁带机故障灯 告警灯为黄色说明有故障或磁带机太脏,须清洗。
3. 系统错误报告(Error Log)的检查: 硬件故障检测命令:# errpt -d H -T PERM 若有故障执行命令# errpt -a -d H -T PERM>/tmp/harderror.log保存,分析结果报告给客户 软件故障检测命令:# errpt -d S -T PERM 若有故障执行命令# errpt -a -d S -T PERM>/tmp/softerror.log保存,分析结果报告给客户
4. 有否发给root用户的错误报告(mail):#mail a. 观察所有未读消息,注意有关diagela的消息。 b. 常用命令: h [] Display headings of group containing message t [] Display messages in or current message. n Display next message. q Quit c. 对发现的问题详细分析,结果报告给客户
5. 件系统的检查:命令:# df –k %Used为文件系统的使用率。所有文件系统的使用率不能大于80%
6.磁带机清洁的检查:命令: #/usr/lpp/diagnostics/bin/utape -cd rmt0 –n 显示结果为磁带机使用的小时数,若大于72小时,则不论磁带机黄灯是否亮都应用清洁带清洗。
7. 信系统的检测: a. 网卡的状态:命令: #ifconfig –a 输出判断: en0: flags=e080863 inet 192.9.200.2 netmask 0xffffff00 broadcast 192.9.200.255 en1: flags=e080863 |
|
[综合]ESQL/C资料(完全版)四 文章收藏, 网上资源
薛 峰 发表于 2005/7/18 10:34:55 |
5.3 嵌入SQL的处理过程 INFORMIX的预编译器为esql。嵌入SQL包含一些组件:嵌入SQL的库文件,提供访问数据库服务器、操作各种数据类型、出错信息的处理等函数。嵌入SQL的头文件(UNIX环境:$INFORMIXDIR/incl/esql下,WINDOWS环境:%INFORMIXDIR%\incl\esql下),提供程序用的数据结构、常数和宏的定义信息。Esql是预编译器。UNIX系统下,是finderr程序获得INFORMIX的错误信息,WINDOWS平台下是find error获得错误信息。还有一些GLS locale文件,提供一些特定的locale信息。在WINDOWS平台下,还有另外一些文件,如:setnet32、ilogin、regcopy、esqlmf程序。 创建嵌入SQL/C的程序的一般步骤:程序的后缀可以是.ec或.ecp。 1、定义宿主变量。 2、访问数据库。 3、操作。 4、完成后,使用esql命令来预编译。如:esql demo1.ec。在预编译后,程序中只有C语言语句,它们都可以为C语言的编译器所识别。所以,可以按照一般的方法进行编译和连接,但在将SQL语句转换以后,在C语言程序中,又引入了许多一般的C语言系统所没有的结构、变量和函数,因此应该设置INCLUDE和LIB的设置。最后生成的可执行文件。 5.4 动态SQL语言 所谓静态SQL的编程方法,就是指在预编译时SQL语句已经基本确定,即访问的表或视图名、访问的列等信息已经确定。但是,有时整个SQL语句要到执行的时候才能确定下来,而且SQL语句所访问的对象也要到执行时才能确定。这就需要通过动态SQL语句完成。动态SQL语句的处理步骤是: 1、组合SQL语句。 2、PREPARE。PREPARE语句是动态SQL语句独有的语句。其语法为: PREPARE 语句名 FROM 宿主变量|字符串 该语句接收含有SQL语句串的宿主变量,并把该语句送到DBMS。DBMS编译语句并生成执行计划。在语句串中包含一个“?”表明参数,当执行语句时,DBMS需要参数来替代这些“?”。PREPRARE执行的结果是,DBMS用语句名标志编译后的语句。在执行SQL语句时,EXECUTE语句后面是这个语句名。请看下面这个例子: EXEC SQL prepare slct_id from 'select company from customer where customer_num = ?'; 可以通过SQLCA检查PREPARE操作是否成功。 3、EXECUTE或OPEN。 EXECUTE语句的语法如下: EXECUTE 语句名 USING 宿主变量 | DESCRIPTOR 描述符名 它的作用是,请求DBMS执行PREPARE语句准备好的语句。当要执行的动态语句中包含一个或多个参数标志时,在EXECUTE语句必须为每一个参数提供值。这样的话,EXECUTE语句用宿主变量值逐一代替准备语句中的参数标志(“?”),从而,为动态执行语句提供了输入值。 如果是多行查询,则使用游标,使用OPEN USING语句传递参数;如果是单行查询,则使用SELECT INTO。如果是修改数据:则使用EXECUTE USING语句。如果知道参数个数,就可以使用宿主变量。如果不知道参数个数,则必须使用DESCRIBE语句。下表总结了动态SQL语句的处理方法: 语句类型是否有输入参数执行的方法 INSERT、DELETE、UPDATE没有EXECUTE INSERT、DELETE、UPDATE有(数据类型和个数确定)EXECUTE …USING INSERT、DELETE、UPDATE有(数据类型和个数不确定)EXECUTE...USINGSQL DESCRIPTOR或EXECUTE...USINGDESCRIPTOR SELECT(返回多行)无OPEN SELECT(返回多行)有(数据类型和个数确定)OPEN…USING SELECT(返回多行)有(数据类型和个数不确定)OPEN...USINGSQL DESCRIPTOR或OPEN...USINGDESCRIPTOR SELECT(返回一行)无EXECUTE...INTO SELECT(返回一行,但是返回的数据类型和个数不确定)无EXECUTE...INTODESCRIPTOR或EXECUTE...INTOSQL DESCRIPTOR SELECT(返回一行)有EXECUTE...INTO...USING SELECT(返回一行,但是返回的数据类型和个数不确定)有EXECUTE...INTO...USING SQLDESCRIPTOR或EXECUTE...INTO...USINGDESCRIPTOR
4、释放资源。 5.4.1 SQLDA 可以通过SQLDA为嵌入SQL语句提供输入数据和从嵌入SQ语句中输出数据。理解SQLDA的结构是理解动态SQL的关键。 我们知道,动态SQL语句在编译时可能不知道有多少列信息。在嵌入SQL语句中,这些不确定的数据是通过SQLDA完成的。SQLDA的结构非常灵活,在该结构的固定部分,指明了多少列等信息(如下图中的sqld=2,表示为两列信息),在该结构的后面,有一个可变长的结构(SQLVAR结构),说明每列的信息。
SQLDA结构 Sqld=2 sqlvar Desc_name Desc_occ Desc_next
Sqltype=500 Sqllen sqldata …..
Sqltype=501 Sqllen Sqldata …..
图6-6 SQLDA结构示例 具体SQLDA的结构在sqlda.h中定义,是: struct sqlvar_struct { short sqltype;/* variable type*/ short sqllen;/* length in bytes*/ char *sqldata;/* pointer to data*/ short *sqlind;/* pointer to indicator*/ char *sqlname;/* variable name*/ char *sqlformat;/* reserved for future use */ short sqlitype;/* ind variable type*/ short sqlilen;/* ind length in bytes*/ char *sqlidata;/* ind data pointer*/ };
struct sqlda { short sqld; struct sqlvar_struct *sqlvar; char desc_name[19];/* descriptor name */ short desc_occ;/* size of sqlda structure */ struct sqlda *desc_next;/* pointer to next sqlda struct */ };
#endif /* _SQLDA */ 从上面这个定义看出,SQLDA是一种由三个不同部分组成的可变长数据结构。位于SQLDA开端的sqldaid用于标志该SQLDA描述了多少列的信息;而后是一个或多个sqlvar结构 ,用于标志列数据。当用SQLDA把参数送到执行语句时,每一个参数都是一个sqlvar结构;当用SQLDA返回输出列信息时,每一列都是一个sqlvar结构。第三部分是SQLDA结构的描述信息部分。具体每个元素的含义为: lSqld。目前使用的sqlvar结构的个数。即输出列的个数。 lSqlvar。指向sqlvar_struct结构。 即指向描述第一列信息的sqlvar结构。 lDesc_name。Sqlda的名称。 lDesc_occ。Sqlda结构的大小。 lDesc_next。指向下一个SQLDA结构。 lSqltype。代表参数或列的数据类型。它是一个整数数据类型代码。具体每个整数的含义见第二节。 l Sqllen。代表传送数据的长度。如:2,即代表二字节整数。如果是字符串,则该数据为字符串中的字符数量。 lSqldata。指向数据的地址。注意,仅仅是一个地址。 lSqlind。代表是否为NULL。如果该列不允许为NULL,则该字段不赋值;如果该列允许为NULL,则:该字段若为0,表示数据值不为NULL,若为-1,表示数据值为NULL。 lSqlname。代表列名或变量名。它是一个结构。包含length和data。Length是名字的长度;data是名字。 lSqlformat。保留为以后使用。 lSqlitype。指定用户定义的指示符变量的数据类型。 lSqlilen。指定用户定义的指示符变量的长度。 lSqlidata。指向用户定义的指示符变量所存放的数据。
下面这个ADHOC程序非常经典,演示了SQLDA的作用。模拟一个不确定的查询,然后通过SQLDA来获得数据,并打印出来。 EXEC SQL include locator.h; EXEC SQL include sqltypes.h; #define BLOBSIZE 32276; main() { int i = 0; int row_count; /**** Step 1: 声明一个SQLDA结构,来存放查询的数据 ********/ struct sqlda *da_ptr; /*连接到数据库服务器*/ EXEC SQL connect to 'stores7'; if ( SQLCODE < 0 ) { printf("CONNECT failed: %d\n", SQLCODE) exit(0); } /* 创建一个临时表,模拟一个不确定列和表的环境*/ EXEC SQL create table blob_tab (int_col integer, blob_col byte); /* load_db函数是往blob_tab表插入数据,读者不用关心它的代码*/ load_db(); /* PREPARE查询语句 */ EXEC SQL prepare selct_id 'select * from tab1'; /* Step 2: 使用describe函数完成两个功能:一是为sqlda分配空间, 二是获取语句信息,并存放在SQLDA结构中。*/ EXEC SQL describe selct_id into da_ptr; /* Step 3: 初试化sqlda结构,如:为列分配空间,改变数据类型等。*/ row_size = init_sqlda(da_ptr, 0); /* 为PREPARE的SELECT语句声明和打开游标*/ EXEC SQL declare curs for selct_id; EXEC SQL open curs; while (1) { /* Step 4: 执行fetch操作,将一行数据存放在sqlda结构中*/ EXEC SQL fetch curs using des |
|
[综合]ESQL/C资料(完全版)三 文章收藏, 网上资源
薛 峰 发表于 2005/7/18 10:34:26 |
第四节 ORACLE数据库的嵌入SQL语言 4.1 基本的SQL语句 4.1.1宿主变量和指示符 1)、声明方法 同其他数据库管理器一样,ORACLE使用宿主变量传递数据库中的数据和状态信息到应用程序,应用程序也通过宿主变量传递数据到ORACLE数据库。根据上面两种功能,宿主变量分为输出宿主变量和输入宿主变量。在SELECT INTO和FETCH语句之后的宿主变量称作“输出宿主变量”,这是因为从数据库传递列数据到应用程序。除了SELECT INTO和FETCH语句外的其他SQL语句中的宿主变量,称为“输入宿主变量”。这是因为从应用程序向数据库输入值。如:INSERT、UPDATE等语句。请看下面这个例子: int emp_number; char temp[20]; VARCHAR emp_name[20]; /* get values for input host variables */ printf("Employee number? "); gets(temp); emp_number = atoi(temp); printf("Employee name? "); gets(emp_name.arr); emp_name.len = strlen(emp_name.arr); EXEC SQL INSERT INTO EMP (EMPNO, ENAME) VALUES (:emp_number, :emp_name); 在上面这个例子中,其中的emp_number和emp_name就是宿主变量。值得注意的是,它同其他数据库的区别是,定义宿主变量可以不需要BEGIN DECLARE SECTION和END DECLARE SECTION。 2)、指示符变量 大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量来解决这个问题。在嵌入式SQL语句中,主变量和指示符变量共同规定一个单独的SQL类型值。指示符变量是一个2字节的整数。 针对输入宿主变量和输出宿主变量,指示变量共有下面几种情况: 同输入宿主变量一起使用时: -1 Oracle将null赋值给列,即宿主变量应该假设为NULL。 >=0 Oracle将宿主变量的实际值赋值给列。 同输出宿主变量一起使用时: -1 表示该列的输出值为NULL。 0 Oracle已经将列的值赋给了宿主变量。列值未做截断。 >0 Oracle将列的值截断,并赋给了宿主变量。指示变量中存放了这个列的实际长度。 -2 Oracle将列的值截断,并赋给了宿主变量。但是这个列的实际长度不能确定。 从数据库中查询数据时,可以使用指示符变量来测试NULL: EXEC SQL SELECT ename, sal INTO :emp_name, :salary FROM emp WHERE :commission INDICATOR :ind_comm IS NULL ... 注意,不能使用关系操作符来比较NULL,这是因为NULL和任何操作都为false。如: EXEC SQL SELECT ename, sal INTO :emp_name, :salary FROM emp WHERE comm = :commission 如果comm列的某些行存在NULL,则该SELECT语句不能返回正确的结果。应该使用下面这个语句完成: EXEC SQL SELECT ename, sal INTO :emp_name, :salary FROM emp WHERE (comm = :commission) OR ((comm IS NULL) AND (:commission INDICATOR :ind_comm IS NULL)); 4.1.2 查询 如果是单行查询,则应该使用SELECT INTO语句。如果是多行查询,应该使用游标或宿主变量数组。如:单行查询的一个例子: EXEC SQL SELECT ename, job, sal + 2000 INTO :emp_name, :job_title, :salary FROM emp WHERE empno = :emp_number; 在嵌入SQL语句中,也可以使用子查询。如: EXEC SQL INSERT INTO emp2 (empno, ename, sal, deptno) SELECT empno, ename, sal, deptno FROM emp WHERE job = :job_title; 4.1.3 修改数据 1)、插入数据 使用INSERT语句插入数据。其语法同ANSI SQL语法类似。如: EXEC SQL INSERT INTO emp (empno, ename, sal, deptno) VALUES (:emp_number, :emp_name, :salary, :dept_number); 2)、更新数据 使用UPDATE语句更新数据。其语法同ANSI SQL语法类似。如: EXEC SQL UPDATE emp SET sal = :salary, comm = :commission WHERE empno = :emp_number; 3)、删除数据 使用DELETE语句删除数据。其语法同ANSI SQL语法类似。如: EXEC SQL DELETE FROM emp WHERE deptno = :dept_number; 4.1.4 游标 用嵌入式SQL语句查询数据分成两类情况。一类是单行结果,一类是多行结果。对于单行结果,可以使用SELECT INTO语句;对于多行结果,你必须使用游标来完成。游标是一个与SELECT语句相关联的符号名,它使用户可逐行访问由ORACLE返回的结果集。使用游标,应该包含以下四个步骤。 1)、定义游标 使用DECLARE语句完成。如: EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ename FROM emp WHERE deptno = :dept_number; 值得注意的是,不能在同一个文件中定义两个相同名字的游标。游标的作用范围是全局的。 2)、打开游标 使用OPEN语句完成。如: EXEC SQL OPEN emp_cursor; 3)、取一行值 使用FETCH语句完成。如: EXEC SQL FETCH emp_cursor INTO :emp_name; 4)、关闭游标 使用CLOSE语句完成。它完成的功能是:释放资源,如占用内存,锁等。如:EXEC SQL CLOSE emp_cursor; 5)、使用游标修改数据 我们可以使用CURRENT OF子句来完成修改数据。如: EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ename, sal FROM emp WHERE job = 'CLERK' FOR UPDATE OF sal; ... EXEC SQL OPEN emp_cursor; EXEC SQL WHENEVER NOT FOUND GOTO ... for (;;) { EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; ... EXEC SQL UPDATE emp SET sal = :new_salary WHERE CURRENT OF emp_cursor; } 值得注意的是,在使用CURRENT OF子句来完成修改数据时,在OPEN时会对数据加上排它锁。这个锁直到有COMMIT或ROLLBACK语句时才释放。 以下是使用游标修改数据的一个完整例子: ... /* 定义游标 */ EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ename, job FROM emp WHERE empno = :emp_number FOR UPDATE OF job; /* 打开游标 */ EXEC SQL OPEN emp_cursor; /* break if the last row was already fetched */ EXEC SQL WHENEVER NOT FOUND DO break; /* 循环取值*/ for (;;) { EXEC SQL FETCH emp_cursor INTO :emp_name, :job_title; /* 更新当前游标所在的行的数据*/ EXEC SQL UPDATE emp SET job = :new_job_title WHERE CURRENT OF emp_cursor; } ... /* 关闭游标 */ EXEC SQL CLOSE emp_cursor; EXEC SQL COMMIT WORK RELEASE; ...
下面这个例子完整演示了静态游标的使用方法。这个例子的作用是,获得部门编号,通过游标来显示这个部门中的所有雇员信息。
#include <stdio.h> /* 声明宿主变量 */ char userid[12] = "SCOTT/TIGER"; char emp_name[10]; int emp_number; int dept_number; char temp[32]; void sql_error(); /*包含SQLCA */ #include <sqlca.h> main() { emp_number = 7499; /* 处理错误*/ EXEC SQL WHENEVER SQLERROR do sql_error("Oracle error"); /* 连接到Oracle数据库*/ EXEC SQL CONNECT :userid; printf("Connected.\n"); /* 声明游标 */ EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ename FROM emp WHERE deptno = :dept_number; printf("Department number? "); gets(temp); dept_number = atoi(temp); /* 打开游标*/ EXEC SQL OPEN emp_cursor; printf("Employee Name\n"); printf("-------------\n"); /* 循环处理每一行数据,如果无数据,则退出*/ EXE |
|
[综合]ESQL/C资料(完全版)二 文章收藏, 网上资源
薛 峰 发表于 2005/7/18 10:33:03 |
第三节 IBM DB2嵌入SQL语言 DB2支持SQL嵌入到C/C++、JAVA、COBOL、FORTRAN和REXX等语言。本节以SQL嵌入C/C++为例子,讲解静态的嵌入SQL编程和动态的嵌入SQL编程。 静态SQL嵌入C语言编程是指,应用程序在书写时,每个SQL语句的大部分都已确定下来(如:查询的表、列和语句的格式等),唯一不确定的是查询语句中某些特定变量的值,这些值可以在执行时由变量传进去,但是,值的类型要事先确定。 3.1 一个简单示例 首先,我们来看一个嵌入静态SQL语句的C程序。 例1、连接到SAMPLE数据库,查询LASTNAME为JOHNSON的FIRSTNAME信息。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include "util.h" #include <sqlca.h> EXEC SQL INCLUDE SQLCA; (1) #define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1; int check_error (char eString[], struct sqlca *caPointer) { char eBuffer[1024]; char sBuffer[1024]; short rc, Erc; if (caPointer->sqlcode != 0) { printf ("--- error report ---\n"); printf ("ERROR occured : %s.\nSQLCODE : %ld\n", eString, caPointer->sqlcode); } return 0; } int main(int argc, char *argv[]) { EXEC SQL BEGIN DECLARE SECTION; (2) char firstname[13]; char userid[9]; char passwd[19]; EXEC SQL END DECLARE SECTION; printf( "Sample C program: STATIC\n" ); if (argc == 1) { EXEC SQL CONNECT TO sample; CHECKERR ("CONNECT TO SAMPLE"); } else if (argc == 3) { strcpy (userid, argv[1]); strcpy (passwd, argv[2]); EXEC SQL CONNECT TO sample USER :userid USING :passwd; (3) CHECKERR ("CONNECT TO SAMPLE"); } else { printf ("\nUSAGE: static [userid passwd]\n\n"); return 1; } /* endif */
EXEC SQL SELECT FIRSTNME INTO :firstname FROM employee WHERE LASTNAME = 'JOHNSON';(4) CHECKERR ("SELECT statement"); (5) printf( "First name = %s\n", firstname ); EXEC SQL CONNECT RESET; (6) CHECKERR ("CONNECT RESET"); return 0; } /* end of program : STATIC.SQC */
上面是一个简单的静态嵌入SQL语句的应用程序。它包括了静态嵌入SQL的主要部分。 (1)中的include SQLCA语句定义并描述了SQLCA的结构。SQLCA用于应用程序和数据库之间的通讯,其中的SQLCODE返回SQL语句执行后的结果状态。 (2)在BEGIN DECLARE SECTION和END DECLARE SECTION之间定义了主变量。主变量可被SQL语句引用,也可以被C语言语句引用。它用于将程序中的数据通过SQL语句传给数据库管理器,或从数据库管理器接收查询的结果。在SQL语句中,主变量前均有“:”标志以示区别。 (3)在每次访问数据库之前必须做CONNECT操作,以连接到某一个数据库上。这时,应该保证数据库实例已经启动。 (4)是一条选择语句。它将表employee中的LASTNAME为“JOHNSON”的行数据的FIRSTNAME查出,并将它放在firstname变量中。该语句返回一个结果。可以通过游标返回多个结果。 (5)在该程序中通过调用宏CHECKERR(即调用函数check_error)来返回SQL语句执行的结果。Check_error函数在下面讲解。 (6)最后断开数据库的连接。 从上例看出,每条嵌入式SQL语句都用EXEC SQL开始,表明它是一条SQL语句。这也是告诉预编译器在EXEC SQL和“;”之间是嵌入SQL语句。如果一条嵌入式SQL语句占用多行,在C程序中可以用续行符“\”。 3.2 嵌入SQL语句 3.2.1宿主变量 1)、声明方法 宿主变量就是在嵌入式SQL语句中引用主语言说明的程序变量(如上例中的firstname变量)。如: …………. EXEC SQL SELECT FIRSTNME INTO :firstname (4) FROM employee WHERE LASTNAME = 'JOHNSON'; …………. 在嵌入式SQL语句中使用宿主变量前,必须采用BEGIN DECLARE SECTION 和END DECLARE SECTION之间给宿主变量说明。这两条语句不是可执行语句,而是预编译程序的说明。宿主变量是标准的C程序变量。嵌入SQL语句使用宿主变量把数据库中查询到的值返回给应用程序(称为输出宿主变量),也用于将程序中给定的值传到SQL语句中(称为输入宿主变量)。显然,C程序和嵌入SQL语句都可以访问宿主变量。 在使用宿主变量前,请注意以下几点: l宿主变量的长度不能超过30字节。开始的字母不能是EXEC和SQL。 l宿主变量必须在被引用之前定义。 l一个源程序文件中可以有多个SQL说明段。 l宿主变量名在整个程序中必须是唯一的。 2)、宿主变量的数据类型 宿主变量是一个用程序设计语言的数据类型说明并用程序设计语言处理的程序变量;另外,在嵌入SQL语句中用宿主变量保存数据库数据。所以,在嵌入SQL语句中,必须映射C数据类型为合适的DB2数据类型。必须慎重选择宿主变量的数据类型。请看下面这个例子: EXEC SQL BEGIN DECLARE SECTION; short hostvar1 = 39; char *hostvar2 = "telescope"; EXEC SQL END DECLARE SECTION;
EXEC SQL UPDATE inventory SET department = :hostvar1 WHERE part_num = "4572-3";
EXEC SQL UPDATE inventory SET prod_descrip = :hostvar2 WHERE part_num = "4572-3"; 在第一个update语句中,department列为smallint数据类型,所以应该把hostvar1定义为short数据类型。这样的话,从C到DB2的hostvar1可以直接映射。在第二个update语句中,prod_descip列为varchar数据类型,所以应该把hostvar2定义为字符数组。这样的话,从C到DB2的hostvar2可以从字符数组映射为varchar数据类型。 下表列出了C的数据类型和DB2的数据类型的一些转换关系: DB2数据类型C数据类型 Smallintshort IntegerLong Decimal(p,s)无 DoubleDouble DateChar[11] TimeChar[9] TimestampChar[27] Char(X)Char[X+1] Varchar(X)Char[X+1] Graphic(X)Wchar_t[X+1] Vargraphic(X)Wchar_t[X+1] 因为C没有date或time数据类型,所以DB2的date或time列将被转换为字符。缺省情况下,使用以下转换格式:mm dd yyyy hh:mm:ss[am | pm]。你也可以使用字符数据格式将C的字符数据存放到DB2的date列上。对于DECIMAL数据类型,在C语言中也没有对应的数据类型。但可以使用char数据类型实现。 3)、宿主变量和NULL 大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量来解决这个问题。在嵌入式SQL语句中,宿主变量和指示符变量共同规定一个单独的SQL类型值。指示变量和前面宿主变量之间用一个空格相分隔。如: EXEC SQL SELECT price INTO :price :price_nullflag FROM titles WHERE au_id = "mc3026" 其中,price是宿主变量,price_nullflag是指示符变量。指示符变量的值为: l-1。表示宿主变量应该假设为NULL。(注意:宿主变量的实际值是一个无关值,不予考虑)。 l=0。表示宿主变量不是NULL。 l>0。表示宿主变量不是NULL。而且宿主变量对返回值作了截断,指示变量存放了截断数据的长度。 所以,上面这个例子的含义是:如果不存在mc3026写的书,那么price_nullflag为-1,表示price为NULL;如果存在,则price为实际的价格。 指示变量也是一种宿主变量,也需要在程序中定义,它对应数据库系统中的数据类型为SMALLINT。为了便于识别宿主变量,当嵌入式SQL语句中出现宿主变量时,必须在变量名称前标上冒号(:)。冒号的作用是,告诉预编译器,这是个宿主变量而不是表名或列名。 3.2.2单行查询 单行查询是通过SELECT INTO语句完成。当这条语句执行时,查询的结果送入INTO所标志的变量中。如果SQLCODE是100,或者SQLSTATE是02000,则说明没有查询到结果或返回结果为NULL,这时,宿主变量不改变,否则,宿主变量中将包含查询的结果。如: …………. EXEC SQL SELECT FIRSTNME INTO :firstname FROM employee WHERE LASTNAME = 'JOHNSON'; ………….
3.2.3多行查询 对于多行结果,必须使用游标来完成。游标是一个与SELECT语句相关联的符号名,它使用户可逐行访问由DB2返回的结果集。下面这个例子演示了游标的使用 |
|
|