真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何用外部程序優(yōu)化SQL語(yǔ)句中的IN和EXISTS

數(shù)據(jù)結(jié)構(gòu)

IN 和 EXISTS 是 SQL 中常見(jiàn)的復(fù)雜條件,在將 SQL(存儲(chǔ)過(guò)程)轉(zhuǎn)換成庫(kù)外計(jì)算獲取高性能時(shí)也會(huì)面對(duì)這些問(wèn)題。本文將以 TPC-H 定義的模型為基礎(chǔ),介紹如何用集算器的語(yǔ)法實(shí)現(xiàn) IN、EXISTS 并做優(yōu)化。

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序設(shè)計(jì)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了博州免費(fèi)建站歡迎大家使用!

TPC-H 是 TPC 事務(wù)處理性能委員會(huì)制定的用于 OLAP 數(shù)據(jù)庫(kù)管理系統(tǒng)的測(cè)試標(biāo)準(zhǔn),模擬真實(shí)商業(yè)應(yīng)用環(huán)境,以評(píng)估商業(yè)分析中決策支持系統(tǒng)的性能。TPC-H 模型定義了 8 張表,表結(jié)構(gòu)和表關(guān)系如下圖:

如何用外部程序優(yōu)化SQL語(yǔ)句中的IN和EXISTS

IN 常數(shù)集合

SQL 示例(1):

select
      P_SIZE, P_TYPE, P_BRAND, count(1) as P_COUNT
from
      PART
where
      P_SIZE in (2, 3, 8, 15, 17, 25, 27, 28, 30, 38, 41, 44, 45)
      and P_TYPE in ('SMALL BRUSHED NICKEL', 'SMALL POLISHED STEEL')
      and P_BRAND not in ('Brand#12', 'Brand#13')
group by
      P_SIZE, P_TYPE, P_BRAND

優(yōu)化思路:

如果常數(shù)集合元素?cái)?shù)少于 3 個(gè)則可以翻譯成 (f == v1 || f == v2) 這種樣式,NOT IN 對(duì)應(yīng)的就是(f != v1 && f != v2)。較多的時(shí)候可以在外層把常數(shù)集合定義成序列,然后用 A.contain(f)來(lái)判斷字段是否在序列中,經(jīng)驗(yàn)表明元素個(gè)數(shù)超過(guò) 10 個(gè)時(shí)二分查找會(huì)明顯快于順序查找,如果要用二分查找則需要先把序列排序,然后用 A.contain@b(f)來(lái)進(jìn)行有序查找,NOT IN 對(duì)應(yīng)的就是! A.contain(f)。注意一定要把序列定義在循環(huán)函數(shù)外,否則會(huì)被多次執(zhí)行。

如果常數(shù)集合元素?cái)?shù)量特別多可以用連接過(guò)濾,具體請(qǐng)參照下圖代碼。

集算器實(shí)現(xiàn):


AB
1=[28, 30, 38,2, 3, 8, 15, 17, 25, 27,50 , 41, 44, 45].sort()/ 對(duì)常數(shù)集合進(jìn)行排序,這樣就可以用序列的有序查找,通常序列元素?cái)?shù)超過(guò) 13 個(gè)用有序查找會(huì)比遍歷快
2=file(PART).cursor@b(P_SIZE, P_TYPE, P_BRAND)/ 在 PART 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(A1.contain@b(P_SIZE)&& (P_TYPE == “SMALL BRUSHED NICKEL” || P_TYPE == “SMALL POLISHED STEEL”)&& (P_BRAND != “Brand#12” && P_BRAND != “Brand#13”))/ 對(duì)游標(biāo)附加過(guò)濾操作,注意常數(shù)序列要定義在過(guò)濾函數(shù)外面否則會(huì)被重復(fù)運(yùn)算
4=A3.groups(P_SIZE, P_TYPE, P_BRAND; count(1): P_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

如果 A1 的元素?cái)?shù)量特別多,則可以使用哈希連接的方法來(lái)過(guò)濾,把第 3 行代碼替換如下:

3=A2.select((P_TYPE == “SMALL BRUSHED NICKEL” || P_TYPE == “SMALL POLISHED STEEL”)&& (P_BRAND != “Brand#12” && P_BRAND != “Brand#13”)).join@i(P_SIZE, A1:~)// 對(duì)游標(biāo)附加過(guò)濾操作后再附加連接過(guò)濾操作

IN 子查詢

子查詢選出字段是主鍵

SQL 示例(2):
select
      PS_SUPPKEY, count(1) as S_COUNT
from
      PARTSUPP
where
      PS_PARTKEY in (
            select
                  P_PARTKEY
            from
                  PART
            where
                  P_NAME like 'bisque%%'
      )
group by
      PS_SUPPKEY

優(yōu)化思路:

子查詢過(guò)濾后讀入內(nèi)存,然后外層表與先讀入的內(nèi)存表(子查詢)做哈希連接進(jìn)行過(guò)濾。集算器提供了 switch@i()、join@i() 兩個(gè)函數(shù)用來(lái)做哈希連接過(guò)濾,switch 是外鍵式連接,用來(lái)把外鍵字段變成指引字段,這樣就可以通過(guò)外鍵字段直接引用指向表的字段,join 函數(shù)不會(huì)改變外鍵字段的值,可用于只過(guò)濾。

集算器實(shí)現(xiàn):

AB
1=file(PART).cursor@b(P_PARTKEY, P_NAME)/ 在 PART 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
2=A1.select(like(P_NAME, “bisque*”)).fetch()/ 對(duì)游標(biāo)附加過(guò)濾操作并取數(shù)
3=file(PARTSUPP).cursor@b(PS_SUPPKEY, PS_PARTKEY)/ 在 PARTSUPP 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
4=A3.join@i(PS_PARTKEY, A2:P_PARTKEY)/ 對(duì) PARTSUPP 游標(biāo)進(jìn)行連接過(guò)濾,@i 選項(xiàng)表示內(nèi)連接
5=A4.groups(PS_SUPPKEY; count(1):S_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

子查詢選出字段不是主鍵

SQL 示例(3):
select
      O_ORDERPRIORITY, count(*) as O_COUNT      
from
      ORDERS
where
      O_ORDERDATE >= date '1995-10-01'
      and O_ORDERDATE < date '1995-10-01' + interval '3' month
      and O_ORDERKEY in (
            select
                  L_ORDERKEY
            from
                  LINEITEM
            where
                  L_COMMITDATE< L_RECEIPTDATE
      )

group by
      O_ORDERPRIORITY

優(yōu)化思路:

子查詢過(guò)濾后按關(guān)聯(lián)字段去重讀入內(nèi)存,然后就變成類似于主鍵的情況了,可以繼續(xù)用上面說(shuō)的 switch@i()、join@i() 兩個(gè)函數(shù)用來(lái)做哈希連接過(guò)濾。

集算器實(shí)現(xiàn):

AB
11995-10-01=after@m(A1,3)
2=file(LINEITEM).cursor@b(L_ORDERKEY,L_COMMITDATE,L_RECEIPTDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(L_COMMITDATE < L_RECEIPTDATE)/ 對(duì)游標(biāo)附加過(guò)濾操作
4=A3.groups(L_ORDERKEY)/ 用 groups 對(duì) L_ORDERKEY 去重
5=file(ORDERS).cursor@b(O_ORDERKEY,O_ORDERDATE,O_ORDERPRIORITY)/ 在 ORDER 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
6=A5.select(O_ORDERDATE>=A1 && O_ORDERDATE < B1)/ 對(duì)游標(biāo)附加過(guò)濾操作
7=A6.join@i(O_ORDERKEY, A4:L_ORDERKEY)/ 對(duì) ORDERS 游標(biāo)進(jìn)行連接過(guò)濾,@i 選項(xiàng)表示內(nèi)連接
8=A7.groups(O_ORDERPRIORITY; count(1):O_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

子查詢結(jié)果集內(nèi)存放不下

SQL 示例(3):
select
      O_ORDERPRIORITY, count(*) as O_COUNT
from
      ORDERS
where
      O_ORDERDATE >= date '1995-10-01'
      and O_ORDERDATE < date '1995-10-01' + interval '3' month
      and O_ORDERKEY in (
            select
                  L_ORDERKEY
            from
                  LINEITEM
            where
                  L_COMMITDATE< L_RECEIPTDATE
      )

group by
      O_ORDERPRIORITY

優(yōu)化思路:

IN 子查詢相當(dāng)于對(duì)子查詢結(jié)果集去重然后跟外層表做內(nèi)連接,而做連接效率較好的就是哈希連接和有序歸并連接,所以這個(gè)問(wèn)題就變成了怎么把 IN 翻譯成高效的連接,下面我們來(lái)分析在不同的數(shù)據(jù)分布下如何把 IN 轉(zhuǎn)成連接。

(1) 外層表數(shù)據(jù)量比較小可以裝入內(nèi)存:

先讀入外層表,如果外層表關(guān)聯(lián)字段不是邏輯主鍵則去重,再拿上一步算出來(lái)的關(guān)聯(lián)字段的值對(duì)子查詢做哈希連接過(guò)濾,最后拿算出來(lái)的子查詢關(guān)聯(lián)字段的值對(duì)外層表做哈希連接過(guò)濾。

(2) 外層表和內(nèi)層表按關(guān)聯(lián)字段有序:

此時(shí)可以利用函數(shù) joinx() 來(lái)做有序游標(biāo)的歸并連接,如果內(nèi)層表關(guān)聯(lián)字段不是邏輯主鍵則需要先去重。此例中的 ORDERS 表和 LINEITEM 表是按照 ORDERKEY 同序存放,可以利用此方法來(lái)做優(yōu)化。

(3) 內(nèi)層表是大維表并且按主鍵有序存放:

集算器提供了針對(duì)有序大維表文件做連接的函數(shù) A.joinx,其它方法跟內(nèi)存能放下時(shí)的處理類似在此不再描述。

集算器實(shí)現(xiàn)(1):

AB
11995-10-01=after@m(A1,3)
2=file(ORDERS).cursor@b(O_ORDERKEY,O_ORDERDATE,O_ORDERPRIORITY)/ 在 ORDER 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(O_ORDERDATE>=A1 && O_ORDERDATE < B1).fetch()/ 對(duì)游標(biāo)附加過(guò)濾操作并取數(shù)
4=file(LINEITEM).cursor@b(L_ORDERKEY,L_COMMITDATE,L_RECEIPTDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
5=A4.select(L_COMMITDATE < L_RECEIPTDATE).join@i(L_ORDERKEY,A3:O_ORDERKEY)/ 對(duì)游標(biāo)附加過(guò)濾操作和鏈接過(guò)濾操作
6=A5.groups(L_ORDERKEY)/ 對(duì) L_ORDERKEY 去重
7=A3.join@i(O_ORDERKEY, A6:L_ORDERKEY)/ 對(duì)排列執(zhí)行鏈接過(guò)濾操作
8=A7.groups(O_ORDERPRIORITY;count(1):O_COUNT)/ 對(duì)排列計(jì)算分組得到最終結(jié)果
集算器實(shí)現(xiàn)(2):

AB
11995-10-01=after@m(A1,3)
2=file(ORDERS).cursor@b(O_ORDERKEY,O_ORDERDATE,O_ORDERPRIORITY)/ 在 ORDER 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(O_ORDERDATE>=A1 && O_ORDERDATE < B1)/ 對(duì)游標(biāo)附加過(guò)濾操作
4=file(LINEITEM).cursor@b(L_ORDERKEY,L_COMMITDATE,L_RECEIPTDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
5=A4.select(L_COMMITDATE < L_RECEIPTDATE)/ 對(duì)游標(biāo)附加過(guò)濾操作
6=A5.group@1(L_ORDERKEY)/ 按 L_ORDERKEY 去重
7=joinx(A3:ORDER, O_ORDERKEY; A6, L_ORDERKEY)/ 對(duì)有序游標(biāo)執(zhí)行內(nèi)連接
8=A7.groups(ORDER.O_ORDERPRIORITY:O_ORDERPRIORITY;count(1):O_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

EXISTS 等值條件

此章節(jié)的優(yōu)化思路和 IN 子查詢的優(yōu)化思路是相同的,事實(shí)上這種 EXISTS 也都可以用 IN 寫出來(lái)(或者倒過(guò)來(lái),把 IN 用 EXISTS 寫出來(lái))。

子查詢關(guān)聯(lián)字段是主鍵

SQL 示例(4):
select
      PS_SUPPKEY, count(1) as S_COUNT
from
      PARTSUPP
where
      exists (
            select
                  *
            from
                  PART
            where
                  P_PARTKEY = PS_PARTKEY
                  and P_NAME like 'bisque%%'
      )

group by
      PS_SUPPKEY

優(yōu)化思路:

子查詢過(guò)濾后讀入內(nèi)存,然后外層表與先讀入的內(nèi)存表(子查詢)做哈希連接進(jìn)行過(guò)濾。集算器提供了 switch@i()、join@i() 兩個(gè)函數(shù)用來(lái)做哈希連接過(guò)濾,switch 是外鍵式連接,用來(lái)把外鍵字段變成指引字段,這樣就可以通過(guò)外鍵字段直接引用指向表的字段,join 函數(shù)不會(huì)改變外鍵字段的值,可用于只過(guò)濾。

集算器實(shí)現(xiàn):

AB
1=file(PART).cursor@b(P_PARTKEY, P_NAME)/ 在 PART 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
2=A1.select(like(P_NAME, “bisque*”)).fetch()/ 對(duì)游標(biāo)附加過(guò)濾操作并取數(shù)
3=file(PARTSUPP).cursor@b(PS_SUPPKEY, PS_PARTKEY)/ 在 PARTSUPP 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
4=A3.join@i(PS_PARTKEY, A2:P_PARTKEY)/ 對(duì) PARTSUPP 游標(biāo)進(jìn)行連接過(guò)濾,@i 選項(xiàng)表示內(nèi)連接
5=A4.groups(PS_SUPPKEY; count(1):S_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

子查詢關(guān)聯(lián)字段不是主鍵

SQL 示例(5):
select
      O_ORDERPRIORITY, count(*) as O_COUNT
from
      ORDERS
where
      O_ORDERDATE >= date '1995-10-01'
      and O_ORDERDATE < date '1995-10-01' + interval '3' month
      and exists (
            select
                  *
            from
                  LINEITEM
            where
                  L_ORDERKEY = O_ORDERKEY
                  and L_COMMITDATE < L_RECEIPTDATE
            )

group by
      O_ORDERPRIORITY

優(yōu)化思路:

子查詢過(guò)濾后按關(guān)聯(lián)字段去重讀入內(nèi)存,然后就變成類似于主鍵的情況了,可以繼續(xù)用上面說(shuō)的 switch@i()、join@i() 兩個(gè)函數(shù)用來(lái)做哈希連接過(guò)濾。

集算器實(shí)現(xiàn):

AB
11995-10-01=after@m(A1,3)
2=file(LINEITEM).cursor@b(L_ORDERKEY,L_COMMITDATE,L_RECEIPTDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(L_COMMITDATE < L_RECEIPTDATE)/ 對(duì)游標(biāo)附加過(guò)濾操作
4=A3.groups(L_ORDERKEY)/ 對(duì) L_ORDERKEY 去重
5=file(ORDERS).cursor@b(O_ORDERKEY,O_ORDERDATE,O_ORDERPRIORITY)/ 在 ORDER 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
6=A5.select(O_ORDERDATE>=A1 && O_ORDERDATE < B1)/ 對(duì)游標(biāo)附加過(guò)濾操作
7=A6.join@i(O_ORDERKEY, A4:L_ORDERKEY)/ 對(duì) ORDERS 游標(biāo)進(jìn)行連接過(guò)濾,@i 選項(xiàng)表示內(nèi)連接
8=A7.groups(O_ORDERPRIORITY; count(1):O_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

子查詢結(jié)果集內(nèi)存放不下

SQL 示例(5):
select
      O_ORDERPRIORITY, count(*) as O_COUNT
from
      ORDERS
where
      O_ORDERDATE >= date '1995-10-01'
      and O_ORDERDATE < date '1995-10-01' + interval '3' month
      and exists (
            select
                  *
            from
                  LINEITEM
            where
                  L_ORDERKEY = O_ORDERKEY
                  and L_COMMITDATE < L_RECEIPTDATE
            )
group by
      O_ORDERPRIORITY

優(yōu)化思路:

等值 EXISTS 相當(dāng)于對(duì)內(nèi)部表關(guān)聯(lián)字段去重然后跟外層表做內(nèi)連接,而做連接效率較好的就是哈希連接和有序歸并連接,所以這個(gè)問(wèn)題就變成了怎么把 EXISTS 翻譯成高效的連接,下面我們來(lái)分析在不同的數(shù)據(jù)分布下如何把 EXISTS 轉(zhuǎn)成連接。

1、外層表數(shù)據(jù)量比較小可以裝入內(nèi)存:

先讀入外層表,如果外層表關(guān)聯(lián)字段不是邏輯主鍵則去重,再拿上一步算出來(lái)的關(guān)聯(lián)字段的值對(duì)子查詢做哈希連接過(guò)濾,最后拿算出來(lái)的子查詢關(guān)聯(lián)字段的值對(duì)外層表做哈希連接過(guò)濾。

2、外層表和內(nèi)層表按關(guān)聯(lián)字段有序:

此時(shí)可以利用函數(shù) joinx() 來(lái)做有序游標(biāo)的歸并連接,如果內(nèi)層表關(guān)聯(lián)字段不是邏輯主鍵則需要先去重。此例中的 ORDERS 表和 LINEITEM 表是按照 ORDERKEY 同序存放,可以利用此方法來(lái)做優(yōu)化。

3、內(nèi)層表是大維表并且按主鍵有序存放:

集算器提供了針對(duì)有序大維表文件做連接的函數(shù) A.joinx,其它方法跟內(nèi)存能放下時(shí)的處理類似在此不再描述。

集算器實(shí)現(xiàn)(1):

AB
11995-10-01=after@m(A1,3)
2=file(ORDERS).cursor@b(O_ORDERKEY,O_ORDERDATE,O_ORDERPRIORITY)/ 在 ORDER 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(O_ORDERDATE>=A1 && O_ORDERDATE < B1).fetch()/ 對(duì)游標(biāo)附加過(guò)濾操作并取數(shù)
4=file(LINEITEM).cursor@b(L_ORDERKEY,L_COMMITDATE,L_RECEIPTDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
5=A4.select(L_COMMITDATE < L_RECEIPTDATE).join@i(L_ORDERKEY,A3:O_ORDERKEY)/ 對(duì)游標(biāo)附加過(guò)濾操作和鏈接過(guò)濾操作
6=A5.groups(L_ORDERKEY)/ 對(duì) L_ORDERKEY 去重
7=A3.join@i(O_ORDERKEY, A6:L_ORDERKEY)/ 對(duì)排列執(zhí)行鏈接過(guò)濾操作
8=A7.groups(O_ORDERPRIORITY;count(1):O_COUNT)/ 對(duì)排列計(jì)算分組得到最終結(jié)果
集算器實(shí)現(xiàn)(2):

AB
11995-10-01=after@m(A1,3)
2=file(ORDERS).cursor@b(O_ORDERKEY,O_ORDERDATE,O_ORDERPRIORITY)/ 在 ORDER 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
3=A2.select(O_ORDERDATE>=A1 && O_ORDERDATE < B1)/ 對(duì)游標(biāo)附加過(guò)濾操作
4=file(LINEITEM).cursor@b(L_ORDERKEY,L_COMMITDATE,L_RECEIPTDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
5=A4.select(L_COMMITDATE < L_RECEIPTDATE)/ 對(duì)游標(biāo)附加過(guò)濾操作
6=A5.group@1(L_ORDERKEY)/ 按 L_ORDERKEY 去重
7=joinx(A3:ORDER, O_ORDERKEY; A6, L_ORDERKEY)/ 對(duì)有序游標(biāo)執(zhí)行內(nèi)連接
8=A7.groups(ORDER.O_ORDERPRIORITY:O_ORDERPRIORITY;count(1):O_COUNT)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

EXISTS 非等值條件

同表關(guān)聯(lián)

SQL 示例(6):
select
      L_SUPPKEY, count(*) as numwait
from
      LINEITEM L1,
where
      L1.L_RECEIPTDATE > L1.L_COMMITDATE
      and exists (
            select
                  *
            from
                  LINEITEM L2
            where
                  L2.L_ORDERKEY = L1.L_ORDERKEY
                  and L2.L_SUPPKEY <> L1.L_SUPPKEY
            )
      and not exists (
            select
                  *
            from
                  LINEITEM L3
            where
                  L3.L_ORDERKEY = L1.L_ORDERKEY
                  and L3.L_SUPPKEY <> L1.L_SUPPKEY
                  and L3.L_RECEIPTDATE > L3.L_COMMITDATE
            )
group by
      L_SUPPKEY

優(yōu)化思路:

我們先來(lái)看一下 LINEITEM 表的數(shù)據(jù)特點(diǎn),LINEITEM 表的主鍵是 L_ORDERKEY、L_LINENUMBER,一個(gè)訂單對(duì)應(yīng) LINEITEM 里的多條記錄,這些記錄的 L_ORDERKEY 是相同的并且在數(shù)據(jù)文件中是相鄰的。知道這些信息后再來(lái)分析上面的 SQL,其條件是為了找出有多個(gè)供應(yīng)商供貨并且有且僅有一個(gè)供應(yīng)商沒(méi)有按時(shí)交貨的訂單,因?yàn)閿?shù)據(jù)是按訂單順序存放的,這樣我們就可以按訂單有序分組,然后循環(huán)每組訂單判斷是否有沒(méi)按時(shí)交貨的訂單項(xiàng),是否有多個(gè)供貨商,并且是不是只有一個(gè)供應(yīng)商沒(méi)有按時(shí)交貨。

集算器實(shí)現(xiàn):

AB
1=file(LINEITEM).cursor@b(L_ORDERKEY,L_SUPPKEY,L_RECEIPTDATE,L_COMMITDATE)/ 在 LINEITEM 表所對(duì)應(yīng)的集文件上定義游標(biāo),參數(shù)為選出列
2=A1.group(L_ORDERKEY)/ 對(duì)有序游標(biāo)附加分組, 結(jié)果為排列構(gòu)成的游標(biāo)
3=A2.conj((t=~.select(L_RECEIPTDATE > L_COMMITDATE),if(t.len() > 0 && t.select@1(t(1).L_SUPPKEY!=L_SUPPKEY)== null && ~.select@1(t(1).L_SUPPKEY!=L_SUPPKEY)!= null,t,null)))/ 選出每一組中沒(méi)有按時(shí)發(fā)貨的訂單賦值給臨時(shí)變量 t,如果 t 長(zhǎng)度大于 0 并且 t 中的供應(yīng)商只有一個(gè)并且此組中供應(yīng)商有多個(gè)則返回 t,否則返回 null,conj 相當(dāng)于 group 的逆操作
4=A3.groups@u(L_SUPPKEY;count(1):numwait)/ 對(duì)游標(biāo)計(jì)算分組得到最終結(jié)果

總結(jié)

在沒(méi)有空值的時(shí)候帶子查詢的 IN 都可以用 EXISTS 描述,同一個(gè)查詢需求用 IN 描述和用 EXISTS 描述翻譯成的集算器代碼是相同的,所以我們只要弄清楚 EXISTS 怎么翻譯和優(yōu)化就知道 IN 怎么處理了。

等值 exist 本質(zhì)上是做連接,兩個(gè)表做連接效率較好的兩種方式是哈希連接和有序歸并連接,對(duì)于翻譯 select *** from A where exists (select *** from B where ***) 樣式的 SQL,我們首先要弄清楚下列信息:

(1)關(guān)聯(lián)字段是否是各表的主鍵或者邏輯主鍵

(2)A、B 表的規(guī)模,執(zhí)行其它過(guò)濾條件后是否能載入內(nèi)存

(3)如果沒(méi)有某個(gè)表能裝入內(nèi)存則要考察兩個(gè)表是否按關(guān)聯(lián)字段有序

如果有一個(gè)表能載入內(nèi)存則可以選用哈希連接的方式來(lái)實(shí)現(xiàn),相關(guān)的集算器函數(shù)有兩個(gè) cs.switch()、cs.join(),這兩個(gè)函數(shù)有兩個(gè)可用的選項(xiàng) @i、@d 分別對(duì)應(yīng) exists 和 not exists,參數(shù)里的表要求按關(guān)聯(lián)字段值唯一,如果不是邏輯主鍵則要先去重,可用 A.groups()去重。如果兩個(gè)表都很大不能載入內(nèi)存則要考察兩個(gè)表是否按關(guān)聯(lián)字段有序,如果無(wú)序可以用 cs.sortx() 排序,對(duì)于有序的兩個(gè)表就可以用 joinx() 來(lái)做連接了。

非等值運(yùn)算則要分析其中的運(yùn)算邏輯看能否轉(zhuǎn)成分組后再計(jì)算,如果不能則只能使用嵌套循環(huán)連接的方式了,對(duì)應(yīng)的函數(shù)是 xjoin()。

知道這些信息并熟練掌握集算器相關(guān)的幾個(gè)函數(shù)后我們就能夠?qū)懗龈咝У拇a。


文章名稱:如何用外部程序優(yōu)化SQL語(yǔ)句中的IN和EXISTS
瀏覽地址:http://weahome.cn/article/picdhd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部