来源:cww
上回谈的是如何建立连结,这SQL与Informix没有什麽不同,但是
再来要谈的是令人十分痛苦的事了,那便是如何产生一个rdoResultSet物件
rdoResultSet相对应於DAO的Recordset物件,产生的方式主要如下:
Private WithEvents cn As rdoConnection
Private en As rdoEnvironment
Private rs As rdoResultset
Private qry As rdoQuery
Dim sql As String
Set en = rdoEnvironments(0)
Set cn = New rdoConnection
en.CursorDriver = rdUseServer '见注一
connstr = "UID=cww;PWD=jjh5612;Database=cwwpf@eis;" _
+ "Driver={OpenLink Generic 32 Bit Driver};" _
+ "Host=192.168.0.61;" _
+ ";FetchBufferSize=30" _
+ ";NoLoginBox=Yes" _
+ ";Options=" _
+ ";Protocol=TCP/IP" _
+ ";ReadOnly=No" _
+ ";ServerOptions=" _
+ ";ServerType=Informix 7.2"
cn.Connect = connstr
Set cn = en.OpenConnection("", rdDriverNoPrompt, _
False, connstr) '第三个叁数False表示非ReadOnly
.
.
rs.Close
cn.Close
|
如果不想cn 加入en.Connections之中,则改用以下方式
Set en = rdoEnvironments(0)
Set cn = New rdoConnection
connstr = "UID=cww;PWD=jjh5612;Database=cwwpf@eis;" _
+ "Driver={OpenLink Generic 32 Bit Driver};" _
+ "Host=192.168.0.61;" _
+ ";FetchBufferSize=30" _
+ ";NoLoginBox=Yes" _
+ ";Options=" _
+ ";Protocol=TCP/IP" _
+ ";ReadOnly=No" _
+ ";ServerOptions=" _
+ ";ServerType=Informix 7.2"
Set cn = New rdoConnection
cn.CursorDriver = rdUseServer
cn.EstablishConnection rdDriverNoPrompt, False
sql = "Select * From qppfa"
Set rs = cn.OpenResultset(sql, rdOpenForwardOnly, _
rdConcurReadOnly)
.
.
rs.Close
cn.Close
|
重点都是在OpenResultset这个方法上,但是如果要做更多的控制,我会在rdoQuery上使
用OpenResultset,如下:
Set en = rdoEnvironments(0)
Set cn = New rdoConnection
cn.CursorDriver = rdUseServer
connstr = "UID=cww;PWD=jjh5612;Database=cwwpf@eis;" _
+ "Driver={OpenLink Generic 32 Bit Driver};" _
+ "Host=192.168.0.61;" _
+ ";FetchBufferSize=30" _
+ ";NoLoginBox=Yes" _
+ ";Options=" _
+ ";Protocol=TCP/IP" _
+ ";ReadOnly=No" _
+ ";ServerOptions=" _
+ ";ServerType=Informix 7.2"
cn.Connect = connstr
cn.EstablishConnection rdDriverNoPrompt, False
sql = "Select * From testtab"
Set qry = cn.CreateQuery("MyQuery", sql)
qry.RowsetSize = 50 '见注二
qry.MaxRows = 200 '见注三
Set rs = qry.OpenResultset(rdOpenKeyset, _
rdConcurRowVer)
.
.
rs.Close
cn.Close
|
至於说OpenResultset方法中又提及记录集又分成以下四种:
rdOpenForwardOnly 0 (预设值)是固定集 (Fixed Set),不可卷动 (Non-Scrolling)
rdOpenKeyset 1 固定集,可卷动的查询记录集的资料指标,存的只是Key,而其
他的资料於需要时可以去读取,因此它可以读到其他人更新过後
的资料,当然,需和RowSetSize做搭配,别人在我们读取到Data
後才更新资料时,我们的Process仍然没有反映最新的资料,此
时下个Move 0指令可以更新至最新的Data。不过看不到其他人新
增到该Result Set的资料
rdOpenDynamic 2 动态集的资料指标,特性和rdOpenKeyset同,唯其他Process加入
该Resultset的资料可以在目前Process中看到。
rdOpenStatic 3 是固定集,和rdOpenKeyset不同的是,资料集一建立之後就看不
见其他Process对Resultset的修正。
其实,我觉得MS 对於这些东西的说明十分不清楚,而且上面的说明针对的都是rdUseServer
的Server端之Cursor,而ODBC端的Cursor没有像上面所说的那样,ODBC端的Cursor因为
资料是Copy到Client端,自然也就看不到他人是如何对Resultset成员的修改了;当然了,
理论上还是可以得知,不过这要花上代价,那就是每一次读取资料时还得向Server来询问
是否有改,那不就失去Client端Cursor的原意了吗?所以我们可以想像,ODBC端的Cursor
只有rdOpenForwardOnly与rdOpenStatic这两种。
这样就结束了吗?还没有!以上是MS SQL SERVER6.5的特性,而Informix呢?InforMix
Server端的Cursor只有rdOpenForwardOnly与rdOpenKeyset两种(注意,不是rdOpenStatic)
这和Informix Server有关,然而我们在Informix为後端的Server中使用rdOpenStatic/
rdOpenDynamic时,也不会有误,只是行为和rdOpenKeyset相同。而Informix为後端,但
我们使用rdUseOdbc之Client端Cursor呢,此时只有rdOpenForwardonly与rdOpenStatic
(注意,不是rdOpenKetset喔),这个原因是来自於ODBC Cursor的特性。
而不管是SQL SERVER或Informix为後端,rdUseNone的方式就没有太多的选择,一律只能
使用rdOpenForwardonly的Cursor型态,这不必多说,应是很自然的事吧。
透过上面的说明,何时用Client端的Cursor何时用Server端的Cursor应比较有念了吧。
注一:
CursorDriver 有以下数种方式
rdUseIfNeeded 0 ODBC 驱动程序 将选取适当的资料指标样式。可能的话,使用
伺服端资料指标。
rdUseOdbc 1 将使用ODBC 资料指标程序库(ODBC Cursor Library)。
rdUseServer 2 使用伺服端资料指标。
rdUseClientBatch 3 RDO 将使用乐观批次资料指标程序库
rdUseNone 4 记录集(Result Set)不以资料指标型态传回。
而这里想讨论的是
rdUseOdbc rdUseServer rdUseNone,而rdUseClientBatch不多做讨论
rdUseOdbc 在Client端建立Cursor来管理Cursor的移动,因为是在Client端,所以实作
上是在Client端Copy一份ResultSet,不同的Client端各自有其一份资料;
假设有A,B两个Client端要求了相同的资料,如:都是下Select * from testtab
之SQL指令,假设一共有740笔资料,那麽,A, B各自保有740笔资料,如果
对这些资料作更动,A看不见B,B也看不见A(这合理嘛,因为各自有其资料
的Copy )。然而这740笔资料是在什麽时候传到Client端呢?并不是OpenResultSet
时便立即全部传过来,而是一开始只传部份的资料过来,而Cursor指到後面
的资料时,才会将之再传过来。所以,如果我们使用MoveLast方法时,会看到
这个指令执行时整个程序停顿了下来(没有使用非同步传送时),这时候电脑
便是在接收Server端传送来的资料,如果我们在传送资料的过程中查看一下硬
碟空间,会发现,空间正被用走,而且传送的过程时而会停个一下下。而这
rdUseOdbc的Cursor在Server端有没有做什麽动作呢?这个没有书有做说明,而
我认为Server端可能也会产生一个ForwardOnly的Cursor或者一个Tmp 的Table,
否则Server如何知道曾传过了多少资料给Cilent端是不是呢?(先前提过,并
不是在OpenResultset时便把所有资料传过来,而且在OpenResultSet时,会花
个一些时间才完成,时间的多少要看资料量与Sql的语法)。为什麽我会如此假设
呢,我做过一些Testing,如果Cursor的建立很容易,例如:Select * from testtab
where id between 1 and 800 (而有在id上做Index),那麽,这个Cursor的
建立很快,一下子便可以传回Client端了;我们可以想像,这种Cursor我们可以
在Server端建一个ForwardOnly的Cursor,所以只要Fetch个某个数量的资料後,
便可传回Client了,所以速度快,等需要更多资料时便从目前Server端的Cursor
位置再继续读取下去。相反的,如果是Select * From testtab where
fld2 = 'tt' order by fld3 (fld2, fld3上没有Index),这时候,就得在tmp
Database中建立起该Table了,要不就得将所有Table中的Data都传到Client了,
我想,应是在Tmp Database中建Table比较像,所以这一类的Cursor在建立时
就要花较多的时间,相对的OpenResultSet的时间就会久。
rdUseServer
和rdUseODBC相反,Cursor是在Server端建立,在Server端所建的Cursor和资料
库的特性就习习相关,我们如果查阅RDO的使用说明,会告诉我们Cursor又有分
Static, Keyset, Dynamic, ForwardOnly等等,但并不是所有的Database Server
都具有这个能力,例如说,SQL Server中就有所谓的Dynamic Cursor,这种
Cursor的特色在於:我们的Resultset建立完之後,别人新增了资料,只要该
资料在我们ResultSet的范围,我们也可以看得到它。然而,这种Dynamic的Cursor
在Informix 是没有提供的;但是一般来说,发展ODBC的厂商并不会在我们使
用Server 端没有提供的Cursor种类时,产生任何错误,取而代之的是,他们
会使用另一种较接近的Cursor来取代,例如说,对Informix Server使用Dynamic
Cursor时,并没有产生错误,而其dynamic Cursor的行为和KetSet Cursor相同(
例:如果我们Server端是SQL Server,那使用Dynamic Cursor的Resultset,其
RowCount会传回-1 ,但如果Server端是Informix则传回实际的笔数)。使用
Server端的Cursor有好处也有坏处,好处等一下再说,先讲它的坏处,因为
Cursor要由Server来handle,所以多人使用时很浪费资源,尤其使用的Cursor
如果具有任意往前往後移动者(这叫Scroll Cursor),会在Server端的Temp
database建立table,那花的时间与Resource会较多。rdUseServer所建的Cursor
如果是属於Scroll Cursor者(static, keyset, dynamic皆是)它会在Server端
将资料全准备好才算完成我们所下的OpenResultset的方法,如果资料量又大的话
,那这个temp的table就会很大,可能会使我们的Resultset会造不出来。一般来
说,使用rdUseServer的Scroll Cursor在OpenResultset时花的时间会比rdUseODBC
的Scroll Cursor多,但是使用MoveLast时,刚好相反,因为Server端的Scroll
cursor是使用Temp Database中所建立的Temp table,而这table在OpenResultset
时,便已完全的造出了。当然了,不管用Server/Client端的ForwardOnly Cursor
(即OpenResultset使用rdOpenForwardOnly叁数),在OpenResultset时花的时间都
比较少,因为不必在Server端建立temp table;而的Cursor建立起来的速度(即
OpenResultset的速度)除了和是否是Scroll Cursor有关外,和所下的Sql指令与
RowSetSize这个属性有关。
rdUseNone 字面上没有使用Cursor,不过我觉得在RDBMS中应仍旧是使用Server端的Cursor来
做,只是这种Cursor是ForwardOnly, ReadOnly,这类的Cursor不像Scroll Cursor
一定会在tmp Database中建立Table,所以Resource用得少,OpenResultset回应得
较快(建立快,且只Fetch一笔);因为OpenResultset方法会令Server端的Cursor
於Open Cursor後Fetch一笔资料,所以OpenResultset的速度快或慢,便取快於这
Fetch的速度了。而Client端呢,就真的没有Create Cursor来维护了。rdUseNone
的方式於只查寻没有修改、新增的情况中应是使用最多的一种,因它花费Server/
Client 的资源最少。使用它时,OpenResultSet只能使用rdOpenForwardOnly与
rdConcurReadOnly的搭配,不能使用其他搭配,而且其RowSetSize自动设成 1。
注:以上皆是本人的试验与假设,若有问题敬请多多指正。
而如何设定Cursor是在Client端或Server端呢,那便得设定CursorDriver。
如果没有设定,会使用内定的rdUseIfNeeded,而手动的设定要如此:
1.如果在rdoConnection上设定CursorDriver属性,便得使用EstablishConnection方法
来做,如下:
cn.CursorDriver = rdUseServer
cn.EstablishConnection rdDriverNoPrompt, False
sql = "Select * From qppfa"
Set rs = cn.OpenResultset(sql, ....)
2.如果在rdoEnvironment上设定CursorDriver属性,便得使用OpenConnection方法
来做,如下:
en.CursorDriver = rdUseServer
Set cn = en.OpenConnection("", rdDriverNoPrompt, False, connstr)
sql = "Select * From qppfa"
Set rs = cn.OpenResultset(sql, ....)
注二:
RowSetSize 是rdoQuery的一个属性,以下这一段是OnLine Help的说明
RowsetSize 属性确定有多少笔索引键集 (Keyset) 的资料列被应用程序放入缓冲区中。
RDO 使用RowsetSize 属性来确定有多少资料列被 ODBC 的 SQLExtendedFetch 函数读取
到记忆体中。调整 RowsetSize 之大小,会影响到其性能以及为维护索引键集缓冲区所
需的记忆体。
如何,是不是每个字都懂,但是就是有看没有懂,说实在的,我也不敢说全懂,不过我做
了一些Testing,这好像是:
1.如果是rdUseODBC的Cursor,这影响ResultSet一次传回Client端的笔数,例如:
ResultSet中一共有800笔资料,在OpenResultSet时(且不为rdOpenForwardOnly)时,
不会将这800笔Data一次传回,而是先传回RowSetSize所设定的笔数(如:100);等要读
第101笔时会再要求Server把101-200笔的资料传回来。所以了,如果Cursor的需Scan
table才能知道有哪些Row符合条件时,RowSetSize也会影响OpenResultset所需的时间。
2.如果是Server端的Cursor(rdUseServer),截录online help的说明
另外,当使用悲观锁定的 (rdConcurLock) 平行处理 (Pessimistic Concurrency) 时
,RowsetSize 属性决定了有多少资料列(及其资料页)被锁定。例如,如果设定
RowsetSize 属性为 100 并且执行一个带有 rdConcurLock 选项的 rdoQuery 物件时
,就锁定记录集的前 100 笔资料列以及和每一笔被锁定资料列相关的资料页,直到该资
料指标被关闭或将目前资料列指标移至该记录集的结束位置。在任何情况下,至少有
RowsetSize 笔资料列被锁定。
除此之外,RowSetSize也会影响Cursor建立後的一些特性,例如说,RowSetSize设为2
那代表OpenResultSet之後会读取两笔的资料,而此时的Current Record是第一笔,如果
尚未MoveNext到第二笔, 而第二笔资料被他人修改了(如果没有Tranaction而且是
rdOpenKeyset的ResultSet),那我们第一次下MoveNext後 (即指到第二笔资料),得到的
资料是未修改之前的Data,此时如果下Move 0的指令才会再得到最新的资料。相反的,如
果我们设RowSetSize = 1,而Cursor未指向第二笔前(即未MoveNext),第二笔资料被更
新了,而後的MoveNext会得到的是新的资料。
3.rdUseNone则固定RowSetSize = 1
注三:
MaxRows的设定限制了ResultSet的最多笔数,但Informix的设定没有效
阅读(808) | 评论(0) | 转发(0) |