新的數(shù)據(jù)類型是如何影響 DBF 文件的
你也許會(huì)對VFP是如何在表中實(shí)現(xiàn)這些新的數(shù)據(jù)類型感興趣。DBF結(jié)構(gòu)并不允許可變長度的字段,因此事實(shí)上在DBF表里的 Varchar 和 Varbinary 字段其實(shí)是被填補(bǔ)上空格的。因此,Microsoft 已經(jīng)有了一種跟蹤 Varchar 和 Varbinary 字段的長度的機(jī)制,以保證當(dāng)需要的時(shí)候返回經(jīng)過正確的 Trim 的值。這里是它的工作方式:
× 在所有版本 VFP 的DBF表中,如果其中某個(gè)字段可以接受 Null 值,那么這個(gè)表都會(huì)被增加一個(gè)隱藏的字段,名叫 _NullFlags。該字段中包含一個(gè)位值(bit value),用于指示在一條指定記錄中的某個(gè)特定字段是否包含著一個(gè) Null。例如,如果在一條記錄中的第一個(gè)可接收 null 的字段中包含一個(gè) null,那么 _NullFlags 中的位0就被設(shè)置為1。如果第二個(gè)可接收 null 值的字段中包含一個(gè)非 null 值,那么 _NullFlags 中的位1就被設(shè)置0。由于一個(gè)字節(jié)中有8位,_NullFlag 中值的寬度為可接收 null 值字段的數(shù)量處以8。
× 在 VFP 9 中,_NullFlags 服務(wù)于兩個(gè)責(zé)任:它的位還指示在 Varchar 和 Varbinary 字段中的值是否將字段填滿了。如果一個(gè)位包含0,則在一個(gè)字段中值的長度等于該字段的長度(這個(gè)字段是滿的)。如果這個(gè)位包含1,則值的長度小于字段的長度,這種情況下字段根據(jù)需要會(huì)被用空格填補(bǔ),而且最后一位包含著字段的長度。例如,一個(gè)包含著“AB”這樣內(nèi)容的10位長度的Varchar 字段中,實(shí)際上包含的是“AB”后面跟上7個(gè)空格、再加上一個(gè) CHR(2)(2代表值的長度),同時(shí)在 _NullsFlags 中該字段的位為1。
×如果一個(gè)字段既可以接收 null 值又是 Varchar 或者 Varbinary 類型的,那么會(huì)用兩位來表示一個(gè)字段。低的那位代表“滿”狀態(tài)、而高的那位代表 null 狀態(tài)。例如,一個(gè)可接收 null 的10位Varchar字段中包含著“AB”,它在 _NullFlags 中就用 01 來代表(0意味著不為 null,1意味著不滿),而同一個(gè)字段中如果是一個(gè) null 值則用11來表示(null并且不滿)。
這里是一個(gè)示例,用于演示 _NullFlags 在用于可接收 null 的字符型(Field3)、不能為 null 的 Varchar(Field2)、可以為 null 的 Varchar 字段(Field4)的情況下的各種值。位0代表 Field2 的“滿”狀態(tài),位1包含著 Field3 的 null 狀態(tài),位2包含著Field4的“滿”狀態(tài),而位3包含著 Field4 的 null 狀態(tài)。這個(gè)示例使用 VFP 自帶的 HexEdit 工具來展示 DBF 文件中的 binary 內(nèi)容。滾動(dòng)到地址 000001C0 來察看表中這7條記錄的內(nèi)容。
create table TestVarchar (Field1 C(1), Field2 V(1), Field3 C(1) null, ; Field4 V(1) null) insert into TestVarchar values ('A', 'A', 'A', 'A') && Record 20 41 41 41 41, _NullFlags 00000000 = 00 insert into TestVarchar values ('A', '', 'A', 'A') && Record 20 41 00 41 41, _NullFlags 00000001 = 01 insert into TestVarchar values ('A', 'A', 'A', '') && Record 20 41 41 41 00, _NullFlags 00000100 = 04 insert into TestVarchar values ('A', 'A', .NULL., 'A') && Record 20 41 41 20 41, _NullFlags 00000010 = 02 insert into TestVarchar values ('A', 'A', 'A', .NULL.) && Record 20 41 41 41 00, _NullFlags 00001100 = 0C insert into TestVarchar values ('A', 'A', .NULL., .NULL.) && Record 20 41 41 20 00, _NullFlags 00001110 = 0E insert into TestVarchar values ('A', '', .NULL., .NULL.) && Record 20 41 00 20 00, _NullFlags 00001111 = 0F use do home() + 'Tools\HexEdit\HexEdit' with 'TestVarchar.dbf'
(在代碼的注釋中,在記錄中開頭的 20 表示該記錄沒有被刪除過,41 是字母“A”,00 指示在一個(gè) Varchar 字段中的值的長度為0字節(jié),因?yàn)樵撟侄螢榭栈蛘?null,而在一個(gè)字符型字段中的 20 是一個(gè)空格,指示該字段為空或者 null。)
Blob 字段不影響 DBF 文件的結(jié)構(gòu),因?yàn)樗鼈儠?huì)被使用跟通常的 Memo 字段一樣的格式儲(chǔ)存在一個(gè) FPT 文件中。狐社
DBF 的另一個(gè)改動(dòng):如果一個(gè)表中包含有這些新數(shù)據(jù)類型中的任何一種,指示表類型的第一個(gè)位中將包含著 0x32(decimal 類型的 50)(你可以使用 SYS(2029)來返回這個(gè)值)。結(jié)果,你就不能在過去版本的 VFP 中或者用 VFP ODBC 驅(qū)動(dòng)打開這個(gè)表。
Binary 索引
VFP 程序員經(jīng)常會(huì)建立一個(gè)基于 DELETED() 函數(shù)的索引。這個(gè) Tag 能得到 Rushmore 優(yōu)化,因?yàn)?VFP 不需要大量訪問磁盤來判定哪些記錄已經(jīng)被刪除了;它便于從索引中查找,看起來就好像從內(nèi)存的緩存中查找一樣(不過,在特定條件下,這樣的索引可能反而會(huì)拖慢 VFP的速度。詳情請見 Chris Probst 在 FoxPro Advisor 1999年五月刊上的文章。在 FoxPro Wiki 上也有幾個(gè)關(guān)于這個(gè)問題的主題;http://fox.wikis.com)。
由于建立在 DELETED() 或者別的邏輯表達(dá)式基礎(chǔ)上的索引只可能包含兩個(gè)值中的一個(gè)(.T.或者.F.),Microsoft 發(fā)現(xiàn)他們可以改變這樣的一個(gè)索引被存儲(chǔ)在 CDX 文件中的途徑,結(jié)果產(chǎn)生了更小同時(shí)更快速的索引。于是,VFP 9 就有了一種新的索引類型:binary。
為了建立一個(gè) binary 索引,請給 INDEX 命令添加 BINARY 關(guān)鍵字。例如:
index on DELETED() tag DELETED binary
這里是關(guān)于 binary 索引的一些細(xì)節(jié):
× Binary 索引可能會(huì)是一個(gè)比正常的索引小得多的、因此也就快得多的東西。TestBinaryIndex.PRG 建立了表,其中分別建立了基于 DELETED() 的一個(gè)普通的索引和一個(gè) binary 索引。binary 索引要比普通的那個(gè)快90%。
× Binary 索引的用途是 Rushmore 優(yōu)化。你不能在它們上面進(jìn)行 SEEK、也不能對它們進(jìn)行 SET ORDER。
× 邏輯表達(dá)式的運(yùn)算結(jié)果永遠(yuǎn)不能為 null 值,不管是在建立索引的時(shí)候、還是在以后使用這個(gè)表的時(shí)候,否則會(huì)出錯(cuò)。
× 你不能在 INDEX 命令中使用 FOR、ASCENDING、DESCENDING、UNIQUE、或者 CANDIDATE 子句,并且在建立一個(gè) binary 索引的時(shí)候不能建立一個(gè) IDX 索引文件。
× 按照 VFP 幫助(“Visual FoxPro Index Types”主題)的說法,VFP 根據(jù)返回記錄的數(shù)量是多余還是少于總記錄數(shù)量的 3%,為一個(gè) binary 索引建立的 Rushmore 優(yōu)化位圖會(huì)更快或者更慢??傊@個(gè)限制由幾個(gè)事實(shí)而決定,包括總的記錄數(shù)量。象許多情況一樣,你需要在實(shí)際條件下測試以判定 binary 索引將會(huì)對你的查詢產(chǎn)生什么樣的影響。另一個(gè) VFP 幫助主題“Index Based on Deleted Records”中有著關(guān)于 VFP 在各種條件下可以怎樣優(yōu)化的更多信息。
總結(jié)
給 VFP 9 新增加的數(shù)據(jù)類型可以使它比過去任何時(shí)候都輕松的與象 SQL Server 這樣的非本地?cái)?shù)據(jù)庫一起工作,同時(shí)也在本地表中使用它們也非常有用。如果你需要在 General 字段中存儲(chǔ)圖像的話,Blob 字段尤其有用。Binary 索引能夠增強(qiáng)你的 SQL SELECT 語句的性能,盡管 VFP 過去就已經(jīng)超速了。
你也許會(huì)對VFP是如何在表中實(shí)現(xiàn)這些新的數(shù)據(jù)類型感興趣。DBF結(jié)構(gòu)并不允許可變長度的字段,因此事實(shí)上在DBF表里的 Varchar 和 Varbinary 字段其實(shí)是被填補(bǔ)上空格的。因此,Microsoft 已經(jīng)有了一種跟蹤 Varchar 和 Varbinary 字段的長度的機(jī)制,以保證當(dāng)需要的時(shí)候返回經(jīng)過正確的 Trim 的值。這里是它的工作方式:
× 在所有版本 VFP 的DBF表中,如果其中某個(gè)字段可以接受 Null 值,那么這個(gè)表都會(huì)被增加一個(gè)隱藏的字段,名叫 _NullFlags。該字段中包含一個(gè)位值(bit value),用于指示在一條指定記錄中的某個(gè)特定字段是否包含著一個(gè) Null。例如,如果在一條記錄中的第一個(gè)可接收 null 的字段中包含一個(gè) null,那么 _NullFlags 中的位0就被設(shè)置為1。如果第二個(gè)可接收 null 值的字段中包含一個(gè)非 null 值,那么 _NullFlags 中的位1就被設(shè)置0。由于一個(gè)字節(jié)中有8位,_NullFlag 中值的寬度為可接收 null 值字段的數(shù)量處以8。
× 在 VFP 9 中,_NullFlags 服務(wù)于兩個(gè)責(zé)任:它的位還指示在 Varchar 和 Varbinary 字段中的值是否將字段填滿了。如果一個(gè)位包含0,則在一個(gè)字段中值的長度等于該字段的長度(這個(gè)字段是滿的)。如果這個(gè)位包含1,則值的長度小于字段的長度,這種情況下字段根據(jù)需要會(huì)被用空格填補(bǔ),而且最后一位包含著字段的長度。例如,一個(gè)包含著“AB”這樣內(nèi)容的10位長度的Varchar 字段中,實(shí)際上包含的是“AB”后面跟上7個(gè)空格、再加上一個(gè) CHR(2)(2代表值的長度),同時(shí)在 _NullsFlags 中該字段的位為1。
×如果一個(gè)字段既可以接收 null 值又是 Varchar 或者 Varbinary 類型的,那么會(huì)用兩位來表示一個(gè)字段。低的那位代表“滿”狀態(tài)、而高的那位代表 null 狀態(tài)。例如,一個(gè)可接收 null 的10位Varchar字段中包含著“AB”,它在 _NullFlags 中就用 01 來代表(0意味著不為 null,1意味著不滿),而同一個(gè)字段中如果是一個(gè) null 值則用11來表示(null并且不滿)。
這里是一個(gè)示例,用于演示 _NullFlags 在用于可接收 null 的字符型(Field3)、不能為 null 的 Varchar(Field2)、可以為 null 的 Varchar 字段(Field4)的情況下的各種值。位0代表 Field2 的“滿”狀態(tài),位1包含著 Field3 的 null 狀態(tài),位2包含著Field4的“滿”狀態(tài),而位3包含著 Field4 的 null 狀態(tài)。這個(gè)示例使用 VFP 自帶的 HexEdit 工具來展示 DBF 文件中的 binary 內(nèi)容。滾動(dòng)到地址 000001C0 來察看表中這7條記錄的內(nèi)容。
create table TestVarchar (Field1 C(1), Field2 V(1), Field3 C(1) null, ; Field4 V(1) null) insert into TestVarchar values ('A', 'A', 'A', 'A') && Record 20 41 41 41 41, _NullFlags 00000000 = 00 insert into TestVarchar values ('A', '', 'A', 'A') && Record 20 41 00 41 41, _NullFlags 00000001 = 01 insert into TestVarchar values ('A', 'A', 'A', '') && Record 20 41 41 41 00, _NullFlags 00000100 = 04 insert into TestVarchar values ('A', 'A', .NULL., 'A') && Record 20 41 41 20 41, _NullFlags 00000010 = 02 insert into TestVarchar values ('A', 'A', 'A', .NULL.) && Record 20 41 41 41 00, _NullFlags 00001100 = 0C insert into TestVarchar values ('A', 'A', .NULL., .NULL.) && Record 20 41 41 20 00, _NullFlags 00001110 = 0E insert into TestVarchar values ('A', '', .NULL., .NULL.) && Record 20 41 00 20 00, _NullFlags 00001111 = 0F use do home() + 'Tools\HexEdit\HexEdit' with 'TestVarchar.dbf'
(在代碼的注釋中,在記錄中開頭的 20 表示該記錄沒有被刪除過,41 是字母“A”,00 指示在一個(gè) Varchar 字段中的值的長度為0字節(jié),因?yàn)樵撟侄螢榭栈蛘?null,而在一個(gè)字符型字段中的 20 是一個(gè)空格,指示該字段為空或者 null。)
Blob 字段不影響 DBF 文件的結(jié)構(gòu),因?yàn)樗鼈儠?huì)被使用跟通常的 Memo 字段一樣的格式儲(chǔ)存在一個(gè) FPT 文件中。狐社
DBF 的另一個(gè)改動(dòng):如果一個(gè)表中包含有這些新數(shù)據(jù)類型中的任何一種,指示表類型的第一個(gè)位中將包含著 0x32(decimal 類型的 50)(你可以使用 SYS(2029)來返回這個(gè)值)。結(jié)果,你就不能在過去版本的 VFP 中或者用 VFP ODBC 驅(qū)動(dòng)打開這個(gè)表。
Binary 索引
VFP 程序員經(jīng)常會(huì)建立一個(gè)基于 DELETED() 函數(shù)的索引。這個(gè) Tag 能得到 Rushmore 優(yōu)化,因?yàn)?VFP 不需要大量訪問磁盤來判定哪些記錄已經(jīng)被刪除了;它便于從索引中查找,看起來就好像從內(nèi)存的緩存中查找一樣(不過,在特定條件下,這樣的索引可能反而會(huì)拖慢 VFP的速度。詳情請見 Chris Probst 在 FoxPro Advisor 1999年五月刊上的文章。在 FoxPro Wiki 上也有幾個(gè)關(guān)于這個(gè)問題的主題;http://fox.wikis.com)。
由于建立在 DELETED() 或者別的邏輯表達(dá)式基礎(chǔ)上的索引只可能包含兩個(gè)值中的一個(gè)(.T.或者.F.),Microsoft 發(fā)現(xiàn)他們可以改變這樣的一個(gè)索引被存儲(chǔ)在 CDX 文件中的途徑,結(jié)果產(chǎn)生了更小同時(shí)更快速的索引。于是,VFP 9 就有了一種新的索引類型:binary。
為了建立一個(gè) binary 索引,請給 INDEX 命令添加 BINARY 關(guān)鍵字。例如:
index on DELETED() tag DELETED binary
這里是關(guān)于 binary 索引的一些細(xì)節(jié):
× Binary 索引可能會(huì)是一個(gè)比正常的索引小得多的、因此也就快得多的東西。TestBinaryIndex.PRG 建立了表,其中分別建立了基于 DELETED() 的一個(gè)普通的索引和一個(gè) binary 索引。binary 索引要比普通的那個(gè)快90%。
× Binary 索引的用途是 Rushmore 優(yōu)化。你不能在它們上面進(jìn)行 SEEK、也不能對它們進(jìn)行 SET ORDER。
× 邏輯表達(dá)式的運(yùn)算結(jié)果永遠(yuǎn)不能為 null 值,不管是在建立索引的時(shí)候、還是在以后使用這個(gè)表的時(shí)候,否則會(huì)出錯(cuò)。
× 你不能在 INDEX 命令中使用 FOR、ASCENDING、DESCENDING、UNIQUE、或者 CANDIDATE 子句,并且在建立一個(gè) binary 索引的時(shí)候不能建立一個(gè) IDX 索引文件。
× 按照 VFP 幫助(“Visual FoxPro Index Types”主題)的說法,VFP 根據(jù)返回記錄的數(shù)量是多余還是少于總記錄數(shù)量的 3%,為一個(gè) binary 索引建立的 Rushmore 優(yōu)化位圖會(huì)更快或者更慢??傊@個(gè)限制由幾個(gè)事實(shí)而決定,包括總的記錄數(shù)量。象許多情況一樣,你需要在實(shí)際條件下測試以判定 binary 索引將會(huì)對你的查詢產(chǎn)生什么樣的影響。另一個(gè) VFP 幫助主題“Index Based on Deleted Records”中有著關(guān)于 VFP 在各種條件下可以怎樣優(yōu)化的更多信息。
總結(jié)
給 VFP 9 新增加的數(shù)據(jù)類型可以使它比過去任何時(shí)候都輕松的與象 SQL Server 這樣的非本地?cái)?shù)據(jù)庫一起工作,同時(shí)也在本地表中使用它們也非常有用。如果你需要在 General 字段中存儲(chǔ)圖像的話,Blob 字段尤其有用。Binary 索引能夠增強(qiáng)你的 SQL SELECT 語句的性能,盡管 VFP 過去就已經(jīng)超速了。