tbwshc

tbw

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  95 Posts :: 8 Stories :: 3 Comments :: 0 Trackbacks

常用链接

留言簿(4)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

#

摘要:本文主要讲述了使用DBGird等ActiveX控件来显示Access数据库记录数据的一般方法。
 
  关键字:DBGird控件、ActiveX、Access数据库

  一、 引言

  随着数据库技术的进一步发展,我们在生活、办公时越来越多地同各式各样的数据库前台程序打着交道,这就要求数据库前台程序必须拥有良好的人机界面,使用户能有一种好的心情方便的同程序进行交互。Microsoft 的Office系列产品之所以能得到广泛的认同,也是与其良好的人机界面分不开的。数据库最基本的单位--表包含有若干条数据记录,而每一条记录又包含有许多的字段,如何能方便、美观的将这些数据记录显示给用户,并能方便实用的同用户进行交互操作便成为一个程序能否为人接受的重要因素了。Microsoft的Access 97/2000在这方面就做的相当不错,用一个网格式表单容纳了表中所有的数据,显得清晰简洁。而我们在用Visual C++开发的数据库前台程序中如要实现类似的表格就不得不借助于提供的ActiveX控件--DBGrid Control来实现,因为自己重新开发类似的功能无疑是比较困难而又烦琐的。本文着重对该控件的使用做了介绍。

  二、 程序的设计实现

  本程序采用ODBC接口同Access 2000数据源相连,并将数据库中的记录数据通过网格的形式显示给用户,并能完成同Access表单类似的诸如添加记录、删除记录等功能。

  在开始编制程序之前首先要通过控制面板的32位ODBC数据源设置我们待操作的后台Access数据源,建立名称为"雇员"的系统DSN,并将其指向Employee.mdb。为简单计,数据库中有一个"雇员表",内含5个字段:"雇员ID","tb雇员姓名"、"所在部门","职务","备注"等,并预先填充几条记录备用。

  在用VC创建工程时,需要在第二步确认提供了对ActiveX控件的支持。需要有后台数据库的支持,并通过"DataSource"按扭选择刚才注册过的ODBC数据源。此时编译运行程序,通过工具条上的数据库导航条可以移动数据库的记录指针,说明此时已经同数据库建立了连接,但由于没有控件(编辑框或其他)同数据库的字段相棒定,此时还无法显示数据库中的记录。我们先插入网格控件DBGrid Control,方法如下:

  1)选择菜单->Project->Add to Project->Components and Controls Gallery

  2)在部件选择对话框中进入Registered ActiveX Controls

  3)选择DBGrid Control,单击Insert按钮,确认后对类进行配置(可以按默认),我们不做任何修改单击OK按钮,插入完成。

  在VC工作区的ResourceView中可以如同使用标准控件一样将刚添加来的DBGird网格控件拖入到对话框中,并对其属性进行设置。下面将主要的属性列表如下:

属性名称 说明
Caption 雇员表 设定DBGird控件的网格标题
AllowAddNew True 是否允许添加记录
AllowDelete True 是否允许删除记录
AllowDelete True 是否允许更新记录
ColumnHeaders True 是否显示每列的标题
DefColWidth 100 设定每列的宽度
RowHeight 11 设定每行高度
DataSource <Not bound to a DataSource> 设定绑定的数据源
BackColor 0x8000000E 设定网格的背景色

  再次运行程序,可以看到类似Access表格风格的DBGird控件以按我们的属性设定显示了出来,但并没有数据库记录的显示,而且我们注意到刚才设定数据源属性DataSource时,下拉选项只有<Not bound to a DataSource>一项,而并没有我们所希望的ODBC数据源"雇员"的存在。所以我们还要继续添加一些辅助的控件来完成同数据库源的绑定。用同插入DBGird控件一样的步骤,插入Microsoft RemoteData Control控件,同样也要对其属性进行设置:

属性名称 说明
ID IDC_REMOTEDATACTL1 控件ID
Caption 人事管理系统--雇员表 设定导航条的标题
UserName   由于没有指定用户及密码,设为空
Password   同上
SQL SELECT * FROM "雇员表" 待执行的SQL结构化查询语言

  在RemoteData控件里用SQL语言将ODBC数据源的"雇员表"打开并选取里面的所有字段,也即显示表里的所有记录信息。这时再打开DBGird控件的DataSource属性就会发现下拉条里多了一个"IDC_REMOTEDATACTL1",正是RemoteData的ID号。此次编译运行程序就在网格控件内显示了数据源指定表的所有记录信息,而且可以方便的添加、删除记录以及调整字段尺寸等。具体如图所示:


  运行结果表明,在RemoteData控件的中介作用下实现了DBGird控件同ODBC数据源之间的交互。该程序设计实现过程是可靠、实用的。

  小结

  DBGrid数据网格控件以其短小精悍而深受大家的喜爱,,本文将在VC下使用DBGrid的具体步骤和方法作了简要地介绍。其它类似的表格控件也可以大致参考这个过程,希望本文能有所启迪与帮助。在Windows 2000 Professional下,由Microsoft Visual C++ 6.0编译测试通过。后台数据源为Microsoft Access 2000。
posted @ 2012-08-05 14:29 tbwshc| 编辑 收藏

前言

在许多视窗应用软件中,通常要在屏幕上同时显示若干个子视窗,以显示同一个文档的不同部分,或者是在每个视窗中分别显示不同文档的内容。为了实现多视窗界面,可以采用MDI(Multiple Document Interface)的多文档模式进行处理,但是多文档的应用程序设计与维护相对于单文档的应用程序而言比较复杂。而且,如果要在屏幕上同时显示多个子视窗,通常要利用视窗重叠函数进行管理,每个子视窗的位置往往需要用鼠标人为设定,过多的人为干预降低了程序使用的效率。因此,如果能对单文档视窗做适当的分裂,无疑程序使用者将可以得到更易于操作的接口,数据的显示也更加直观和方便。本文通过对单文档视窗的静态分裂原理进行分析,实现上述要求。

二分裂视窗的类型

视窗的分裂可分为两种类型,一是动态分裂,二是静态分裂。动态分裂可以让使用者通过拖曳分裂方块的使用,将视窗分裂。但是,动态分裂最多只可以将视窗分裂为2×2个子视窗,不能进行混合分裂视窗,所有子视窗的属性和父视窗都是一样的,而且子视窗的数据通常来源于同一处。而静态分裂,使用者除了可以调整子视窗的大小和进行混合分裂视窗外,最多可将视窗分裂为16×16个子视窗,每个子视窗可以有各自不同的视图类(CView),各个子视窗显示的数据可以来自于不同的数据源。不论是要创建动态分裂视窗还是静态分裂视窗,都必须要利用MFC的CSplitterWnd类别来完成视窗的分裂。

混合静态分裂视窗的实现

混合分裂视窗是指在子视窗中进行视窗的再分裂。在MFC的框架下,混合分裂视窗必须完成三件工作:

⑴在视窗框架类别中定义CSplitterWnd控件为其属性(数据成员)。

⑵重载视窗框架类别中的OnCreateClient函数(CFrameWnd::OnCreateClient),建立静态分裂子视窗,为静态分裂子视窗填充视图。

⑶建立维持各子视窗同步更新的机制。

首先,利用MFC AppWizard生成一个单文档应用程序,在应用程序的CMainFrame类别中声明CSplitterWnd类别的数据成员。

其次,重载CMainFrame类别中的OnCreateClient(LPCREATESTRUCT,CCreateContext* pContext)函数。在该函数中利用CsplitterWnd类别的构造函数Create Static(CWnd *pParentWnd,int nRows,int nCols,DWORD dwstyle,UINT nID) 创建混合静态分裂子视窗,即在Create Static分裂出的子视窗中利用CsplitterWnd类别的控件再一次分裂视窗。

Create Static函数的参数含义为:

·pParentWnd是准备建立静态分裂视窗的视窗框架控件的指针;

·nRows和nCols是准备建立静态分裂视窗行数(nRows)与列数(nCols)

因此,创建的静态分裂子视窗个数为nRows × nCols个,这两个参数最小不得小于0,最大不可超过16;dwstyle是设定子视窗的形式;nID静态分裂的代号(ID),此代号预设为AFX_IDW_PANE_FIRST,若静态分裂视窗位于另一个分裂视窗内时,不可以使用默认值,可以利用CsplitterWnd类别的成员函数IdFromRowCol(int row,int col)获得。利用CsplitterWnd类别的成员函数Create View (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext) 为静态分裂子视窗填充视图,在将视图与子视窗关联时必须先完成子视窗的创建。

Create View函数的参数含义为:

·row和col是指定准备建立View控件的子视窗,其指定的方式是以表示该子视窗所在的行列位置;

·pViewClass是指定用于建立子视窗View控件的View类别,该类别需要被声明为Run-Time类别;

·Sizeini是View控件的起始大小;pContext是一个指向记录应用程序所使用的视窗框架控件、Document控件,以及View控件之变量的指针,此参数在CMainFrame::OnCreateClient函数被调用时传入,再由该tb函数传递给此函数。

·CsplitterWnd类别的成员函数SetColumnInfo(int col,int cxIdeal,int cxMin)和SetRowInfo(int row,int cyIdeal,cyMin)为设置子视窗的宽度和高度,参数cxIdeal和cxMin是指定子视窗的宽度和最小宽度,cyIdeal和cyMin是指定子视窗的高度和最小高度,在使用这两个函数调整子视窗的大小后还应该使用该类别的成员函数RecalLayout()重新调整视窗框架的布局。如果要设定视窗框架里的活动子视窗,可以通过CsplitterWnd类别的成员函数SetActivePane(int row,int col,CWnd* pWnd=NULL)来完成,该函数指定子视窗的方式有两种,一是指出子视窗所在的行列,二是传入指向该子视窗的控件指针。

最后,将视窗分裂成多个子视窗后,整个视窗程序中将存在多个View控件。当在其中一个View控件执行更新操作时,如何让其它View控件同步更新数据?可以通过文档类别(CDocument)的UpdateAllViews(CView* pSender,LPARAM lHint,CObject* pHint)成员函数的调用,再由该函数分别调用目前存在于视窗程序中各View控件的On Update函数来完成数据的同步更新。

UpdateAllViews函数的参数含义为:

·pSender是指向引发更新操作的View控件指针,如果传入NULL表示所有视图都要执行更新操作;

·lHint是用于传送更新视图时,需要传送的额外信息参数;

·pHint是指向记录更新视图所需额外信息的控件。在调用该函数时,将View控件的指针传入的目的是要告诉该函数该子视图已经完成数据更新,该函数不需要再调用该子视图的On Update进行数据更新。


子视图的动态切换

在多视图应用程序中,可以通过改变CCreateContext对象的值,来创建更加灵活的视图,实现多视图的动态切换。CCreateContext是MFC框架所使用的一种数据结构,它将构成文档/视图结构的组件联系起来。这个结构包括指向文档的指针、视窗框架的指针、视图的指针以及文档模板的指针,它还包含一个指向CRuntimeClass结构的指针,以指明所创建的视图的类型。

其数据成员如下:

·m_pNewViewClass是指向创建上下文的视图的CRuntimeClass结构的指针;

·m_pNewDocTemplate是指向与视窗框架的创建相联系的文档模板的指针;

·m_pCurrentDoc是指向文档对象的指针,以和新视图tb联系起来;

·m_pLastView是指向已存在的视图的指针,它是新产生的视图的模型;

·m_pCurrentFrame是指向已存在的视窗框架的指针,它是新产生的视窗框架的模型。

此外,任何一个从CObject类别继承而来的子类别,在使用宏DECLARE_DYNAMIC、DECLARE_DYNCREATE、DECLARE_SERIAL三个中的任意一个时都会产生一个CRuntimeClass结构的静态对象,RUNTIME_CLASS返回的就是这个对象的指针,这个对象包含了其基类和本身在运行时刻的信息。

在单文档静态分裂视窗的应用程序中,利用CsplitterWnd类别的成员函数Delete View(int row,int col)可以删除子视窗的原有视图,然后再通过该类别的成员函数Create View为子视窗创建新的视图。但是,创建新视图前必须初始化创建上下文相关指针,即对CCreateContext结构赋值。值得注意的是,使用Create View函数创建的新视图不能自动调用视图类别的成员函数OnInitialUpdate和自动显示并且激活新视图,需要人工调用OnInitialUpdate函数和ShowWindow(SW_SHOW) 函数,这些函数的调用都可以通过CsplitterWnd类别的成员函数Get Pane(int row,int col)获得新视图的指针来完成。

结束语

在MFC的框架下,混合分裂视窗有多种编程方法,本文只是从CsplitterWnd类别的角度去分析混合静态分裂视窗的实现方法,希望能给读者起到抛砖引玉的作用。

posted @ 2012-08-05 14:26 tbwshc| 编辑 收藏

应用程序:一个异步的HTTP服务器的设计

  假设我们要设计一个HTTP服务器,它的设计目标包括:高并发性、精简(部分支持HTTP/1.1)、支持plug-in结构。在不少场合可能都有这个需求。总体上来说,HTTP服务器可以类比成一个基于多线程的操作系统:OS调度每个工作线程在适当的时候获得执行,而工作线程提供服务(也就是处理HTTP请求)。在这个基础上,主要的考虑就是调度粒度的大小,粒度太大的时候并发性会降低,而粒度太小又可能因为任务切换(考虑OS的Context Switching)而导致效率降低,所以这又是一个折衷的结果。类似于Apache(以及其他的HTTP服务器),我们可以把一个HTTP处理过程分为若干个状态,基于这些状态可以构造出一个HTTP处理的状态机。这种情况下,我们就可以把每个状态的处理作为调度的粒度。一个调度过程就是:一个工作线程从全局的任务队列里取出一个HTTP_Context结构;根据当前的状态完成相应处理;然后根据状态机设置下一个状态;再放回到全局的任务队列里。这样子,若干个HTTP状态就可以通过这个调度策略构成一个完整HTTP处理过程。显而易见,一个状态对于下一个状态处理的调用都可以认为是异步的。一个HTTP状态机的设计如下图所示。

  工作线程的函数其实就是两个操作:从状态队列里取出一个HTTP_Context,调用HTTP_Context的service()函数,周而复此。在这个架构上,就很容易引入异步I/O和Plug-in的机制了。事实上我们也可以使用基于事件(例如select/poll)的I/O策略来模拟异步I/O,实现中使用一个tb用户线程就可以了。

  对于异步I/O和Plug-in的调用,我们也是采用类似于Linux 2.6里面aio的重试方案,而异步完成的时候采用回调函数。在某个状态上,如果系统需要I/O操作(recv或者send),则会请求一个异步I/O(操作系统提供的异步I/O或者由用户线程模拟的异步I/O),这时候相应的HTTP_Context不会重新回到状态队列里,而在I/O完成的回调函数里面才会重新放回到状态队列,得到重新调度的机会。HTTP_Context得到重新调度的时候会检查I/O状态(这个可以通过一些标志位来完成),如果已经完成,则处理然后设置下一状态,重新调度,否则可以重新请求一个新的I/O请求。Plug-in也可以使用类似的方案,比如说一个Plug-in要跟外部的一个服务器通信,这时候就可以在通信完成的时候才把HTTP_Context重新放回到状态队列。显然,Plug-in跟HTTP状态是多对多的关系,一个Plug-in可以在若干个关心的状态注册自身,同时还可以设置一些short-path来提高处理的效率。

  结论

  总的来说,异步调用的设计和应用归根结底就是对多个主动对象的管理问题:如何提供执行的动力以及如何保证执行的顺序逻辑。主要考虑的问题是主动对象的粒度以及执行方式,同步或者回调来完成顺序的调度,或者使用近似的调度而加一些鲁棒的错误处理机制来保证语义的正确。后者可以考虑在使用基于事件的socket的时候,readable事件的通知可以是冗余的,或者说可以比实际中发生的readable事件更多,这个时候使用非阻塞的socket,有些read()(或者recv())会直接返回EWOULDBLOCK,系统只要考虑处理这种情况(使用non blocking socket而不是blocking socket),当例外的情况不多的时候是可以接受的。这时候可以说事件的报告就只是近似的。
posted @ 2012-08-05 12:47 tbwshc| 编辑 收藏

创建外键约束时如果使用Oracle默认的创建方式,在删除被参照的数据时,将无法被删除,这一点在Oracle9i中给了我们更多灵活的选择,我们可是使用on delete cascade和 on delete set null关键字来决定删除被参照数据时是否要将参照这个数据的那些数据一并删除,还是将那些参照这条数据的数据的对应值赋空。

例如下面这两个表中分别存的时员工的基本信息和公司的部门信息。我们为

create table dept
(deptno number(10) not null,
deptname varchar2(30) not null,
constraint pk_dept primary key(deptno));

create table emp
( empno number(10) not null,
fname varchar2(20) ,
lname varchar2(20) ,
dept number(10) ,
constraint pk_emp primary key(empno));

然后我们现在分别使用这两个关键字来增加外键试一下,首先我们来试一下on deletbe cascade

alter table emp
add constraint fk_emp_dept foreign key(dept) references dept(deptno) on delete cascade;

先增加外键。然后插入数据。

insert into dept values(1,’销售部’);
insert into dept values(2,’财务部’);
insert into emp values (2,’Mary’,'Song’,1);
insert into emp values (3,’Linda’,'Liu’,2);
insert into emp values (4,’Linlin’,'Zhang’,1);

然后现在我要删除销售部,会有什么后果呢?

delete from dept where deptno = 1;

我们发现除了dept中的一条数据被删除了,emp中两条数据也被删除了,其中emp中的两条数据是参照了销售部的这条数据的,这就很容易理解on delete cascade了。

 

创建外键约束时如果使用Oracle默认的创建方式,在删除被参照的数据时,将无法被删除,这一点在Oracle9i中给了我们更多灵活的选择,我们可是使用on delete cascade和 on delete set null关键字来决定删除被参照数据时是否要将参照这个数据的那些数据一并删除,还是将那些参照这条数据的数据的对应值赋空。

按照上文中介绍的就能够实现在oracle数据库中用非默认方式创建外键的目的,希望对大家能够有所帮助。

posted @ 2012-08-04 13:26 tbwshc| 编辑 收藏

现在某家企业的Oracle数据库中有一张产品信息表。这张表中的记录已经超过了500万条。其中成品信息大概30万条。零件记录有300万条左右。剩余的都是包装信息。数据库工程师通过相关的分析与监测,用户访问这张表的时候,会有严重的等待现象。这主要是因为这张表中的数据存放在同一块硬盘上。当不同的用户并发访问这张表时,会因为磁盘I/O性能的瓶颈,而导致等待。如下图所示。当各位读者遇到这种情况,该如何采取措施来优化性能呢?笔者这里的建议是采用Oracle分区表减少磁盘的I/O冲突,改善数据库的性能。

一、分区表的原理与优势。

分区表对于提高大表的访问性能会有很大的帮助。如上图所示,可以将一张产品信息表分按产品类别分为三个部分,分别为成品信息、零件信息和原材料信息。然后将这三部分对应一个单独的分区,并将它们存放在不同的硬盘上。此时当不同的用户访问不同的信息时,就可以有效的降低磁盘的I/O冲突。即使是同一个用户,需要同时访问这三部分信息,如产品的物料清单时,由于其分别从不同的硬盘中读取数据,为此也可以明显的降低磁盘I/O冲突。

所以分区的基本原理就是通过访问一个表或者索引的较小片断,而不是访问整个表和索引,以提高数据库的性能。当然这有一个前提条件,需要将一个表的不同分区放置在不同的磁盘上,此时磁盘整体的吞吐量就会成倍上升。

采取分区,不仅可以提高用户访问时的性能,而且还可以提高备份时的灵活性。如上面这个例子,将产品信息根据其类别分为不同的区,并将它们保存在不同的硬盘上。此时就可以对各自的分区进行单独的备份。如最近因为国家环保的要求,tb原材料信息进行了大规模的调整。此时就可以对原材料信息所在的分区数据进行单独的备份。这不仅可以减少备份的时间,而且可以降低备份作业过程中出现的I/O冲突问题。

一般来说,分区表的优势有一个前提,就是需要将分区数据放置在不同的磁盘上。如果不这么做的话,那么分区往往很难起到降低磁盘I/O的效果。所以为了最大程度的降低一个大表的磁盘I/O(特别是经常会有并发行的访问),此时应该将表分割到多个分区上。然后再将这些分区存放在不同的磁盘上。

二、分区表模式的选择。

那么该如何对表进行分区呢?这又是一个比较关键的问题。根据经验,笔者认为要让分区取得更好的效果,分区表模式的选择至关重要。也就是说,按什么内容对表进行分区管理。有时候,先同的数据,采取不同的分区表模式,往往会有不同的效果。在下面的内容中,笔者会结合企业实际应用的情景,对分区表模式的选择进行举例。希望这些内容能够帮助各位读者,更好的维护分区表。

第一种模式:按行来进行分区。

上面这个例子中,笔者谈到有一张产品信息表,其包括成品信息、零件信息和原材料信息。当这张表的记录比较多,并且当用户访问这张表时已经出现了严重的I/O冲突的时候,则就可以根据行记录来进行分区。如在产品信息表中有一个产品类别的字段。数据库管理员就可以根据这个字段对标进行分区。具体的分区方法也比较简单。在建立表的时候,在产品类别字段后加上Partion关键字,然后指定按字段的内容进行分区。这个操作比较简单,笔者就不过多展开了。笔者这里需要强调的是,分区完之后一定要将数据存放在不同的磁盘上,即不同的表空间。否则的话,不能够起到改善磁盘I/O的效果。

第二种模式:按列来进行分区。

在实际工作中,还有这么一种情况。如现在有一张员工信息表。这这张表中除了包含员工的基本信息,如身份证号码、姓名、籍贯等内容,还包括员工的身份证复印件或者照片等图片信息。大家都知道,图片信息的数据流量是很大的。有可能一张身份证复印件的数据流量相当于几千条的员工基本信息。而且,当用户访问员工信息表的时候,并不是每个时候都需要查看身份证复印件。大部分时候他们可能只是查询员工的联系方式或者住址等等。另外,一般身份证复印件等照片不会随意更改,而员工的联系方式或这住址等等,则更改比较频繁。此时如果需要更改员工信息,却将不需要更改的员工身份证复印件也查询出来,显然那这会加重磁盘的I/O冲突。

当企业存在这种情况时,也可以对这个表进行分区。此时分区并不是对行进行分区,而是对列进行分区。如可以将身份证复印件信息或者照片信息分为一个独立的分区,并将其保存在另外一个硬盘上。这么做,能够带来如下的好处。

一是在数据访问时,可以指定是否需要查询身份证信息所在的分区。在查询员工信息的时候,在语句中可以指定从哪个分区中查询信息。当用户平时只是查询员工的联系方式或者住址时,就不需要访问身份证复印件所在的分区。如可以使用如下语句查询:

Select * from ad_user partition(uinfo) –假设员工的基本信息存放在分区Unifo中。

在查询语句中,使用Partition关键字可以指定其查询的是哪个分区。如果不特指的话,则系统会查询这个表所对应的全部分区。而指定的话,就只访问某个特定分区的内容。上面这条语句,就只读取Uinfo分区中的信息。而不会读取身份证复印件等相关信息。如此的话,就可以降低磁盘的I/O冲突,减少不必要的数据流量,提高查询的性能。

二是方便对数据的备份。根据使用习惯,一般身份证复印件或者员工照片等信息不怎么会更改。为此对这些数据的备份频率可以比较低一点。况且这些信息的容量往往会很大。如果经常对其进行备份,显然会增加磁盘的I/O负担。而对于员工的联系信息或者住址等等,其变化的频率就会高许多。对这些信息就需要进行经常性的备份。对大表进行分区管理,还有一个很大的优势就在于可以对各个分区中的数据采取独立的备份。为此就可以对身份证复印件所在的分区进行单独的备份,如一个月或者有大的变动时进行备份。而对于其他的信息则可以每天进行备份。这就可以实现在性能与安全方面的均衡。一般来说,在访问某个表时,如果经常需要访问的信息只是特定的几列,而不需要访问的信息容量比较大,此时就可以采用按列分区的模式。在这种情况下,用户就可以在查看某个分区内容的时候避免访问其他分区。同时还可以在不妨碍其它分区的情况下对某个分区的数据进行独立的备份。

第三种分区模式:散列分区。

有时候某个表可能没有明显的分区特征,即不符合上面提到的这些情况。但是表中的记录又非常的多。在这种情况下,也有必要进行分区。不过此时我们可以让系统进行随机的分区。这种分区模式就叫做散列分区。通常情况下,为了提高散列分区的效果,即得到一个比较均匀的分布,往往可以将2的N次方指定为散列分区数。一般来说,N越大,其分布的越均匀。

也就是说,当数据库管理员不知道该如何对表进行分区时,但确实有分区的必要时,可以使用散列分区。不过笔者需要提醒的是,散列分区其有一个重大的限制。在使用散列分区的时候,仅仅支持本地索引,而不支持其他的索引方式。这一点需要特别的注意。在实际工作中不能够因为采取了散列分区,而降低或者取消了索引。这往往是得不偿失的,不可行。

希望通过上文的学习,大家能够掌握好利用Oracle分区表来减少磁盘I/O冲突的知识,便于大家在以后的工作中灵活运用。

posted @ 2012-08-04 13:25 tbwshc| 编辑 收藏

下面就介绍一下Oracle手动创建数据库的步骤:

1、确定新建数据库名称和实例名称;

2、确定数据库管理员的认证方式;

3、创建初始化参数文件;

4、创建实例;

5、连接并启动实例;

6、使用create database语句Oracle创建数据库;

7、创建附加的表空间;

8、运行脚本创建数据字典视图;

下面以创建一个名为“MYNEWDB”的数据库为例

1、确定数据库名称与实例名称;

1.DB_NAME=MYNEWDB

2.SID=MYNEWDB

2、确定数据库管理员的认证方式;

管理员的认证方式包括操作系统认证和口令认证两种,本例采用操作系统认证

3、创建初始化参数文件;

Oracle提供的初始化参数样本文件位于$ORACLE_HOME\admin\tbsample\pfile目录中的initsmpl.ora

我们采用修改样本的方式,创建参数文件名为:initMYNEWDB.ora,存放在D:\oracle\ora92

1.\database\initMYNEWDB.ora,

主要内容设置如下:

共享服务器设置

1.dispatchers="(PROTOCOL=TCP)(SERVICE=MYNEWDBXDB)

数据库实例名设置

1.instance=MYNEWDB

安全与审计设置

1.remote_login_passwordfile=EXCLUSIVE

排序区大小设置

1.pga_aggregate_target=25165824

2.sort_area_size=524288

全局数据库名设置

1.db_domain=""

2.db_name=MYNEWDB

控制文件设置

1.control_files=("D:\oracle\oradata\MYNEWDB\CONTROL01.CTL",

2."D:\oracle\oradata\MYNEWDB\CONTROL02.CTL",

3."D:\oracle\oradata\MYNEWDB\CONTROL03.CTL")

SGA区设置

1.java_pool_size =33554432

2.large_pool_size=8388608

3.shared_pool_size=50331648

以上的相关内容就是对Oracle创建数据库的步骤的介绍,望你能有所收获。

按照上文中介绍的步骤,就能够实现Oracle手动创建数据库,希望上文中介绍的内容对大家能够有所帮助。

posted @ 2012-08-04 13:24 tbwshc 阅读(738) | 评论 (0)编辑 收藏

Oracle数据库以其高可靠性、安全性、可兼容性,得到越来越多的企业的青睐。如何使Oracle数据库保持优良性能,这是许多数据库管理员关心的问题,根据笔者经验建议不妨针对以下几个方面加以考虑。

一、分区

根据实际经验,在一个大数据库中,数据空间的绝大多数是被少量的表所占有。为了简化大型数据库的管理,改善应用的查询性能,一般可以使用分区这种手段。所谓分区就是动态表中的记录分离到若干不同的表空间上,使数据在物理上被分割开来,便于维护、备份、恢复、事务及查询性能。当使用的时候可建立一个连接所有分区的视图,使其在逻辑上仍以一个整体出现。

1.建立分区表
Create table Employee(
EmpNo varchar2(10) primary key,
Name varchar2(30),
DeptNo Number(2)

Partition by range(DeptNo)
(partition PART1 values less than (11)
tablespace PART1_TS,
partition PART2 values less than(21)
tablespace PART2_TS,
partition PART3 valuse less than(31)
tablespace PART3_TS
partition PART4 values less than(MAXVALUE)
tablespace PART4_TS
);

表Employee依据DeptNo列进行分区。

2.分区索引
Create index Employee_DeptNo on Employee (DeptNo)local(
partition PART1 tablespace PART1_NDX_TS,
partition PART2 tablespace PART2_NDX_TS,
partition PART3 tablespace PART3_NDX_TS,
partition PART4 tablespace PART4_NDX_TS,
);

当分区中出现许多事务并且要保证所有分区中的数据记录的惟一性时采用全局索引,在建立全局索引时,Global子句允许指定索引的范围值,这个范围值可以不同于表分区的范围值。只有建立局部索引才会使索引分区与表分区间建立起一一对应关系。因此,在大多数情况下,应该使用局部索引分区。若使用了此索引,分区就能够很容易地将索引分区与表分区建立关联,局部索引比全局索引更易于管理。

3.分区管理
根据实际需要,还可以使用Alter table命令来增加、删除、交换、移动、修改、重命名、划分、截短一个已存在分区的结构。

二、重建索引

如果表中记录频繁地被删除或插入,尽管表中的记录总量保持不变,索引空间的使用量会不断增加。虽然记录从索引中被删除,但是该记录索引项的使用空间不能被重新使用。因此,如果表变化不定,索引空间量会不断增加,不论表中记录数量是否增加,只是因为索引中无效空间会增加。
要回收那些曾被删除记录使用的空间,需要使用Alter index rebuild命令。可以做一个定期运行的批处理程序,来重建最活动表的索引。这个批处理程序可以在空闲时运行,以避免该程序与其他应用程序冲突。若能坚持索引的这一程序规划,便可以及时回收那些未使用空间,提高空间利用率。

三、段的碎片整理

当生成一个数据库对象时(一个表或一个索引),通过用户缺省值或指定值来为它指定表空间。一个在表空间中生成的段,用于存储对象的相关数据。在段被关闭、收缩、截断之前,段所分配的空间将不被释放。

一个段是由范围组成,而范围是由相邻的Oracle块组成。一旦存在的范围不能再存储新的数据,这个段就会去获得新的范围,但并不要求这些范围是彼此相邻的。这样的扩展会一直继续下去,直到表空间中的数据文件不能提供更多的自由空间,或者范围数量已达到极限。

因此,一个碎片太多的数据段,不仅会影响运行,也会引发表空间中的空间管理问题。所以,每个数据段只含有一个范围是十分有益的。借助监控系统,可以通过检查DBA_SEGMENTS数据字典视图来了解哪些数据库对象含有10个或更多范围的段,确定其数据段碎片。

若一个段的碎片过多,可用两种方法解决:
1. 用正确的存储参数建立一个新表,将旧表的数据插入到新表中,在删除旧表;
2. 利用Export/Import工具。

如:exp system/manager file=exp.dmpcompress=Y grants=Y indexes=Y
tables=(T1,T2)
若输出成功,进入Oracle,删除上述表。
注:compress=Y表示将在输出过程中修改它们的存储参数。
imp system/manager file=exp.dmp commit=Y buffer=64000 full=Y

四、自由范围的碎片整理

表空间中的一个自由范围是表空间中相连的自由(空间)块的集合。当一个段关闭时tb,它的范围将被释放,并被标记为自由范围。然而,这些自由范围再也不能与相邻的自由范围合并,它们之间的界线始终存在。但是当表空间的缺省值pctincrease设置不是0时,SMON后台进程会定期将这些相邻的自由范围合作。若pctincrease设置为0,那么相邻自由范围不会被数据库自动合并。但可以使用Alter table命令"coalesce"选项,来强迫进行相邻自由范围的合并。

不进行自由范围合并,在日后的空间请求中,会影响到表空间中的空间分配。当需要一个足够大的范围时,数据库并不会合并相邻的自由范围,除非没有其他选择。这样,当表空间中前面较小的自由范围已被使用时,将使用表空间中后面部分最大的一个自由范围。结果,会因为没有足够多的使用空间,从而导致表空间需求的矛盾。由于这样的情况出现,使数据库的空间分配距理想越来越远。自由空间碎片常会出现在那些经常关闭又重新生成的数据库表和索引中。

在理想的Oracle表空间中,每一个数据库对象存储在一个单独的范围中,并且所有有效自由空间集中在一个巨大而连续的范围中。这样,在一个对象需要附加存储空间时,可以在增加获取足够大自由空间的可能性的同时,最小化空间中的循环调用,提高自由空间使用率。


posted @ 2012-08-04 13:23 tbwshc| 编辑 收藏

1、DB2 访问前10行数据与Oracle区别

DB2 :    
select * from test fetch first 10 rows only
Oracle :   
select * from test where rownum<=10
 
查询语句
Db2:不提供隐形转换
select * from employee where empno=1010;
oracle:提供隐形转换
select * from employee where empno='1010';
 
2、DB2 Insert into 与Oracle区别
DB2 允许有类似这样多行插入:
insert into staff values(1212,'cemy',20,'sales',3,90000,30000);
(1212,'cemy',20,'sales',3,90000,30000); 
oracle:
SQL>  insert into staff values(1212,'cemy',20,'sales',3,90000,30000),(1212,'cemy'
,20,'sales',3,90000,30000)
                                                    
3、DB2 Update 与Oracle Update
Db2
DB2 update staff set (salary,comm)=(80000,50000);
DB2 update staff set salary=80000,comm=50000;
Oracle:
SQL> update staff set salary=80000,comm=50000;
已更新 1 行。I
4、取得系统日期
Oracle:
Select sysdate from dual;
DB2:
Select current timestamp from sysibm.sysdummy1;
 
5、转换日期时间到字符类型:
Oracle  
TO_CHAR(date_expression_r_r, 'YYYY-MM-DD')  
TO_CHAR(date_expression_r_r, 'HH24:MI:SS')  
DB2  
CHAR(date_expression_r_r,ISO)  
CHAR(time_expression_r_r,ISO) 
 
6、转换日期时间字符串到日期时间类型:
Oracle  
TO_CHAR(date_expression_r_r, 'YYYY-MM-DD')  
TO_CHAR(date_expression_r_r, 'HH24:MI:SS')  
DB2  
DATE('2005-05-20')  
TIME('18:59:59')  
TIEMSTAMP('2007-2-1', '21:12:12')  
TIEMSTAMP('2007-2-1 21:12:12')
 
DB2也有TO_CHAR 和 TO_DATE函数,但只能提供固定的转换格式,如下
TO_CHAR (timestamp_expression_r_r,'YYY-MM-DD HH24:MI:SS')  
TO_DATE (string_expression_r_r, 'YYY-MM-DD HH24:MI:SS') 
 
 
7、快速清空大表
Oracle:
truncate table TableName ;
DB2:
alter table TableName active not logged initially with empty table;
 
8、创建类似表
Oracle:
create table a as select * from b ;
DB2:
create table a like b ;
 
9、修改字段长度或类型:
ORACLE:
ALTER TABLE NODES MODIFY NODE_NAME varchar(32);
DB2:
alter table NODES ALTER NODE_NAME SET DATA TYPE varchar(32);
 
10、空值处理得到abc
Oracle:
SELECT 'abc' || c1 FROM t1 (c1 IS NULL)  
DB2 :
SELECT 'abc‘ || COALESCE(c1,'') FROM t1 
 
11、创建 indexes 
Oralce:
Create TABLE T1 .............IN DATA_TA
Create Index ........ ON T1  ...... IN INDX_TS
 
DB2:
Create TABLE T1 ........ IN DATA_TS INDEX IN INDX_TS
Create INDEX  .....ON T1
 
12、更改列名
oracle :
alter table test rename column mail to mail2;
db2  
不提供更改列名功能(解决办法同删除,或者通过建立一个新视图解决)
13、更改列类型
oracle :alter table test modify column (mail2 integer);
db2    :alter table test alter mail varchar(256) 只可以加宽,不能更改类型
 
14 创建PROCEDURE的参数的区别
1)参数类型和参数名称的位置不同
db2:
CREATE PROCEDURE PRO1 (IN OrgID int)
oracle:
CREATE PROCEDURE PRO1 (OrgID IN int)
2)同时作为输入输出参数的写法不同
db2:   
CREATE PROCEDURE PRO1 (INOUT OrgID int)    INOUT连着写
oracle:
CREATE PROCEDURE PRO1 (OrgID IN OUT int)    IN OUT中间空格隔开,而且必须IN在OUT之前
3)没有输入或输出参数时
db2:  
CREATE PROCEDURE PRO1 ()    
oracle:
CREATE PROCEDURE PRO1 不能有空的括号
 
变量定义和BEGIN END体的位置不同
        db2中变量定义在BEGIN END体内,并且每个变量都要用DECLARE声明;存储过程结束时,END后跟P1,并且不需要分号
        oracle中变量定义必须在BEGIN END体外,变量都不需要用DECLARE声明(有种说法是,第一个变量需要DECLARE,其他变量不需要);存储过程结束时,END后跟存储过程的名称,并且需要分号        
 db2:
CREATE PROCEDURE PRO1()
 LANGUAGE SQL    
       P1: BEGIN
          --变量定义
           DECLARE INSERT_DATE TIMESTAMP; 
           DECLARE ALLDEPT_NO  VARCHAR(20);
           --具体操作
           SELECT a FROM TAB_1;
                          .........
            END P1
        
oracle:  
CREATE PROCEDURE PRO1
          IS
         --变量定义
         INSERT_DATE TIMESTAMP; 
         ALLDEPT_NO  VARCHAR(20);
          BEGIN
            --具体操作
         SELECT a FROM TAB_1;
                       .........
         END PRO1;
15、控制语句的不同
 db2:    
 IF …THEN ......ELSEIF THEN .... END IF;
 oracle: 
IF …THEN ......ELSIF  THEN .... END IF;
 
16、如何执行脚本SQL文件
Oracle: 
@$PATH/filename.sql; 
DB2:
db2 -tvf $PATH/filename.sql
 
17、查看当前用户的表和视图
DB2:
LIST   TABLES 
ORACLE:   
SELECT   *   FROM   TBAB;
 
DB2:DROP   TABLE删除表和定义。LIST   TABLES发现表不存在了。 
ORACLE:DROP   TABLE删除表的内容保留表的定义。可以看到表。
 
 
 
 
---------------------------------------------------------------
另外附上今天分享的东西:【快速复制表】
 
1.复制表结构及数据到新表 
CREATE TABLE 新表 SELECT * FROM 旧表 (DB2不适用)
 
2.只复制表结构到新表 
(1)oracle
CREATE TABLE 新表 SELECT * FROM 旧表 WHERE 1=2 
即:让WHERE条件不成立. 
(2)DB2
CREATE TABLE 新表 LIKE 旧表 
 
3.复制旧表的数据到新表(假设两个表结构一样) 
INSERT INTO 新表 SELECT * FROM 旧表 
 
4.复制旧表的数据到新表(假设两个表结构不一样) 
INSERT INTO 新表(字段1,字段2,.......) SELECT 字段1,字段2,...... FROM 旧表
posted @ 2012-07-28 12:46 tbwshc 阅读(935) | 评论 (0)编辑 收藏

java对象的初始化

小冬(珠海)11:02:48
我们知道一个对象可以有静态变量、变量、静态初始化块、初始化块,当我们创建一个对象时,它是怎么初始化的呢?按什么顺序初始化的呢?
 
  1. public class Test { 
  2.  
  3.      
  4.     // 静态变量 
  5.     public static String staticField = "静态变量"; // 变量 
  6.     public String field = "变量"
  7.     // 静态初始化块 
  8.     static { 
  9.         System.out.println(staticField); 
  10.         System.out.println("静态初始化块"); 
  11.     } 
  12.     // 初始化块 
  13.     { 
  14.         System.out.println(field); 
  15.         System.out.println("初始化块"); 
  16.     } 
  17.     // 构造器 
  18.     public Test() { 
  19.         System.out.println("构造器"); 
  20.     } 
  21.     public static void main(String[] args) { 
  22.         Test test = new Testb(); 
  23.  
  24.     } 
 
运行下代码,输出结果是:
静态变量
静态初始化块
变量
初始化块
构造器
 
 
由此可以看到,当new一个对象时,它并不是就是调构造方法,而是先初始化属性变量,我们把变量的定义先后顺序换下,再执行,会发现,静态的是先于非静态进行实始化的,那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?
我们先改下代码:
 
  1. public class Test { 
  2.  
  3.     public static TestA ta = new TestA(); 
  4.     // 静态变量 
  5.     public static String staticField = "静态变量"; // 变量 
  6.     public String field = "变量"
  7.     // 静态初始化块 
  8.     static { 
  9.         System.out.println(staticField); 
  10.         System.out.println("静态初始化块"); 
  11.     } 
  12.     // 初始化块 
  13.     { 
  14.         System.out.println(field); 
  15.         System.out.println("初始化块"); 
  16.     } 
  17.     // 构造器 
  18.     public Test() { 
  19.         System.out.println("构造器"); 
  20.     } 
  21.     public static void main(String[] args) { 
  22.         Test test = new Test(); 
  23.  
  24.     } 
  25.  
  26. class TestA { 
  27.     public TestA() { 
  28.         System.out.println("Test--A"); 
  29.     } 
 输出是:
Test--A
静态变量
静态初始化块
变量
初始化块
构造器
 
 
静态变量:static TestA ta = new TestA()在静态初始化块前,所以先输出Test--A
再换下位置,把static TestA ta = new TestA()放到在静态初始化块后,我们发现输出是:
静态变量
静态初始化块
Test--A
变量
初始化块
构造器
 
 
由此可见这是取决于它们在类中出现的先后顺序,同理可得:变量和初始化块之间也如此,总结可得:初始化优先级是(静态变量/静态初始化块)>(变量/初始化块)>构造器。
 
 
那继承关系时的初始化又是怎样的呢?如下:
大家应该知道,初始化子类时会先初始化父类,再看代码:
 
  1. public class Test extends Parent{ 
  2.     // 静态变量 
  3.     public static String staticField = "子类静态变量"; // 变量 
  4.     public String field = "子类变量"
  5.     // 静态初始化块 
  6.     static { 
  7.         System.out.println(staticField); 
  8.         System.out.println("子类静态初始化块"); 
  9.     } 
  10.     //public static TestA ta = new TestA(); 
  11.     // 初始化块 
  12.     { 
  13.         System.out.println(field); 
  14.         System.out.println("子类初始化块"); 
  15.     } 
  16.     // 构造器 
  17.     public Test() { 
  18.         System.out.println("子类构造器"); 
  19.     } 
  20.     public static void main(String[] args) { 
  21.         Test test = new Test(); 
  22.     } 
  23.  
  24. class Parent{ 
  25.  
  26.     public String field = "父类变量";// 变量 
  27.     public static String staticField = "父类静态变量"; // 静态变量 
  28.     // 静态初始化块 
  29.     static { 
  30.         System.out.println(staticField); 
  31.         System.out.println("父类静态初始化块"); 
  32.     } 
  33.     // 初始化块 
  34.     { 
  35.         System.out.println(field); 
  36.         System.out.println("父类初始化块"); 
  37.     } 
  38.     // 构造器 
  39.     public Parent() { 
  40.         System.out.println("父类构造器"); 
  41.     }    
刚才结果应该是:
父类静态变量
父类静态初始化块
子类静态变量
子类静态初始化块
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
 
从结果看到,并不是父类完全初始化完后再进行子类的初始化,子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。
 
我们在main方法再创建一个对象,Test test2 = new Test();
大家就test2的初始化又如何?
 
为了好看,我们子类构造器里加多行代码System.out.println("***********");
输出结果:
父类静态变量
父类静态初始化块
子类静态变量
子类静态初始化块
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
***********
父类变量
父类初始化块
父类构造器
子类变量
子类初始化块
子类构造器
***********


发现什么了?
静态变量和静态代码块只加载一次 。
 
 
总结:
一、初始化优先级:
1、静态变量/静态初始化块)>(变量/初始化块)>构造器
2、父类>子类

二、静态变量和静态代码块只加载一次,因为它们是全局共享的
 
posted @ 2012-07-28 12:45 tbwshc 阅读(895) | 评论 (0)编辑 收藏

背景:先前在生产库上配置了oracle监控,每5分钟尝试连接一次数据库,若连接失败则通过nagios+fetion自动报警,此配置参考文章:http://ylw6006.blog.51cto.com/470441/787496

早晨收到报警信息后,登陆数据库执行ps -ef查看oracle的后台进程都在,使用conn /as sysdba的方式登陆数据库,提示连接到空闲的实例,使用easy connect 方式连接则报oracle实例无法分配内存,从报错提示上看,就像oracle数据库实例未打开的状态!分析alert日志不断出现如下错误信息:
Process J002 died, see its trace file
kkjcre1p: unable to spawn jobq slave process
Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_cjq0_18577.trc:

trace文件摘要信息如下:
*** 2012-07-26 10:20:31.068
Process J002 is dead (pid=13857 req_ver=1136 cur_ver=1136 state=KSOSP_SPAWNED).

*** 2012-07-26 10:20:32.069
Process J002 is dead (pid=13876 req_ver=1594 cur_ver=1594 state=KSOSP_SPAWNED).

google查询一番后,发现大部分描述和oracle的进程数设置有关,又或者是内存不足引起!于是在oracle 10g环境下测试,线上数据库环境为11.2.0.3

一:设置processes初始化参数值为20,重启数据库后,已经占用19个进程

  1. SQL> select count(*) from v$process;  
  2.  
  3.   COUNT(*)  
  4. ----------  
  5.         19  
  6.  
  7. SQL> show parameter process;  
  8.  
  9. NAME                                 TYPE        VALUE  
  10. ------------------------------------ ----------- ------------------------------  
  11. aq_tm_processes                      integer     0  
  12. db_writer_processes                  integer     1  
  13. gcs_server_processes                 integer     0  
  14. job_queue_processes                  integer     10  
  15. log_archive_max_processes            integer     2  
  16. processes                            integer     20 

新的会话连接,则报连接到空闲的实例,alert日志则出现相应的报错

  1. [root@db1 ~]# su - oracle  
  2. [oracle@db1 ~]$ sqlplus /nolog  
  3. SQL*Plus: Release 10.2.0.1.0 - Production on Wed Jul 4 13:50:22 2012  
  4. Copyright (c) 1982, 2005, Oracle.  All rights reserved.  
  5.  
  6. SQL> conn /as sysdba  
  7. Connected to an idle instance.  
  8.  
  9. [oracle@db1 dbs]$ tail -f /u01/app/oracle/admin/db1/bdump/alert_db1.log   
  10. Wed Jul  4 13:52:23 2012  
  11. ksvcreate: Process(q000) creation failed  
  12. Wed Jul  4 13:52:35 2012  
  13. Process q001 died, see its trace file  
  14. Wed Jul  4 13:52:35 2012  
  15. ksvcreate: Process(q001) creation failed  
  16. Wed Jul  4 13:52:37 2012  
  17. Process m000 died, see its trace file  
  18. Wed Jul  4 13:52:37 2012  
  19. ksvcreate: Process(m000) creation failed 

二:于是想到监控oracle的进程和会话数来进一步确定问题
1:首先要对用户进行显示授权,否则后面创建存储过程编译将会报错

  1. SQL> grant select on V_$SESSION tbo hr;  
  2. Grant succeeded.  
  3.  
  4. SQL> grant select on V_$PROCESS to hr;  
  5. Grant succeeded. 

2:建表,用来存储结果

  1. SQL> create table session_monitor(time timestamp,session_count number,process_count number);  
  2. Table created. 

3:创建存储过程,将数据插入表

  1. SQL> create or replace procedure proc_session  
  2.   2  is  
  3.   3  v_session number(8);  
  4.   4  v_process number(8);  
  5.   5  begin  
  6.   6   select count(*) into v_session from v$session;  
  7.   7   select count(*) into v_process from v$process;  
  8.   8   insert into session_monitor values (sysdate,v_session,v_process);  
  9.   9   commit;  
  10.  10  end proc_session;  
  11. Procedure created. 

4:创建任务

  1. SQL> var job number;  
  2. SQL> begin  
  3.   2    sys.dbms_job.submit(job => :job,  
  4.   3                        what => 'proc_session();',  
  5.   4                        next_date => sysdate,  
  6.   5                        interval => 'sysdate+2/1440');  
  7.   6* end;  
  8. PL/SQL procedure successfully completed. 

5:测试效果

  1. SQL> exec proc_session;  
  2. PL/SQL procedure successfully completed.  
  3.  
  4. SQL> alter session set nls_date_format='YYYY-MM-DD-HH24:MI:SS';  
  5. Session altered.  
  6.  
  7. SQL>  select * from session_monitor;  
  8.  
  9. TIME                                     SESSION_COUNT PROCESS_COUNT  
  10. ---------------------------------------- ------------- -------------  
  11. 26-JUL-12 03.02.12.000000 PM                       140           155  
  12. 26-JUL-12 03.02.14.000000 PM                       141           157  
  13.  
  14. SQL> select job,next_date from user_jobs where what='proc_session();';  
  15.  
  16.        JOB NEXT_DATE  
  17. ---------- -------------------  
  18.        145 2012-07-26-15:04:14  
  19.  
  20. SQL> select * from session_monitor;  
  21.  
  22. TIME                                     SESSION_COUNT PROCESS_COUNT  
  23. ---------------------------------------- ------------- -------------  
  24. 26-JUL-12 03.04.14.000000 PM                        87            94  
  25. 26-JUL-12 03.02.12.000000 PM                       140           155  
  26. 26-JUL-12 03.02.14.000000 PM                       141           157 

6:如果要删除任务,则运行下列的命令,145代表user_jobs视图中的job列

  1. SQL> begin  
  2.   2  dbms_job.remove(145);  
  3.   3  end;  
  4. PL/SQL procedure successfully completed. 

三:使用nagios+fetion,定时去监控会话和进程数
1:创建监控脚本,该脚本放任务计划中运行,每2分钟自动执行

  1. [root@server240 libexec]# cat session_oracle.sh   
  2. #!/bin/sh  
  3. rm -rf /tmp/session_oracle.log  
  4. export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db1  
  5. /u01/app/oracle/product/11.2.0/db1/bin/sqlplus hr/hr@192.168.1.240:1521/orcl <<EOF 
  6. set echo off  
  7. set feedback off  
  8. spool /tmp/session_oracle.log  
  9. alter session set nls_date_format='YYYY-MM-DD:HH24:MI:SS';  
  10. select session_count from (select * from session_monitor order by time desc ) where  rownum=1;  
  11. select process_count from (select * from session_monitor order by time desc ) where  rownum=1;  
  12. spool off  
  13. set echo on  
  14. set feedback on  EOF

2:创建第二脚本,用来处理前面监控脚本的日志输出,将结果返回给监控服务器

  1. [root@server240 ~]# cat /tmp/session_oracle.log
    SQL> alter session set nls_date_format='YYYY-MM-DD:HH24:MI:SS';
    SQL> select session_count from (select * from session_monitor order by time desc ) where  rownum=1;
  2. SESSION_COUNT                                                                  
    -------------                                                                  
              138                                                                  
    SQL> select process_count from (select * from session_monitor order by time desc ) where  rownum=1;
  3. PROCESS_COUNT                                                                  
    -------------                                                                  
              153                                                                  
    SQL> spool off
  4.  
  5. [root@server240 libexec]# cat check_oracle_session.sh   
  6. #!/bin/sh  
  7. STATE_OK=0 
  8. STATE_CRITICAL=2 
  9.  
  10. if  [ -f /tmp/session_oracle.log  ];then  
  11.      SESSION=$(grep -A 2 'SESSION_COUNT'  /tmp/session_oracle.log |tail -1|sed 's/[ ][ ]*//g')  
  12.      PROCESS=$(grep -A 2 'PROCESS_COUNT'  /tmp/session_oracle.log |tail -1|sed 's/[ ][ ]*//g')  
  13.      else   
  14.      echo "something wrong,please check monitor script"  
  15.      exit $STATE_CRITICAL  
  16. fi  
  17.  
  18. if   [ $SESSION -gt 500 ] || [ $PROCESS -gt 500 ];then   
  19.      echo "Current session is $SESSION,process is $PROCESS "  
  20.      exit $STATE_CRITICAL  
  21.      else   
  22.        echo "Current session is $SESSION,process is $PROCESS "  
  23.        exit $STATE_OK  
  24. fi 

四:实际效果
[root@server198 ~]# /usr/local/nagios/libexec/check_nrpe -H 192.168.1.240 -c check_oracle_session
Current session is 138,process is 153

五:后期观察结果,估计和内存问题相关
[oracle@server240 ~]$ sar -r |grep 10:20
10:20:02 AM   3481492  21195164     85.89    675584  13661448   3683012    413552     10.10     
[oracle@server240 ~]$ sar -r |grep 04:40
04:40:01 PM   2076748  22599908     91.58    734088  14581728   4048864     47700      1.16

posted @ 2012-07-28 12:43 tbwshc 阅读(1039) | 评论 (0)编辑 收藏

仅列出标题
共10页: First 2 3 4 5 6 7 8 9 10