VisualFoxPro9中新的数据处理方式 |
|
www.nanhushi.com 佚名 不详 |
Visual FoxPro 9.0与以前的版本相比,在数据引擎上做了很大的改进。从增强的SQL语言到支持新的数据类型和索引都作了增强,本文阐述了这个最新版本作为一个成熟开发平台的魅力。
数据引擎的改变主要体现在以下5个方面:
· 增强的SQL语言:取消了很多硬编码的限制,增强了子查询和关联查询的支持,支持更复杂的表达式,以及增强了对UNION的支持。
· 性能方面:加入了一个全新的索引方式,增加了过滤型索引的性能,提高了了TOP n ,MIN()/MAX()以及LIKE这些查询子句的性能。
· 命令和函数:对数据操作的更具灵活性,增强对SQL中showplan的支持,增加ICASE()来代替IIF()函数。
· 新的数据类型:支持VarChar、VarBinary和BLOB等新的数据类型,并提供相应的类型转换函数:CAST()。增强了现有函数对数据类型的控制和转换能力
· 远程数据:增强了事务控制的能力,游标机制使得代码逻辑更加清晰,并且对CursorAdapter作了加强,使开发者只需数行代码就可以方便地访问远程视图。
由于提供了与SQL Server强有力的互操作性,Visual FoxPro 9对客户端/服务器模式做了很大的改进。通过支持新的数据类型,并取消了SQL语言的诸多限制,同一套代码可同时运行在本地数据引擎和SQL Server这两种不同的数据源上。
以上是大致的描述,下面让我们深入剖析这些新增功能。
SQL子查询的增强
如果要用一句话来表示SQL子查询的增强程度,那就是:“太多了”!SQL语句中再没有了元素数量的硬编码限制。一个简单的SELECT语句能包括更多的表、连接、子查询、嵌套子查询和联结。
SQL语句中的IN子句中再也没有数量限制。在以前的版本中IN实际被映射到了一个名字INLIST()函数中,但现在这种依赖取消了。这个改变使得IN子句能使用更多的参数来生成非常复杂的SQL语句。与原来版本不同,只要找到相应记录,Visual FoxPro 9会自动停止计算IN子句中的表达式,这将带来性能的提高。
完全无限制?
IN参数表的元素也不是完全无限的,它的最大数量等于函数SYS(3055)的返回值,而这个函数的返回值与实际可用内存有关,因此如果你的可用内存越大,那么IN子句支持的元素就越多。无硬编码的限制并不等于完全无限制。像可用内存以及表达式的复杂性都能决定是否能运行一个非常长而且复杂的语句,你要花很大的功夫才能找出它们在你的机器上的真实极限。
增强的子查询功能
子查询在SQL语言中是一个很有用的功能。它一般处于WHERE子句中的右边,充当一个选择器的作用。在Visual FoxPro 9中,子查询还可以处于SELECT的参数列表中(称为投影)以及FROM子句中(称为派生表)。
当你使用投影时,如果子查询没有返回任何记录,那将返加一个空值(NULL)。投影还允许互相关联,以后我们会讲到这点。 以下使用投影的SQL语句的一个例子:
SELECT ; C.CustomerID, ; C.CompanyName, ; (SELECT YTD_Sales FROM Sales_02 WHERE ; C.CustomerID = Sales_02.CustomerID) AS Y02,; (SELECT YTD_Sales FROM Sales_03 WHERE ; C.CustomerID = Sales_03.CustomerID) AS Y03,; (SELECT YTD_Sales FROM Sales_04 WHERE ; C.CustomerID = Sales_04.CustomerID) AS Y04 ; FROM Customers C | 这个SELECT语句返回最后三个会计年度的客户ID和公司名称。
使用投影的限制是子查询只能查询一个字段,并且子查询返回的记录数不能大于1。
投影的另一个有价值的使用方法是它可以成为表达式的一部分,如下所示:
SELECT ; C.customerID, ; C.companyname, ; SUM(D.quantity*D.unitprice) AS CustTotal ,; (SUM(D.quantity*D.unitprice) / ; (SELECT SUM((quantity*unitprice)-discount) ; FROM OrderDetails D2) ; )*100 AS PctTotal ; FROM Customers C ; INNER JOIN Orders O ; ON C.customerID = O.customerID ; INNER JOIN OrderDetails D ; ON O.orderid = D.orderid ; GROUP BY C.customerID, C.companyname, O.orderID ; ORDER BY pctTotal DESC | 这个SELECT语句返回客户ID、公司名称、销售额以及销售额占总销售额的百分比。
注意在以上语句中,子查询充当SELECT列表中的一个复杂表达式,并且它还包含一个聚集函数SUM(),这里我们可以看到使用它的灵活性。
子查询的另一种使用场景即派生表,实际你可以将它看作一个逻辑表。
考虑以下的例子:
SELECT ; C.customerid, ; P.product_count AS p_count; FROM Customers C, ; (SELECT c2.customerid, ; COUNT(DISTINCT D.productID) AS p_count ; FROM Customers C2 ; INNER JOIN Orders O ; ON C2.customerid = O.customerid ; INNER JOIN OrderDetails D ; ON O.orderid = D.orderid ; GROUP BY c2.customerid) AS P ; WHERE C.customerID = p.customerID ; AND P.p_count >= ; (SELECT (COUNT(*)*.50) FROM Products) ; ORDER BY p.product_count DESC | 这个SELECT语句返回客户ID、所有购买了50%产品的客户,以及它们所购买的产品数量。
观察以上的语句,你可以发现派生表有一个名为“P”的别名,这与普通字段别名的语法一样――都必须用AS子句来表达。而且这个子查询很复杂(在本例中,它关联了两个表),这个派生表还可以作为WHERE子句的一个条件或者将它放在ORDER BY子句中。
与投影不同,派生表能返回多个字段以及多条记录,但它不能相互关联。另外,所有的子查询都会在主句中的SELECT执行之前运行。
子查询还可以充当UPDATE语句中的SET列表。但SET子句只允许使用一个子查询,并且当SET子句使用子查询后,那WHERE子句中就不允许再使用子查询了。
更好的关联支持
新版本中的UPDATE语句和DELETE语句支持关联。这样,一条语句可以引用不同的表,如下所示:
DELETE products ; FROM mfg ; WHERE mfg.productID = products.productID; AND mfg.discontinued = .t. | 这个DELETE语句删除mfg表中所有不再生产的产品。
另一个关联UPDATE语句示例如下:
UPDATE products ; SET unitprice = mfg.msrp *.90 ; FROM mfg ; WHERE mfg.productID = products.productID | 这条UPDATE语句将零售产品的价格打了九折。可能你会问:它支持子查询吗?当然支持。但使用的时候要格外小心。因为如果子查询没有返回任何记录,那将会返回一个值为NULL的空记录。而这恰恰不是你所希望得到的结果。如下所示:
UPDATE products ; SET unitprice = ; (SELECT ( msrp *.90 ) ; FROM mfg ; WHERE mfg.productID = products.productID) | 这条UPDATE语句的作用与上条基本相似,但如果子查询中的产品没有找到的话,那unitprice将被置为NULL。
视图与查询设计器
尽管新版本增强了子查询功能,但不幸的是在视图与查询设计器中并不支持这种增强功能。并且由于SQL中的IN子句中的元素数目取消了硬编码的限制,但视图与查询设计器中并不知道,因此如果你使用设计器,那IN子句还是只支持24个元素。
增强的UNION操作符
由于联结的数量没有了硬编码的限制,你可以在INSERT INTO子句的结果集中使用UNION。也可以在使用UNION的同时使用ORDER BY子句。
性能
不管你是访问远程数据还是依赖于它强大的本地数据库引擎,Visual FoxPro始终将性能考虑在第一位。Visual FoxPro 9进一步地增强了数据引擎的功能。
二进制索引
这种新型的索引使用方法如下:
INDEX ON DELETED() TAG DELETED BINARY
这种索引能与任何非空的逻辑表达式一起使用。除此之外,FOR表达式、ASCENDING、DESCENDING、UNIQUE或CANDIDATE关键字不能与它一起使用。
二进制索引并不支持SET ORDER TO命令,而且INDEX ON命令会将当前的order设为0。但你可在Seek语句中使用二进制索引。
二进制索引最大的优势在于它的索引文件大小。以一个包含800万条记录的表为例,它的二进制索引文件的大小差不多为表大小的三十分之一。尺寸越小意味着在执行APPEND和REPLACE操作时I/O处理速度越快,但遗憾的是所有的Rushmore优化技术目前都还不支持二进制索引。
如果SQL语句返回的记录起过表中总记录的三分之一的话,那Rushmore将得到很好的发挥(当所有的记录都命中的话会提高92%的速度)。如果SQL语句返回的记录低于总记录的三分之一,那Rushmore将变得很慢(如果没有记录命中的话会降低两倍的速度)。
在Visual FoxPro 9中,将DELETE语句设置为二进制索引是一种增强性能的简单方法。但要注意版本的问题,因为以前的版本并不支持这种新的索引方式。
Rushmore优化技术
新版本中有使用了大量的Rushmore优化技术,例如对TOP N[PERCENT]作了优化,这样便能提供更好的性能。它一般与ORDER BY子句配合使用,返回前N个或者前百分比数目的记录。在Visaul FoxPro 9中它减少了内排序操作和文件I/O操作,使得执行这种类型的语句占用更少的内存,并且正如此语句所言,它只返回确切的前N个记录。
在以前的版本中,如果要统计一个班级总分排在前十名的学生,但中间存在并列名次的话,那结果会返回多于10个的记录。
在适当的情况下,Visual FoxPro 9将在FOR DELETED()子句和FOR NOT DELETED()子句中使用过滤索引来对MIN()和MAX()这两个聚集函数进行优化,可以提高MIN()和MAX()的计算速度。
如果LIKE模糊查询语句中的条件以“%”为结尾,那查询速度也将得到很大提高(请注意,“%”只能出现在查询条件的结尾,而不能出现在其它地方,否则优化无效)。这种优化的结果等同于普通WHERE子句查询的速度。
更多的智能索引技术
Visual FoxPro 9比以前的版本更智能化,它充分地让索引获得Rushmore的优化技术,如下所示:
INDEX ON DELETED() TAG DELETED | 以上语句自动对NOT DELETED()和DELETED()条件进行优化,不用你添加一条INDEX ON NOT DELETED()来实现。
这里有个特例,就是当索引过过滤表达式采用了FOR NOT DELETED()作为Rushmore的优化,并且SET DELETED设为ON的话,那就无须为 NOT DELETED()作优化。
命令和函数
一些新的命令和函数得到扩展,能够更好地控制Visual FoxPro将读取或写入数据到磁盘中去。
数据访问与提交的细粒度控制
在Visual FoxPro中,SET REFRESH命令后的第二个参数控制当前内存中数据刷新到磁盘中的间隔时间,原来的版本只能以整数作为最小单位,但现在可以为小数。你还可以将它指定为“?1”,这样可以强迫Visual FoxPro每次只从硬盘中读取数据,从而降低数据丢失的风险,并且这个时间的最小值可以设为“.001”。
如果你将这个值设得过低的话,可能会降低性能,特别是当请求增多,或是跨网络存取数据库时尤其如此,因此要小心谨慎地使用它。
SYS(1104)函数用来清理程序与数据的内存缓冲区,以及数据表的缓冲区。在Visual FoxPro 9中,SYS(1104)的第二个参数用来指定要清理的工作区或者别名,当一个应用打开了很多表时,如果调用SYS(1104),那清理所有的表缓冲区将会很耗时,有了这样的一个参数可以对它进行更好的控制,从而加快系统的响应速度。
FLUSH命令系列可以将对于表、索引、文件的的有修改全部回写到磁盘中去,在Visual FoxPro 9中,FLUSH命令被扩展为两个步骤:先指定要刷新的区域,然后调用FlushFileBuffers函数进行刷新。
尽管你可以通过指定要刷新的文件名、工作区或者表的别名来精细地控制回写的粒度,但有时Visual FoxPro 9回写数据到磁盘后,操作系统仍然不会真正地回写,而是将它继续保留在系统缓冲区中,这时你可以用FORCE关键字强制将系统缓冲区的内容回写到磁盘中。
以下是FLUSH命令的一些用法:
FLUSH "c:\data\customers.dbf" FLUSH "c:\data\customers.dbf" FORCE FLUSH IN 1 FORCE FLUSH IN customer FORCE FLUSH "c:\test.txt" FORCE FLUSH FORCE | 在以前的版本中,如果你使用SELECT语句的话,那么数据全部将从磁盘中取得。这意味着如果你想查询一些保存在表缓冲区中的未回写的数据的话,你必须编写一个额外的过程来完成这个功能。现在的版本通过使用SET SQLBUFFERING和SELECT ... WITH(Buffering =<表达式>)使得你可以方便地控制数据到底是从磁盘中取得还是从表缓冲区中获得,如下所示:
SELECT * FROM Customer WITH (BUFFERING = .t.) SELECT * FROM Orders WITH (BUFFERING = lUseBuffer) SELECT DISTINCT c.city, o.shipcity ; FROM customers C WITH (BUFFERING=.T.) ; JOIN orders O WITH (BUFFERING=.T.) ; ON c.customerID = o.customerID | 请注意每个表都要给出一个相应的WITH BUFFERING子句,如果不指定的话,Visual FoxPro 9将使用SET SQLBUFFERING中指定的值(缺省为 .f.)。
这是要提醒你的是只有Visual FoxPro 9本地数据才支持缓冲,如果你使用其他的诸如SQL Server等后端数据库做为数据源的话则存在缓冲管理。
CAST()函数
新的CAST()函数模仿的是SQL Server的一个同名函数。它可以在SQL语句中使用,也可以在普通命令中使用。如果在SQL语句中使用它的话,那你的SQL代码更遵循于TSQL规范。正如它的名字所指示的那样,这个函数将一个数据类型转化为另一个数据类型。
SQL语句中使用CAST()函数的语法如下:
SELECT CustomerID, ; CAST(nAmount*nRate AS N(8,2)) ; FROM SALES SELECT CustomerID, ; CAST(nAmount*nRate AS B NOT NULL) ; FROM SALES SELECT CustomerID, ; CAST(nAmount*nRate AS C(10)) ; FROM SALES SELECT foo.*, ; CAST(NULL as I) AS IntegerField ; FROM foo | ICASE()函数
另一个名为ICASE()的函数模仿了TSQL的CASE分支。它有点类似于IIF()函数,但它的有价值之处在于它不像IIF()函数那样会形成丑陋并且冗长的代码。
ICASE()函数需要指定相应的“条件/结果”参数对才能工作。第一个参数是条件表达式,如果条件表达式为True的话,那第二个参数就会执行;如果条件表达式为False的话,那第二个参数就会被忽略,转而执行下一个条件/结果参数对。如果参数配对错误,那么系统会报#11错误。
以下是ICASE()函数的使用示例:
nHour = HOUR(DATETIME()) ? ICASE( nHour = 8, "breakfast" , ; nHour = 10, "caffeine" , ; nHour = 12, "lunch" , ; nHour = 15, "caffeine" , ; nHour = 18, "dinner" , ; "snack" ; ) | ICASE()中最多能允许100个条件/结果参数对。
SYS(3092):输出到文件
这个新的SYS()函数要与SYS(3054)函数一起协同工作,你可以用SYS(3092)函数为SYS(3054)函数的输出指定一个文件名,于是结果将输出到这个指定文件中去。
以下示例解释了如何将这两个函数结合使用:
SYS(3054,12,"dummyVar") SYS(3092,"ShowPlan.txt") OPEN DATABASE HOME(2)+"Northwind\Northwind" SELECT * ; FROM Customers INTO CURSOR temp1 SELECT * ; FROM summary_of_sales_by_year ; INTO CURSOR temp2 SYS(3092,"") CLOSE DATA ALL MODIFY FILE Showplan.txt NOWAIT | 如果你在SYS(3054)的第三个参数不指定具体的变量名,那结果将输出到当前的窗口中去。
新的数据类型
为了更好地与SQL Server兼容,Visual FoxPro 9增加了三个新数据类型:VarChar、VarBinary和BLOB。这些数据类型可以在本地数据库中作为字段类型,也可由CAST()函数创建或者由远程数据取得。
VarChar
它是一种字符型数据类型,但不像普通字符串那样长度不够的时候会以空格被补齐,而是将其截取。这有点类似于SQL Server中的SET ANSI_PADDING ON命令。如果VarChar中本身有空格的话则不会被截取。假如在一个表达式中将VarChar和Character两种数据类型混合计算,那结果会是VarChar类型。
VarChar在Visual FoxPro中是一个定长域,它的最大长度限定为255个字符。但在SQL Server中,一个VarChar域的最大长度可以达到8060字节。
VarBinary
VarBinary与VarChar有些类似,如果没有达到最大长度的话,多余的域不会被填充,而是被截取。但它们的本质区别在于FoxPro不会为VarBinary类型作任何代码页的转换。以下是这两种数据类型的比较:
BLOB
BLOB数据类型没有固定的长度限制,与Memo类型有些相似。它被存储在以.FPT结尾的文件中,被.DBF文件引用。BLOB字段与Memo字段有相同的限定条件,并且他们都不支持索引。
与VarBinary数据类型一样,Visual FoxPro 9不会将BLOB类型作代码页转换,而是保持它原始的二进制格式。
BLOB数据类型的设计意图旨在取代最初的Gerneral字段。如果图形或者其它一些媒体类型以BLOB的格式存储,可用Image控件的PictureVal属性对它们进行浏览。
MEMO与BLOB类型的数据不能直接修改,如果直接修改的话,那只会显示它们的16进制的映像。
在以前的版本中,Visual FoxPro在建表语句CREATE TABLE创建字段类型时,一般用字段名称的第一个字母来取代。但随着数据类型的增多,像Character和Currency这两种字段类型如果采用第一个字母的简写方式的话会导致同名冲突。现在的版本可以同时支持字段类型的全称、全称的简写、第一个大写字母等多种方式,表1列出了所有的数据类型。
表1: 下面是FoxPro所有的数据类型的全称和字母缩写。
数据类型 |
全称 |
字母缩写 |
Character |
Char, Character |
C |
Date |
Date |
D |
DateTime |
Datetime |
T |
Numeric |
Num, Number |
N |
Floating |
Float |
F |
Integer |
Int, Integer |
I |
Double |
Double |
B |
Currency |
Currency |
Y |
Logical |
Logical |
L |
Memo |
Memo |
M |
General |
General |
G |
Picture |
Picture |
P |
VarChar |
Varchar |
V |
VarBinary |
Varbinary |
Q |
BLOB |
Blob |
W | 与新引进的二进制索引一样,如果要使用新版本中的数据类型,那你必须升级到Visual FoxPro 9。否则就不能使用这些新的数据类型。
远程数据
Visual FoxPro以前的版本对远程数据有很强大的支持,但新版本中为操作及取得远程数据提供了更强大的控制功能。
事务和连接
一个名为DisconnectRoolBack的新属性被加入到了新版本,当事务处于挂起状态或连接断开时可以用它来将事务回滚。SQLSetProp、SQLGetProp、DBSetProp和DBGetProp函数都支持这个新属性。
SQLIdleDisconnect()是一个新增加的函数,它可用来临时地终断一个连接。在大多数情况下,它通过一个IdleTimeOut的属性来控制连接超时的时间。但在多线程运行环境中是不允许线程处于空闲状态的,在这种情况下调用此函数将真正释放这个连接。
游标处理
通过调用CursorGetProp()函数可以取得两个新的属性:RecordsFetched和FetchlsComplete。这些属性能让你知道目前已经处理了多少条记录,以及什么时候可以将所有的记录处理完。
RecordsFetched的值不会影响游标中的记录数目。并且如果在查询中设置了过滤表达式的话,那么过滤表达示将会被忽略掉。 如果你想在查询或更新的SQL语句中知道实际处理记录的数目,那可以调用SQLEXEC()和SQLMORERSULTS()函数,并通过一个名为aCountInfo的二维数组作为它们的参数,当函数调用后,此二维数组将包含表别名以及实际处理记录的数目。
对CursorAdapter和XMLAdapter的增强
关于对CursorAdapter和XMLAdapter的增强足以用长篇大论来描述。但限于篇幅,我们只描述一些显著增强功能。
CursorAdapter作了很多的改动,使得它现在看上去像一个远程视图。这些增强如下:
· 支持时间戳域。这允许UPDATE或DELETE语句可以在WHERE条件中以时间戳作为条件进行数据更新。
· 支持自动更新。这项特性可以使得当使用INSERT或UPDATE进行远程数据更新时,CursorAdapter能够自动地刷新。当你使用自动序号字段、缺省字段或时间戳时这项特性变得非常有用。
· 根据你的需要进行记录刷新。CursorAdapter中添加了一些新的属性和事件使得你能及时地刷新本地或远程视图,其功能与REFRESH()类似。
此外,CursorAdapter还增加了一些属性用来支持DEFAULT和CHECK约束,并且可以将远程数据映射到新的VarChar和VarBinary数据类型上。
XMLAdapter作了如下改进:
· 层次型XML结构支持
· XPath表达式支持
· XML编码与解码的增强
最后结论
在本文中,你已经领略到了新版本数据引擎发生的本质改变。同时新版本还兼顾了向后兼容性,以及提供了方便的升级步骤,使得从版本8升级到版本9对用户而言是一个透明的过程。只要你升级到了版本9,你就能享受到这种巨大的优越性,并且无需改变你的原有代码。它让你的程序建立在一个强兼容性、强大功能以及高可维护性的基础之上。
|
|
|
文章录入:杜斌 责任编辑:杜斌 |
|
上一篇文章: VFP表跟踪日志的实现方法 下一篇文章: 数据库应用程序需注意的问题 |
【字体:小 大】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口】 |
|
|