爲了說明以上引入的特徵函數在加速查詢處理中的作用,讓我們具體分析一個實例。 |
試考察一個描述學生收 selfincome)(8) |
入狀況的表 Students(name,s |
tatus,parentincome, |
其中name是主鍵,屬性 自父母,當status取值0時 得到形如(name,income) 0值時)或是來自父母的收 |
status是一種標法量,當status ,表明學生的收入完全是自己勞 的查詢結果,其中income或爲學 入(當相應的status取值爲1時 |
取值1時,表明學生的收入完全來 動所得。針對這個表,假定我們想 生自己的收入(當相應的status取 )。 |
從表students的結構及查詢結果的語義分析,完成查詢的常規方法應當是 |
SELECT name,income=parentincome |
FROM student |
WHERE student=1 UNION (9) |
SELECT name , income=selfincome |
FROM student |
WHERE student=0 |
這是一個很自然、很直白的查詢表達 執行這個查詢的一般過程是:首先分別執 存放查詢中間結果的臨時表並將兩個子查 序以便消除可能存在的重複值。至此,才 students要遍歷兩次而且要對中間結果作 的。查詢(9)唯一的優點,是它表達上 |
,但同時也是一個非常低效和非常耗費資源的表達。 行由算子UNION所連結的兩個子查詢,然後產生一個 詢的結果存入以這個臨時表中,第3步對臨時表作排 得到最終的查詢結果。在這樣的處理中,除對整個表 排序處理,處理上的煩雜和資源的消耗都是顯而易見 的自然直白,誰都想得到。 |
對本例而言,還有更緊湊和更有效的查詢表達。例如,不難驗證以下的查詢 |
SEIECT name,income=parentincome |
*status+selfincome*(1-status) |
FROM students; (10) |
從語義上與查詢(9) ,因爲它只遍歷一次表stud 果,不同的查詢表達在處理 式,不但是必要的而且是可 |
完全等價。但查詢(10)不但消 ents而且避免了可怕的排序操作 效率和資源消耗上可能會相去甚 行的。 |
耗的存儲少而且處理上要有效得多 。這個例子說明,對同一個查詢結 遠。因此,尋求有效的查詢表達方 |
查詢表達(10)與像( 子句和算子UNION顯式給出 查詢表達採用什麼形式,本 表達(10),不難發現只所 問題稍作些許改變(例如, ,如此等等)問題就不會這 們對任何顯式表達在WHERE 案是肯定的,這就是我們在 |
9)那樣的常規表達不同之處在 ,首者將查詢條件間接地隱藏在 例都屬於“條件檢索”的查詢類 以能給出如此簡潔而正確的回籤 屬性student取0和1以外的值, 麼簡單了。因此,是否有一種很 子句和相關算子中的選擇條件找 下面要介紹的“特徵函數法”。 |
於,後者的查詢條件由兩個WHERE SELECT子句的算術表達式中。無論 型。如果對照一下查詢要求和查詢 ,實在是有點“事有湊巧”。如果 或者student取兩個以上的標法值 一般、很系統的解決方案,能讓我 到與之語義等價的算術表達式?答 |
4. 幾個典型查詢的特徵函數解 |
正如上面所講,特徵函數能夠實現我 因此,特徵函數最直接和簡便的運用是針 爲了較全面地瞭解特徵函數在解決複雜查 例。對某些實例,我們還將說明它的應用 的特徵函數都沒有用元函數展開。因此, (5)、(6)替換這裏的特徵函數。 |
們的願望,即將顯式的布爾條件轉化爲標量表達式。 對條件檢索型的查詢,但它的作用並不僅僅止於此。 詢中的作用,本節將由易到難介紹和分析若干典型實 領域。爲了表達上更緊湊,所有出現在標量表達式中 如果要通過實際運行驗證這裏的實例,必須先藉助於 |
4.1 條件檢索 |
由(10)給出的查詢可藉助於特徵函數識爲 |
SELECT name, |
income=parentincome |
*d [status=1]+selfincome |
*d [status=0] |
FROM student (11) |
如果檢索條件僅止於此 檢索條件遠比此處複雜而多 外,加上按學生的年齡分段 依靠父母的學生爲一組,凡 三組。在查詢結果中,收入 母的收入和學生自己的收入 於用常規方法處理查詢的人 相對於原問題而言,要求的 |
,用(11)代替(10)並沒有什 樣。例如,若將上例的要求稍作 的要求,即以19歲和23歲爲年齡 年齡超過23歲者完全自食其力的 (income)一欄有不同的含義: ,對第三組學生,則對應於前兩 看來,這樣的條件就顯得大複雜 擴展是很輕微的。對照查詢表達 |
麼本質上的意義。但實際問題中的 修改,即在保留status原有語義而 的分界點,凡年齡不超過19歲而且 學生爲第二組,所有其他學生爲第 對前兩組學生,分別對應於他們父 組學生收入的算術平均值。在習慣 了。實際上,這是很自然的要求, 式(11),不難驗證 |
SELECT name, |
income=parentincome*d [atatus=1]*d [age<=19]+selfincome*sign (d [status=O]+d [age>23])+( (parentinceome+selfinco me)/2.0*(1一d [status=1])*d [age<=19]-sign(d [sign=0] +d [age>23]) |
FROM students; (12) |
正是上述查詢所要求的有效表達方式 一一對應,都具有很典型的級聯式IF� ,無論查詢條件多複雜(例如有更多的屬 等等),條件檢索型的查詢都具有如(11 件越多則級聯數越多,但正則算術表達式 只對表student遍歷一次。相反,若按常 來回答,最終的結果是所有子查詢結果往 瞭然。 |
。從income的表達形式看,與查詢條件的要求完全是 THEN�ELSE結構。一般而言,在特徵函數的參與下 性出現在條件中,同一屬性值被劃分爲更多的區段, ),(12)那樣的典型結構。不同之處僅僅在於,條 的邏輯結構都相同。所有這類查詢表達,在執行中都 規方法求解,原則上每一個分類條件需要一個子查詢 UNION運算所得。兩種表達兩種效果,孰優孰劣一目 |
4. 2 直方圖問題 |
求直方圖是統計應用中 ,用常規方法求解並不是一 處理的過程很高效而且很直 在表employee(name,age 如(nokids,onekids,few 、有一個孩子的、有兩個或 |
經常要解決的問題白如果統計數 個很輕鬆的任務。但是,借用特 觀。爲了說明這一點,讓我們看 dept,kids)中,其中kid也表 kids,manykids)的統計結果, 三個孩子的以及有三個以上孩子 |
據來自數據庫而且數據量很大的話 徵函數可以順利地解決問題,不但 一個具體的例子。假定統計數據存 示每個僱員的子女數。要求給出形 即分別計算出所有僱員中沒有孩子 的僱員總數。 |
如果用常規方法,需要查歷表employ manykids的值,然後經3個UNION運算才能 分爲4個區段而是8個甚至更多個區段,常 問題的解顯然是 |
ee四次,分別計算出nokids,onekids,fewkids和 得出最終的結果。如果原問題不是將僱員的子女數劃 規方法的低效就更明顯不過了。運用特徵函數,上述 |
SELECT nokids=SIJM(d [kids=0]), |
Onekids=SUM(d [kids=1]) |
fewkids=SUM(d [2<=kids<=3]) |
manykids=SUM[kids>=4]) |
FROM employee; (13) |
這個查詢結果的正確性很容易驗證:對於表中任意一行,如果kids=0,則d [kids=0]=1而且d [kids=l]=d [kids>=4]=d [2<=kids <=3]=0,所以該行在區段nokids中求和而不在任何其他三個區段中求和,對於kids的其他取值依此類推,這表明(13)的結果正是原問題所需要的結果。重要的是這個結果不但正確,得到這個結果的途境非常有效,因爲處理中只遍歷表一次。如果將僱員所擁有的子女數區分爲更多的值段,運用特徵函數的查詢處理仍然只遍歷表一次而不是更多,不同之處僅在於選擇表中的計算多幾項而已,查詢表達在邏輯上的複雜性一點也沒有增加。 |
同一個基本問題也可以 問題往往很困難。 |
引導出不同的變異。若沒上述的 |
基本解作基礎,直接解決這些變異 |
變異問題之一:對同一 要求得到如(dept,nokids |
個表employee,按僱員所在的不 ,onekid,fewkids,manykids |
同部門分別計算子女數的分佈,即 )的結果。 |
這個問題的解顯然是以下的查詢表達 |
SELECT dept. |
nokids=SUM(d [kids=0]), |
onekid=SUM(d [kids=1]) |
fewkids=SUM(d [2<=kids <=3] |
manykids=SUM(d [kids>=4]) |
FROM employee;GROUP BY dept; (14) |
變異問題之二:按照年齡區段求僱員 個區段,即:小於25歲的、大於45歲的以 2年齡段。這個問題事實上是要求對錶emp fewkids,manykids)的結果,其中 |
子女分佈的直方圖。爲確定起見,僱員的年齡分爲三 及年齡在25歲到45歲之間的,分別稱爲第1、第3和第 loy回給出形如(ageCategoy,nokids,onekids, |
1 若age<25 |
d (a)= 2 若25<=age<=45 3 若age>45 |
(15) |
這個問題雖有相當的難 Sybase的Transact SQL就是 需要的解答 |
度,但對於允許表達式出現在GR 如此),答案也是直接了當的。 |
OUP BY子句中的系統(例如, 不難驗證以下查詢表達正是我們所 |
SELECT ageCategory=1xd [age<25]+2×d [25<=age<=45] +3×d [age>45], |
nokids =SUM(d [kids=0]), |
onekids =SUM(d [kids=1]), |
onekid =SUM( d [kids<=3 AND Kids>=2]) |
manykids =SUM(d [kids>=4]) |
FROM employee |
GROUP BY 1′ d [age<25]+2×d [25<=age<=45]+ 3×d [age>45]; (16) |
這個問題與上一個問題的區別僅僅在 ageCaegory,按照(15)式的定義,很容 |
選擇表和GROUP BY子句中使用3年齡段表達式 易驗證(16)確是我們所需要的查詢。 |
沿着這個思路走下去,還可以處理更 有效性也越能顯現出來。 |
複雜的問題。當直方圖越來越“寬”時,特徵函數的 |
4.3 錶轉置 |
錶轉置是一個變換過程 設計中經常遇到的問題。C Date將中文中前一種形式的 示。鑑於SQL的集函數本質 用集函數的給應用處理帶來 主意。 |
,它將一個窄而長的錶轉化成一 .j Date很早就注意到這一點並 表稱之爲表的“列式”表示,而 上是面向列式表示而不是面向行 靈活性的優點。因此,基表的設 |
種寬而短的表,這是在數據庫應用 給出了處理這一問題的一般原則。 將後一種形式的表稱爲“行式”表 式表示的,所以列式表示有便於運 計多考慮採用列式表示一般是個好 |
針對列式表示的基表作 僱員月獎金的表bonus(nam 示,例如就可以寫成bonus 獎金一覽表,從bonus'表查 他的查詢要求很難有適應性 回籤其他處理要求。例如, |
查詢時,特徵函數是實現錶轉置 e,month,amount)。這個表顯 ’(name, janAmount,…,decAm 詢最簡便。但這種行式表示的表 。相反,形如bonus的列式表示 針對上述要求的特徵函數表示就 |
的有力主具。例如,考察一個記錄 然是列式表示,相對於它的行式表 ount)。如果想得到每個僱員各月 本質上只對這一種查詢有效,對其 不僅可以回答上述查詢而且還可以 是 |
SELECT name, |
janAmount=SUM(amount×d [month=1]), |
febAmount=SUM(amount×d [month=2]), |
. . . . |
decAmount=SUM(amount×d [month=12]) |
FROM bonus |
GROUP BY name; (17) |
讀者不妨思考一下,針對bonus表的同一查詢要求若不採用特徵函數該怎麼滿足。 |
4.4 求中位數 |
在實驗數據處理中,經常有求一組數 位數,存在兩種定義,即統計學定義和所 是這組數中的某一個。因此,當有偶數個 ,要視具體應用背景而定。中位數的後一 果數值的個數爲奇數(設爲n),則中位 的定義,用一個語句求一組數的中位數始 用一般方法來處理這個問題,也得寫一個 這個問題的一個很簡潔的解。爲確定起見 這組數據中不存在重複的值。除此而外, 假定下,數據集data的中位數正是下述查 |
據的“中位數”(median的要求。衆所周知,關於中 謂的“財務”定義。按照統計學的定義,中位數必須 數時,必須從兩個數中作出選擇,或選大者或選小者 種定義取兩數(在有偶數個數時)的算術平均值。如 數就是數組中第(n+1)/2個數。不論採用什麼樣 終是一個難題。既使是訓練有素的SQL程序員,要想 很複雜的過程。但是,借用於特徵函數,很容易得到 ,考慮這樣的一組實驗數據data (value)。這表明 我們還要假定所有的數據都是非空的數據。在這樣的 詢語句的結果: |
SELECT x.value FROM data x, data y |
GROUP BY x.value |
HAVING SUM(d [y.value<=x.v |
alue])=(COUNT(×) +1)/2 (18) |
因爲,對於每個x.value,表達式SUM(d [y.value<=x.value])的結果是數據集中小於或等於該值數據的個數,所以由這個HAVING子句選擇的正是所要求的中位數(細心的讀者不難發現,我們這裏利用了Sybase兩個整數相除的結果是實際相除後再取截斷而得到的值。另外,當數據集包含偶數個元素時,取的數是兩數中較小的一個,這正符合中位數的統計學定義。) |
上面求中位數的方法很 考察數據集data 2(partit 以是任意數據類型,整個數 是各個子集的中位數: |
容易延拓到數據集往某些屬性而 ion,value),其中value仍爲非 據集data2經此屬性而分割爲若 |
分割爲若干個子集的情形。例如, 空數值量,但屬性partition則可 幹個子集。下述查詢語句的結果恰 |
SELECT x.partition,x.value |
FROM data2 x,data2 y |
WHERE x. partition=y. Partition |
GROUP BY x.Partition , x.value |
HAVING SUM (d [y.Value<=x.value])=(COUNT(x)+1) /2 (19) |
上式中的自連結是表分割的需要,除此而外上兩種方法沒有本質上的區別。 |
4.5 求端值 |
在某些實際問題中,所 將求這些數據項中取值最大 sat2),其中sat 1和sat 2 成績的一覽表,即求形如( 最好成績。 |
設計的表的行數據包含了若干個 或最小的稱爲“端值問題”。例 代表學生兩次考試的成績。假定 name,bestSat)的結果,其中b |
可以彼此比較分析的數據項。我們 如,考察表scores(name,sat1, 需要得到每個人兩次考試中的最好 estSat表示每個學生兩次成績中的 |
某些數據庫系統(例如Oracle)有內部函數greatest(value 1,value 2…),可供直接解決問題。在不具備這種函數的系統(例如Sybase等)中,一般解決方法是,第一次遍歷全表得以滿足條件,sat 1>=sat 2的sat 1,第二次遍歷全表得到滿足條件sat 2>sat l的sat 2,再將中間結果經UNION運算才能獲得最終結果。 |
藉助於特徵函數只須掃描表一遍而且查詢表達非常簡單,即: |
SELECT name, |
bestSat=sat 1% d [sat 1>=sat 2]+sat 2×d [sat 2>sat1] |
FROM score; (20) |
假定我們不只要得到每 所得,只須在(20)的選擇 |
個學生兩次考試中的最好成績, 表中補加一項,即: |
而且還想知道這個成績是哪次考試 |
SELECT name |
bestSat=sat l % d [sat1>=sat 2]+sat 2% d [sat 2>sat 1] whichSat=1% d [sat 1>=sat 2]+2% d [sat 2>sat l] |
FROM score; (21) |
這個結果只在sat 1=s 所得)。除此而外似乎不必 興趣的讀者不妨考慮一下這 |
at2 時有點歧義但並不錯(在這 再做任何解釋了。以上只考慮了 個問題的種種變異情況及其解答 |
種情況下,(21)認爲是第一次考試 最大值,求最小值可仿此辦理。有 。 |
5 幾個值得進一步思考的問題 |
由(5)式給出的特徵 函數,在計算的複雜性上會 改善特徵函數的效率。其次 ,是爲了保證元函數abs( 在着降低這一條件強度的可 ,去掉非空假定就顯得特別 |
函數表示,並不是唯一的形式, 有差異。因此,選擇具有更低計 ,本文開頭關於出現在特徵函數 )和sign()有定義和整個(5 能性。考慮到幾乎所有的主流數 必要了。 |
還可有其他的表現形式。不同的元 算複雜性的函數,有可能更進一步 中的屬性必須是非空數值量的假定 )式正確的充分性條件。所以,存 據庫系統都支持三值邏輯(3VL) |
儘管本文只考慮了特徵函數在查詢中 作較系統的考察。另外,在E.birger等 方面(例如,出現在特徵函數中的屬性, 象數據類型等等)。所有這些,都有待於 |
的作用,我們認爲同樣的思想也應當針對數據庫更新 人原始工作的框架內,也存在着種種明顯的可擴充的 既可以是普通的表屬性,也應當允許是某種受限的抽 我們更進一步的工作去挖掘或作出分析判斷。 |