排號鍵是SPL獨特的數據類型,適合替代多層次、各層不連續的鍵值,比如×××號、合同編號、產品編號、組織機構代碼等。排號鍵定位速度快,常用于優化內存索引查詢和外鍵關聯計算。
cardNormal.btx是集文件格式的×××信息表,數據量一百萬條,字段為:cardNo(×××,主鍵),name(姓名),gender(性別),province(省份),email(電子郵件),mobile(移動電話),address(住址)。cardK.btx與cardNormal.btx在結構和數據上完全相同,唯一的區別在于cardNo字段是排號鍵。
本案例對cardNormal.btx和cardK.btx分別執行百萬次索引查詢,并比較兩者性能。
其中cardNo是簡化后的×××,格式如下:
位數 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
規則 | 行政區劃 | 生日 | 流水 | 校驗 | ||||||||||||
細則 | 省 | 地區 | 年 | 月 | 日 | 流水 | 校驗 | |||||||||
范例 | 1 | 0 | 0 | 3 | 1 | 9 | 8 | 0 | 1 | 2 | 1 | 3 | 0 | 2 | 3 | x |
省、地區:各自取值范圍為1-10。
生日:取值為"1980-06-01"至"1981-01-01"。
流水:取值為1-100。
校驗:根據前15位計算出的冗余校驗位,取值為0至10,其中10用x來表示。
將上述×××轉為排號鍵,可采取如下思路:
1. 省、地區:排號鍵的每一層只支持1-255的整數,因此將省和地區分別轉為整數,作為第1、2層排號鍵。
2. 生日:排號鍵以1為起始,可以取得更好的性能,因此算出原生日和1980-06-01的間隔天數,作為第3層排號鍵。
3. 流水:轉為整數,作為第4層的排號鍵。
4. 校驗位:冗余數據,可刪除。
具體轉換腳本如下:
k(int(mid(cardNo,1,2)), int(mid(cardNo,3,2)), interval("1980-06-01",date(mid(cardNo,5,8),"yyyyMMdd")), int(mid(cardNo,13,3)) ) |
下面對cardNormal.btx和cardK.btx分別執行百萬次索引查詢。
A | B | C | |
1 | =cardNormal=file("d:\\temp\\cardNormal.btx").import@b().keys(cardNo).index() | /將cardNormal.btx讀入內存 | |
2 | =paramList=cardNormal.(cardNo).sort(rand()).to(100000) | /隨機取1萬個××× | |
3 | |||
4 | =now() | ||
5 | for 100 | =paramList.(cardNormal.find(~)) | /查詢百萬次 |
6 | =interval@ms(A4,now()) | /字符串鍵性能:5537ms | |
7 | |||
8 | =cardK=file("d:\\temp\\cardk.btx").import@b().keys(cardNo).index@s() | /將cardk.btx讀入內存 | |
9 | =paramListK=paramList.(k(int(mid(~,1,2)), int(mid(~,3,2)), interval("1980-06-01",date(mid(~,5,8),"yyyyMMdd")), int(mid(~,13,3)) )) | /將字符串參數轉為排號鍵參數 | |
10 | =now() | ||
11 | for 100 | =paramListK.(cardK.find(~)) | /查詢百萬次 |
12 | =interval@ms(A10,now()) | /排號鍵性能:1977ms |
A8:對排號鍵建立內存哈希索引,需使用函數選項@s。
可以看到,對字符串鍵建立索引,查詢需耗費5547毫秒,而排號鍵只需1977毫秒,后者明顯快。
taxNormal.btx是集文件格式的報稅信息表,數據量一千萬條,字段為:serial(主鍵,流水號),cardNo(外鍵,×××),tax(報稅額),area(所屬地區),declaretype(申報類型),unit(申報單位),declareTime(申報時間),network(辦理網點)。taxK.btx 與taxNormal.btx在結構和數據上完全相同,唯一的區別在于cardNo字段是排號鍵。
本案例算法:
1. 對taxNormal.btx和cardNormal.btx進行外鍵關聯計算,排除操作系統緩存和硬盤IO的影響,只取關聯動作消耗的時間。
2. 對taxK.btx和cardK.btx進行外鍵關聯計算,排除操作系統緩存和硬盤IO的影響,只取關聯動作消耗的時間。
3. 比較1和2的差異。
具體算法如下:
A | B | C | |
1 | =file("d:\\temp\\taxNormal.btx").cursor@b() | for A1,10000 | /打開報稅表,預遍歷游標 |
2 | =A1.reset() | /重置游標到起點 | |
3 | =file("d:\\temp\\cardNormal.btx").import@b().keys(cardNo).index() | /打開×××表 | |
4 | =now() | ||
5 | for A1,10000 | /正式遍歷游標 | |
6 | =interval@ms(A4,now()) | =A1.reset() | /遍歷游標耗時3748ms |
7 | =A1.switch(cardNo,A3:cardNo) | for A1,10000 | /建立關聯,預遍歷游標 |
8 | =A1.reset() | /重置游標到起點 | |
9 | =now() | ||
10 | for A7,10000 | /正式遍歷關聯游標 | |
11 | =interval@ms(A9,now()) | =A11-A6 | / 建立關聯耗時:7553ms |
12 | /上面:字符串鍵關聯。下面:排號鍵關聯 | ||
13 | =file("d:\\temp\\taxK.btx").cursor@b() | for A13,10000 | /打開報稅表,預遍歷游標 |
14 | =A13.reset() | /重置游標到起點 | |
15 | =file("d:\\temp\\cardK.btx").import@b().keys(cardNo).index@s() | /打開×××表 | |
16 | =now() | ||
17 | for A13,10000 | /正式遍歷游標 | |
18 | =interval@ms(A16,now()) | =A13.reset() | /遍歷游標耗時2884ms |
19 | =A13.switch(cardNo,A15:cardNo) | for A19,10000 | /建立關聯,預遍歷游標 |
20 | =A19.reset() | /重置游標到起點 | |
21 | =now() | ||
22 | for A19,10000 | /正式遍歷關聯游標 | |
23 | =interval@ms(A21,now()) | =A23-A18 | /建立關聯耗時:966ms |
B2、B7、B13、B19:預遍歷游標,避免操作系統緩存的影響。遍歷之后需用reset函數重置游標,以便后續再次遍歷。
B11、B23:用總時間減去遍歷時間,獲得關聯動作消耗的時間。
可以看到,用普通鍵做外鍵關聯計算,其關聯動作耗時7553ms;排號鍵做外鍵關聯計算時,只需耗時966ms,后者明顯快。而且可以看出,使用排號鍵讀出記錄(fetch)的時間也少于使用字符串(其它字段和記錄行數都相同),說明排號鍵對象的生成性能更好。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。