用SPL進(jìn)行關(guān)聯(lián),當(dāng)維表不大時(shí)可以讀入內(nèi)存。
10年積累的成都網(wǎng)站制作、成都做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有隴縣免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。如果維表是單字段主鍵,可以使用switch做連接。例如有訂單、客戶、雇員三個(gè)表存儲(chǔ)在集文件中,表結(jié)構(gòu)如下:
Order | Customer | Employee |
orderID | customerID | employeeID |
customerID | name | name |
employeeID | City | title |
…… | …… | country |
…… | ||
現(xiàn)在把訂單表和客戶表、雇員表進(jìn)行關(guān)聯(lián):
A | |
1 | =file("order.btx").cursor@b() |
2 | =file("customer.btx").import@b() |
3 | =file("employee.btx").import@b() |
4 | =A1.switch(customerID,A2: ? customerID;employeeID,A3: employeeID) |
5 | =A4.new(orderID, ? customerID.name, employeeID.name:name) |
A1:訂單表數(shù)據(jù)很多,所以用游標(biāo)。
A2:客戶表數(shù)據(jù)少,全部裝入內(nèi)存,并且建立索引。
A3:同理雇員表也做維表內(nèi)存化。
A4:用switch做關(guān)聯(lián),根據(jù)客戶ID字段關(guān)聯(lián)訂單表和客戶表,以及根據(jù)employeeID字段關(guān)聯(lián)訂單表和雇員表。
從A4可以看到,switch可以一次處理多個(gè)關(guān)聯(lián)計(jì)算。
當(dāng)維表的主鍵是序號(hào)時(shí)還可以用序號(hào)定位。
A | |
1 | =file("order.btx").cursor@b() |
2 | =file("customer.btx").import@b().index() |
3 | =file("employee.btx").import@b() |
4 | =A1.switch(customerID,A2: ? customerID; employeeID D,A3:#) |
5 | =A4.new(orderID, ? customerID.name, employeeID.name:name) |
A5:雇員表的employeeID字段是從1開始的自然數(shù),所以可以做外鍵序號(hào)化。
如果維表的主鍵不是序號(hào)值,就無法直接使用外鍵序號(hào)化進(jìn)行性能優(yōu)化。比如customerID字段的值就是由字母構(gòu)成的。這時(shí),可以把維表的主鍵轉(zhuǎn)換成序號(hào)后再使用外鍵序號(hào)化。
首先把客戶表的客戶ID轉(zhuǎn)換為序號(hào):
A | |
1 | =file("customer.btx").import@b() |
2 | =A1.derive(#:newCustomerID) |
3 | =file("newAndOldCustomerID.btx").export@b(A2, ? newCustomerID, customerID) |
4 | =file("newCustomer.btx").export@b(A2, ? newCustomerID: customerID, name,city) |
序號(hào)化后的客戶保存到了集文件newCustomer.btx中。其中newAndOldCustomerID.btx里保存的是新舊客戶ID的對(duì)應(yīng)關(guān)系。
然后再把訂單表的customerID進(jìn)行序號(hào)化:
A | |
1 | =file("newAndOldCustomerID.btx").import@b() |
2 | =file("order.btx").cursor@b() |
3 | =A2.switch(customerID,A1: ? customerID) |
4 | =A3.run(customerID. ? newCustomerID: customerID) |
5 | =file("newOrder.btx").export@ba(A4) |
序號(hào)化后的訂單保存到了集文件訂單.btx中。
這時(shí)對(duì)于customerID字段,也可以通過序號(hào)化進(jìn)行連接了。
A | |
1 | =connect("demo") |
2 | =file("newOrder.btx").cursor@b() |
3 | =file("newCustomer.btx").import@b() |
4 | =file("employee.btx").import@b() |
5 | =A2.switch(customerID,A3:#; ? employeeID,A4:#) |
6 | =A5.new(orderID, ? customerID.name,employeeID.name:name) |
當(dāng)維表的主鍵是多個(gè)字段的時(shí)候,要使用join做連接。例如有學(xué)生表(Students)和班級(jí)表(Classes),學(xué)生表的專業(yè)號(hào)和班級(jí)號(hào)為外鍵字段,分別指向班級(jí)表的聯(lián)合主鍵(專業(yè)號(hào),班級(jí)號(hào)),表結(jié)構(gòu)如下:
Student | Class |
studentId | majorId |
name | classId |
majorId | teacher |
classId |
現(xiàn)在要查詢學(xué)生的學(xué)號(hào)、姓名、專業(yè)、班級(jí)和班主任:
A | |
1 | =file("student.btx").import@b() |
2 | =file("class.btx").import@b().keys(majorId,classId) |
3 | =A1.join(majorId:classId,A2,teacher) |
A2:導(dǎo)入班級(jí)數(shù)據(jù),并且設(shè)置主鍵為majorId和classId;
A3:join() 函數(shù)進(jìn)行雙字段的主鍵關(guān)聯(lián),將班主任信息添加到學(xué)生信息中。
如果維表無法裝入內(nèi)存,而事實(shí)表可以裝入內(nèi)存,則可以使用joinx函數(shù)進(jìn)行關(guān)聯(lián)。此時(shí)維表要按主鍵有序存儲(chǔ),可分段集文件或組表均可,后者效率更高。
例如有退貨表、產(chǎn)品表兩個(gè)表存儲(chǔ)在集文件中,表結(jié)構(gòu)如下:
Returns | Product |
orderID | productID |
productID | name |
price | price |
quantity | category |
date | …… |
…… |
這里退貨表對(duì)關(guān)聯(lián)字段producID是無序的,產(chǎn)品表是按照producID字段有序的。計(jì)算目標(biāo)是獲得每一筆退貨記錄的產(chǎn)品類別,需要把退貨表和產(chǎn)品表做關(guān)聯(lián):
A | |
1 | =file("returns.btx").import@b() |
2 | =file("product.btx") |
3 | =A1.joinx@q(productID,A2:productID,categroy: ? categroy;) |
4 | =A3.fetch() |
A1:把退貨表裝入內(nèi)存;
A2:給出產(chǎn)品表的文件對(duì)象;
A3:使用joinx函數(shù)進(jìn)行關(guān)聯(lián)。
如果事實(shí)表對(duì)關(guān)聯(lián)字段也是有序的,就可以加上@c,進(jìn)一步提速。例如計(jì)算每一筆退貨記錄的客戶ID,就要把退貨表和訂單表做關(guān)聯(lián):
A | |
1 | =file("returns.btx").import@b() |
2 | =file("order.btx") |
3 | =A1.joinx@qc(orderID,A2:orderID,customerID: ? customerID;) |
4 | =A3.fetch() |
實(shí)際上,上面兩個(gè)例子可以一次完成:
A | |
1 | =file("returns.btx").import@b() |
2 | =file("order.btx") |
3 | =file("product.btx") |
4 | =A1.joinx@qc(orderID,A2:orderID,customerID:customerID; ? productID,A3:productID,category: category;) |
5 | =A4.fetch() |
A4:做了兩次關(guān)聯(lián),退貨表表先跟訂單表關(guān)聯(lián),得到的結(jié)果再跟產(chǎn)品表做關(guān)聯(lián)。這里退貨表對(duì)關(guān)聯(lián)字段orderID是有序的,所以可以加@c,但要寫在最前面。
對(duì)于事實(shí)表無法裝入內(nèi)存的情況,可以使用游標(biāo)。例如有訂單明細(xì)的表結(jié)構(gòu)如下:
orderDetails |
orderID |
productID |
price |
quantity |
date |
…… |
訂單明細(xì)保存在組表里,現(xiàn)在要計(jì)算某個(gè)月銷售的產(chǎn)品的種類情況,需要把訂單明細(xì)表的單月數(shù)據(jù)和產(chǎn)品表進(jìn)行關(guān)聯(lián),:
A | |
1 | =file("orderDetails.ctx").create().cursor(;year(date)==2018&& ? month(date)==11) |
2 | =file("product.btx") |
3 | =A1.joinx@q(productID,A2:productID,categroy: ? categroy;) |
4 | =A3.fetch() |
A1:2018年11月的訂單明細(xì)仍然無法裝入內(nèi)存,使用游標(biāo)訪問。
A2:給出產(chǎn)品表的文件對(duì)象;
A3:使用joinx函數(shù)進(jìn)行關(guān)聯(lián)。
joinx支持事實(shí)表是游標(biāo)的情況,但不宜太大,否則效率就會(huì)比較低了。
對(duì)于按主鍵有序存儲(chǔ)的主子表可以使用joinx實(shí)現(xiàn)有序歸并連接。訂單表、訂單明細(xì)表已經(jīng)是對(duì)訂單ID字段有序的,計(jì)算每個(gè)客戶的總消費(fèi)額:
A | |
1 | =file("order.btx").cursor@b() |
2 | =file("orderDetail.btx").cursor@b() |
3 | =joinx(A1:order,orderID;A2: detail,orderID) |
4 | =A3.groups(order.customerID:customerID;sum(detail.price*detail.quantity):amount ? ) |
有序歸并還可以和游標(biāo)外鍵一起使用,例如計(jì)算消費(fèi)總金額大于1000的客戶名:
A | |
1 | =file("order.btx").cursor@b() |
2 | =file("orderDetail.btx").cursor@b() |
3 | =file("customer.btx").import@b() |
4 | =A1.switch@i(customerID, A3: customerID) |
5 | =joinx(A4:order,orderID;A2:detail,orderID) |
6 | =A5.groups(order.customerID.name:customer; sum(detail.price*detail.quantity):amount ? ).select(amount>100000) |
如果主子表不是按住鍵有序時(shí)則要事先排序才能使用這種方法。
對(duì)于同維的主子組表,可以并行進(jìn)行關(guān)聯(lián)。例如訂單和訂單明細(xì)這兩個(gè)組表,分段字段都是訂單ID。計(jì)算消費(fèi)總金額大于1000的客戶名,仍然使用joinx進(jìn)行關(guān)聯(lián):
A | |
1 | =file("order.ctx").create().cursor@m(;;4) |
2 | =file("orderDetail.ctx").create().cursor(;;A1) |
3 | =joinx(A1:order,orderID;A2:detail ,orderID) |
4 | =A3.groups(order.customerID:customer; ? sum(detail.price*detail.quantity):amount).select(amount>100000) |
A1:得到訂單的多路游標(biāo),這里使用的游標(biāo)路數(shù)是4。
A2:根據(jù)多路游標(biāo)A1的值,得到訂單明細(xì)的多路游標(biāo),游標(biāo)路數(shù)也是4。
實(shí)際測(cè)試的結(jié)果表明,使用4線程并行后速度快了大約2.5倍。
需要注意的是,分段字段要在產(chǎn)生組表時(shí)就指定:
A | |
1 | =file("order.ctx").create(#orderID,customerID,employeeID;orderID) |
2 | =file("orderDetail.ctx").create(#orderID,productID,price,quantity,date;orderID) |
這樣追加的數(shù)據(jù)會(huì)按orderID字段分段,不會(huì)把orderID同值的記錄分到兩段中。
組表支持主子表保存在同一文件中,合一后取出關(guān)聯(lián)數(shù)據(jù)的性能會(huì)更高。例如可以把訂單作為主表保存到組表文件order.ctx,再在主表上創(chuàng)建一個(gè)附表,命名為detail,把訂單明細(xì)保存到這個(gè)附表上,這時(shí)再計(jì)算消費(fèi)總金額大于1000的客戶名,就是這樣:
A | |
1 | =file("order.ctx").create().attach(detail) |
2 | =A1.cursor(orderID,customerID,price,quantity) |
3 | =A2.groups(customerID:customer; sum(price*quantity):amount).select(amount>100000) |
A1:打開附表訂單明細(xì);
A2:建立附表游標(biāo);
A3:進(jìn)行分組,并計(jì)算消費(fèi)總額。
這種方式也支持并行,只要把A2稍微修改就可以:
A | |
1 | =file("order.ctx").create().attach(detail) |
2 | =A1.cursor@m(orderID,customerID,price,quantity;;4) |
3 | =A2.groups(customerID:customer; sum(price*quantity):amount).select(amount>100000) |
A2:建立附表的多路游標(biāo),路數(shù)為4;
根據(jù)實(shí)際測(cè)試的結(jié)果,使用附表比使用joinx更快。主子表是1:N的關(guān)系,當(dāng)N越大時(shí),讀取速度的提升就越大;當(dāng)主表的主鍵是多字段時(shí),讀取速度提升的越明顯。
當(dāng)訂單是1億條,每條對(duì)應(yīng)大約10條訂單明細(xì)時(shí),本案例實(shí)際測(cè)試結(jié)果:
耗時(shí)(秒) | ||
2 個(gè)組表 joinx | 組表合一 | 組表合一并行(4 線程) |
781 | 602 | 368 |
使用主子表合一后,不僅有速度上的優(yōu)化,在空間上也更小了,合一后的組表比兩個(gè)組表要節(jié)省20%左右的硬盤空間。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。