SPL的特征之一是數(shù)據(jù)有序,適當(dāng)?shù)乩梦恢茫梢燥@著提高性能。讓我們先從一個(gè)典型場(chǎng)景開(kāi)始,逐步掌握利用位置的各種技巧。
創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比隴縣網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式隴縣網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋隴縣地區(qū)。費(fèi)用合理售后完善,10余年實(shí)體公司更值得信賴。
對(duì)排序后的數(shù)據(jù)進(jìn)行二分查找,可以獲得較高的性能,但有些算法需用到原始順序,看上去似乎不該再排序。比如下面的案例:
PerformanceRanking.txt有三個(gè)字段,分別是empID(銷售員編號(hào))、dep(部門名稱)、amount(銷售額)。該文件記錄著各部門各銷售員本季度的業(yè)績(jī)排名,已按銷售額逆序存放,現(xiàn)在需根據(jù)指定的銷售員ID,計(jì)算出:他應(yīng)當(dāng)再增加多少銷售額,才能提高業(yè)績(jī)排名。如果該員工已經(jīng)是第1名,則無(wú)需增加銷售額。
本算法需要用排名高一位的銷售員的銷售額,減去該銷售員的銷售額,即對(duì)原始數(shù)據(jù)做相對(duì)位置計(jì)算。既然要用到原始順序,似乎就不該再排序,否則兩者難以互轉(zhuǎn),而且其他算法可能用到原始數(shù)據(jù)。這種思路下會(huì)把腳本寫成這樣:
A | B | |
1 | =file("PerformanceRanking.txt").import@t() | /讀取數(shù)據(jù) |
2 | =A1.pselect(empID:10) | /不利用位置,按empID查詢記錄序號(hào) |
3 | =A1.calc(A2,if(#>1,amount[-1]-amount,0)) | /在原始數(shù)據(jù)中做相對(duì)位置計(jì)算 |
上述腳本沒(méi)有對(duì)數(shù)據(jù)排序,所以不能進(jìn)行二分查找,性能不高。
事實(shí)上,我們可以在保留原始數(shù)據(jù)的前提下,利用位置進(jìn)行排序,從而提高查詢性能。腳本如下:
A | B | |
5 | =oPos=A1.psort(empID) | /排序后記錄在原數(shù)據(jù)中的位置 |
6 | =index=A1(oPos) | /利用位置制造排序數(shù)據(jù) |
7 | =oPos(index.pselect@b(empID: 10)) | /二分查找,獲得序號(hào) |
8 | =A1.calc(A7,if(#>1,amount[-1]-amount,0)) | /在原始數(shù)據(jù)中做相對(duì)位置計(jì)算 |
A5:函數(shù)psort只獲得排序后記錄在原數(shù)據(jù)中的位置,并不會(huì)對(duì)原數(shù)據(jù)真正排序。
A6:利用oPos制造一份排序后的數(shù)據(jù)。注意,此時(shí)原數(shù)據(jù)不受影響,而且oPos可以作為排序后數(shù)據(jù)index和原始數(shù)據(jù)之間互轉(zhuǎn)的橋梁。
A7:對(duì)排序后的數(shù)據(jù)做二分查找,并轉(zhuǎn)回原始數(shù)據(jù)中對(duì)應(yīng)的記錄序號(hào)。
為了驗(yàn)證利用位置之前、之后兩種算法的性能差別,可以隨機(jī)取出銷售員編號(hào)做參數(shù),用循環(huán)模擬大量訪問(wèn),并分別執(zhí)行兩種算法。如下:
A | B | |
10 | =100000.(A1(rand(A1.len())+1).empID) | /制造1萬(wàn)個(gè)empID |
11 | =now() | |
12 | for A10 | =A1.pselect(empID:A12) |
13 | =A1.calc(B12,if(#>1,amount[-1]-amount,0)) | |
14 | =interval@ms(A11,now()) | /不利用位置,耗時(shí):13552毫秒 |
15 | ||
16 | =now() | |
17 | for A10 | =oPos(index.pselect@b(empID: A17)) |
18 | =A1.calc(B17,if(#>1,amount[-1]-amount,0)) | |
19 | =interval@ms(A16,now()) | /利用位置,耗時(shí):165毫秒 |
可以看到,利用位置后性能提高幾十倍。例子中數(shù)據(jù)量較少,隨著數(shù)據(jù)量的增加,性能差距會(huì)急劇拉大,這是因?yàn)楸闅v查找的時(shí)間復(fù)雜度為線性,而二分查找為對(duì)數(shù)。
函數(shù)align可將數(shù)據(jù)按序列對(duì)齊,比如輸入條件:=pOrderList= [10250,10247,10248,10249,10251],將訂單明細(xì)按該列表對(duì)齊,求每個(gè)訂單的金額小計(jì)。代碼如下:
A | |
1 | =connect("demo").query@x("select orderID,productID,price,quantity from orderDetail") |
2 | =A1.align@a(pOrderList,orderID).new(orderID,~.sum(price * quantity):小計(jì)) |
但上述寫法沒(méi)有利用位置,性能因此不高。要想提高性能,可以將序列排序(手工建立索引表),再用二分法對(duì)齊,最后恢復(fù)為原順序,代碼如下:
A | |
1 | =connect("demo").query@x("select orderID,productID,price,quantity from orderDetail") |
2 | =oPos= pOrderList.psort() |
3 | =index= pOrderList (oPos) |
4 | =A1.align@ab(index,orderID).new(orderID,~.sum(price * quantity):total) |
5 | =A4.inv(oPos) |
A2-A3:手工建立索引表。
A4:將訂單明細(xì)表與訂單列表對(duì)齊,求出金額小計(jì)。由于索引表有序,因此可用二分法對(duì)齊,即@b選項(xiàng)。
A5:將A4按原位置調(diào)整,與pOrderList的順序保持一致。函數(shù)inv可按指定位置調(diào)整成員,這里按原位置調(diào)整成員,相當(dāng)于恢復(fù)成原位置。
對(duì)利用位置前后的兩種算法,模擬大訪問(wèn)量測(cè)試,可以看到性能提升顯著:
A | B | |
8 | =now() | |
9 | for A9 | =A1.align@a(A12,orderID).new(orderID,~.sum(price*quantity):total) |
10 | =interval@ms(A11,now()) | /不利用位置,耗時(shí)43456毫秒 |
11 | ||
12 | =now() | |
13 | for A9 | =oPos=A16.psort() |
14 | =index=A16(oPos) | |
15 | =A1.align@ab(index,orderID).new(orderID,~.sum(price*quantity):total) | |
16 | =B18.inv(oPos) | |
17 | =interval@ms(A15,now()) | /利用位置,耗時(shí)7313毫秒 |
18 | =now() | |
19 | for A9 | =A1.align@a(A12,orderID).new(orderID,~.sum(price*quantity):total) |
20 | =interval@ms(A11,now()) | /不利用位置,耗時(shí)43456毫秒 |
有時(shí)要對(duì)有序數(shù)據(jù)進(jìn)行批量查詢,比如pOrderList=[10877,10588,10611,11037,10685],請(qǐng)統(tǒng)計(jì)符合該列表的訂單的運(yùn)貨費(fèi)合計(jì),代碼可以這樣寫:
A | B | |
1 | =connect("demo").query@x("select orderID,customerID,orderDate,shippingCharge from order order by orderID") | |
2 | =pOrderList=[10877,10588,10611,11037,10685] | /列表參數(shù) |
3 | =A1.select(pOrderList.pos(OrderID)).sum(shippingCharge) | /不利用位置,單次代碼 |
解釋:函數(shù)pos和select配合,可實(shí)現(xiàn)批量查詢。其中函數(shù)pos可返回某個(gè)值在序列中的位置,如該值不在序列中,則返回null。函數(shù)select用于查詢,當(dāng)條件非null且非false時(shí),可返回當(dāng)前記錄。
但上述代碼沒(méi)有利用位置,所以性能不高。
應(yīng)當(dāng)注意到,訂單記錄是有序的,所以可以用二分法取得符合條件的訂單位置,再用位置取記錄并計(jì)算。具體代碼如下:
A | B | |
5 | =A1.(orderID).pos@b(pOrderList) | |
6 | =A1(A5).sum(shippingCharge) | /利用位置,單次代碼 |
A1.(orderID)可取得orderID列,pos@b可針對(duì)有序數(shù)據(jù),用二分法快速取得成員位置。A6按位置取數(shù)據(jù)。
對(duì)利用位置前后的兩種算法,模擬大訪問(wèn)量測(cè)試,可以看到性能提升顯著:
A | B | |
8 | =A1.(OrderID) | /性能測(cè)試準(zhǔn)備 |
9 | =100000.(A1.(OrderID).sort(rand()).to(rand(100))) | /隨機(jī)生成100000個(gè)列表 |
10 | ||
11 | =now() | |
12 | for A9 | =A1.select(A12.pos(OrderID)).sum(shippingCharge) |
13 | =interval@ms(A11,now()) | /不利用位置,85166毫秒 |
14 | ||
15 | =now() | |
16 | for A9 | =A1.(OrderID).pos@b(A16) |
17 | =A1(B16).sum(shippingCharge) | |
18 | =interval@ms(A15,now()) | /利用位置,3484毫秒 |
名稱欄目:性能優(yōu)化技巧-位置利用
標(biāo)題路徑:http://aaarwkj.com/article34/gjdpse.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司、建站公司、服務(wù)器托管、動(dòng)態(tài)網(wǎng)站、移動(dòng)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)