第四章 深入了解ADO(这本书最精华的地方)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
4.1 ADO的CursorEngine
Cursor是一种数据结构,主要用来维护从数据源取得的结果数据集。
在ADO的对象架构中,ConnectionObject主要用来连接数据源,RecordSet是一个提供COM接口的Cursor对象。
<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />4.1.1 Client-Side Cursor与Server-Side Cursor(Cursor的位置)
首先必须清楚几个概念,ADO操作数据是通过ADO引擎,来回寻找记录是通过ADOCursor引擎,而只要有ADO引擎就会有配套的ADO缓存。
Client-Side Cursor
Cursor维护在客户端机器的ADO缓存中。Record对象使用查询语句向数据源发出存取数据命令后,这些由数据源处理RecordSet对象查询语句之后取得的数据便会传送到客户端缓存中(ADO)。接着由客户端ADO Cursor控制以便让客户端应用程序存取这些数据。用Client-Side Cursor,则Cursor类型为Static或ForwardOnly。它维护的数据集与数据源中的数据已经没有实体连接,但是修改仍可以传回数据库。
Server-Side Cursor
数据被存储在Server端数据源的ADO缓存中(第一种Server-Side Cursor)或数据源本身的缓存中(第二种Server-Side Cursor,大型RDBMS支持),Server端的ADO引擎负责所有的工作。Cursor类型有KeySet Cursor和Dynamic Cursor两种。
第一种Server-Side Cursor
4-1-2 Static Cursor
回传的数据集由ADO的Cursor引擎处理,Cursor的数据集就像是数据库中数据的快照一样,就和数据库中的数据没有关联了,所有的操作针对缓存。使用UpdateBatch更新回数据库。
通常应用程序都使用Client-Side Cursor与Static Cursor的组合,设定适当的CacheSize值(这个值为一次数据库取数据操作后存放于缓存的笔数,当检索超过CacheSize范围的数据,再从数据库中取),就会拥有良好的表现。
4-1-3 Forward-Only Cursor
与Static Cursor类似,但只能向前查找数据。当然,它的效率很高。
4-1-4 Keyset Cursor
能够让客户端应用程序看到被其他用户修改过之后储存在数据库中最新的数据。当使用KeySet Cursor时,数据源只会把处理SQL命令之后的结果数据集(也是CacheSize笔数)的键值字段储存在ADO缓存中,因此传递的数据量比前两种Cursor小的多。当浏览数据时,都是通过KeySet动态在数据库中查询。但是也会看不到用户新增数据,访问已删除的数据导致异常。
KeySet一般与Server-Side Cursor一起使用,否则会产生大量的round-trip(为什么与Client-Side就会roundtrip?此时客户端缓存上存的是什么?)
通过分析SQL Profiler,区别非常明显。用Server-Side Cursor先declare许多参数,cursoropen以后,一条条cursorfetch;而Client-Side就直接一个select搞定。
通过测试发现,在SQL管理器中更改了数据,在客户端程序中数据集浏览到该记录(Cursor必须变化),就会执行一堆CursorFetch自动更新,但对于没更新数据,并不会产生CursorFetch。分析xml文件可以发现,Server-Side Cursor缓存的数据与Client-Side Cursor一样。我猜客户端的缓存与服务端的缓存还是会随着Cursor的变化不断的传数据(客户端缓存存全部数据,服务端存KeySet),但数据源变化后可能通知或更新了服务端缓存,这样客户端缓存再访问服务端缓存时,就回引起数据源的访问,同时更新客户端。(仅仅是猜测)
4-1-5 Dynamic Cursor
类似Keyset Cursor,也只存储KeySet。但每当客户端需要新的数据时,在ADO缓存中的键值字段信息每次都会从数据库中根据最新的数据来建立。也就是说,每次更新时KeySet列表也会重新刷一遍,这样任何的增加和删除也能看到。
4-1-6 总结
Server-side Cursor虽然能够看到最新的数据,但需要持续的和服务端连接传送数据,客户端从服务端的ADO Engine要数据,对服务端的压力就比较大。
Client-Side Cursor一次取大量数据,使启动速度较慢,但不用持续的传送数据,配合BatchUpdate模式,效果比较好。如果对数据的更新要求不高,就用Client-Side Cursor。
总之,Cursor的位置决定了要访问的ADO缓存的位置,而Cursor的类型决定了缓存中存储的数据的形式(全部还是键值),CacheSize决定了一次放在缓存中的数据笔数(超出范围再取)。
4-2 ADO修改Data的流程(前面已讲)
4-3 原生ADO
原生ADO封装在ADOInt中,ADOExpress封装在ADODB中。
4-3-1 翻页
如RecordSet的页面定位功能,可以通过数个RecordSet对象的属性完成。(当然,翻页还是做成存储过程比较好),实现翻页的方法:
adodsCustomers.RecordSet.PageSize:=页面大小
adodsCustomers.RecordSet.AbsolutePage:=要翻的页
而PageCount可以返回页数。
4-3-2 动态属性
每一个ADO对象的动态属性都储存在一个称为Properties的集合属性中。Properties中存储的类型是Property_,有Name、Type、Value、Attributes四个属性。通过ADODataSet1.RecordSet.Properties就可以获得动态属性,然后就可以遍历了。
UpdateMode:
我们知道,ADOExpress用Post或UpdateBatch,会动态生成SQL,如
exec sp_executesql N'UPDATE "StudentCourse".."SC" SET "score"=@P1 WHERE "score"=@P2 AND "SCNo"=@P3', N'@P1 int,@P2 int,@P3 varchar(10)', 12, 89, '2 '
可以看到Where采用主键加原始值生成,这是由ADO的RecordSet中的UpdateCriteria动态属性决定的。有四种值:
常数 | 数值 | 说明 |
AdCriteriaKey | 0 | 使用键值字段 |
AdCriteriaAllCols | 1 | 使用所有字段 |
AdCriteriaUpCols | 2 | 使用键值+所有被修改字段(默认) |
adCriteriaTimeStamp | 3 | 使用键值和TimeStamp字段 |
过滤与排序优化
对数据集中的数据排序时,如果动态建立索引的话,排序会比较快。更改ADO的Field原生对象中”Optimize”动态属性,就可以建立动态索引。使用方法:
//在Salary字段上建索引
aField:=ADODataSet1.FieldByName(‘Salary’);
pties:=ADODataSet1.RecordSet.Fields[aField.FieldNo-1].Get_Properties;
pty:=pties.Get_Item(‘Optimize’);
pty.Value:=True;
ADODataDataSet1.Sort:=’Salary ASC’;
pty.Value:=False; //释放
4-3-3 TADODataSet、TADOQuery、TADOTable
效率上差不多,TADODataSet必须要回传寄过,TADOTable只能管理一个表,而TADOQuery就可以查询或更改。不过TADODataSet与ADO架构更相近。
4-5 ADO执行效率
Important Principles:
1)尽量找到真正的原生ADO和OLE DB驱动程序,尽量不要使用ODBC。
2)尽量使用客户端CursorLocation
3)适当设定CacheSize值。虽然1000可以得到较好的效率/空间比,但传的太多也会延迟响应时间。
4)尽量使用存储过程。另外ADO的Prepared属性可以把SQL语句预编译成存储过程,对经常调用的SQL语句推荐使用。
5)对于不回传结果数据集的工作,可以考虑结合存储过程和ADO异步执行模式。
6)使用数个不同的TADODataSet、TADOQuery来完成各个语句(我觉得语句不多的话可以每个语句对应一个TADOQuery,这样就不用每次Clear了)
7)尽量使用Optimistic和BatchOptimistic这两种类型的LockType(不过有并发问题),使用Pesstimistic一次就锁一个页,效率很低。
8)尽量使用BatchUpdate模式
9)MarshalOptions控制了客户端修改的数据如何传递回OLE DB Provider进行更新工作,适当的将其设为moMarshalModifiedOnly。
10)对于和图形用户接口有关的ADO应用程序,如需要在TDBGrid种显示大量的数据,可以暂时Disable Controls,增加GUI的效率。
我的想法:专门用TADODataSet/TADOQuery执行查询语句(客户端、ltStatic、CacheSize 1000),修改时对内存中的字段先修改,用户确认后再UpdateBatch,不能UpdateBatch的就用TADOCommand执行更新,这样减少了一次Select。主从表也可以考虑异步。
所有评论(0)