溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SPL 關(guān)聯(lián)優(yōu)化技巧

發(fā)布時(shí)間:2020-07-30 02:24:25 來(lái)源:網(wǎng)絡(luò) 閱讀:135 作者:raqsoft 欄目:大數(shù)據(jù)

1.????????? 小維表

用SPL進(jìn)行關(guān)聯(lián),當(dāng)維表不大時(shí)可以讀入內(nèi)存。

1.1?????????? 單字段主鍵

如果維表是單字段主鍵,可以使用switch做連接。例如有訂單、客戶、雇員三個(gè)表存儲(chǔ)在集文件中,表結(jié)構(gòu)如下:

OrderCustomerEmployee
orderIDcustomerIDemployeeID
customerIDnamename
employeeIDCitytitle
…………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)值,就無(wú)法直接使用外鍵序號(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字段,也可以通過(guò)序號(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)

?

1.2?????????? 多字段主鍵

當(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)如下:

?

StudentClass
studentIdmajorId
nameclassId
majorIdteacher
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é)生信息中。

2.????????? 大維表

如果維表無(wú)法裝入內(nèi)存,而事實(shí)表可以裝入內(nèi)存,則可以使用joinx函數(shù)進(jìn)行關(guān)聯(lián)。此時(shí)維表要按主鍵有序存儲(chǔ),可分段集文件或組表均可,后者效率更高。

例如有退貨表、產(chǎn)品表兩個(gè)表存儲(chǔ)在集文件中,表結(jié)構(gòu)如下:

ReturnsProduct
orderIDproductID
productIDname
priceprice
quantitycategory
date……
……

這里退貨表對(duì)關(guān)聯(lián)字段producID是無(wú)序的,產(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í)表無(wú)法裝入內(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ì)仍然無(wú)法裝入內(nèi)存,使用游標(biāo)訪問。

A2:給出產(chǎn)品表的文件對(duì)象;

A3:使用joinx函數(shù)進(jìn)行關(guān)聯(lián)。

?

joinx支持事實(shí)表是游標(biāo)的情況,但不宜太大,否則效率就會(huì)比較低了。

3.????????? 同維主子表

對(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í)則要事先排序才能使用這種方法。

4.????????? 并行歸并

對(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同值的記錄分到兩段中。

5.????????? 主子表合一

組表支持主子表保存在同一文件中,合一后取出關(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 線程)
781602368

?

使用主子表合一后,不僅有速度上的優(yōu)化,在空間上也更小了,合一后的組表比兩個(gè)組表要節(jié)省20%左右的硬盤空間。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI