專(zhuān)利名稱(chēng)::自動(dòng)產(chǎn)生數(shù)據(jù)庫(kù)查詢(xún)的系統(tǒng)和方法
技術(shù)領(lǐng)域:
:本說(shuō)明書(shū)涉及數(shù)據(jù)庫(kù),更確切地說(shuō),涉及自動(dòng)產(chǎn)生數(shù)據(jù)庫(kù)查詢(xún)的系統(tǒng)和方法。
背景技術(shù):
:結(jié)構(gòu)化查詢(xún)語(yǔ)言(SQL)是一種用于數(shù)據(jù)庫(kù)交互操作的ANSI標(biāo)準(zhǔn)語(yǔ)言。SQL允許用戶(hù)從數(shù)據(jù)庫(kù)中許多不同的記錄集(表格)組合信息,以便從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)。不過(guò),SQL的能力也有某些缺點(diǎn)。例如,用戶(hù)能夠在一個(gè)SQL查詢(xún)中組合不同的表格,它可能產(chǎn)生數(shù)據(jù)庫(kù)引擎不可能解決的或者耗用大量系統(tǒng)資源的查詢(xún)。數(shù)據(jù)庫(kù)系統(tǒng)往往包括性能調(diào)節(jié)的系統(tǒng)或方法。例如,Oracle7提供了多種腳本(如UTILBSTAT和UTLESTAT),能夠用于通過(guò)在一個(gè)或多個(gè)報(bào)告中總結(jié)數(shù)據(jù)庫(kù)的操作狀態(tài),協(xié)助性能調(diào)節(jié)。這些腳本是一組SQL腳本,對(duì)于捕捉全系統(tǒng)的數(shù)據(jù)庫(kù)性能的統(tǒng)計(jì)瞬態(tài)情況和產(chǎn)生有助于操作員優(yōu)化數(shù)據(jù)庫(kù)性能的報(bào)告十分有用。數(shù)據(jù)庫(kù)操作員能夠使用這些報(bào)告對(duì)數(shù)據(jù)庫(kù)的性能進(jìn)行精細(xì)調(diào)節(jié)以及對(duì)數(shù)據(jù)庫(kù)進(jìn)行預(yù)防性的維護(hù)。報(bào)告可能包括例如有關(guān)數(shù)據(jù)庫(kù)存儲(chǔ)器目標(biāo)的信息,包括庫(kù)緩存、詞典緩存、閉鎖使用、文件I/O和回退統(tǒng)計(jì)?,F(xiàn)有系統(tǒng)的一個(gè)問(wèn)題是,它們往往限制了產(chǎn)生最優(yōu)執(zhí)行計(jì)劃所花費(fèi)的時(shí)間長(zhǎng)短。此外,熟悉的用戶(hù)可能對(duì)數(shù)據(jù)了解得比目標(biāo)統(tǒng)計(jì)表現(xiàn)出的更多,如果確實(shí)有目標(biāo)統(tǒng)計(jì)的話(huà)。現(xiàn)有系統(tǒng)往往不利用用戶(hù)的知識(shí)。此外,盡管在恰當(dāng)?shù)靥峁┖头治鰰r(shí)統(tǒng)計(jì)可能有用,如果目標(biāo)還沒(méi)有被分析則可能根本沒(méi)有統(tǒng)計(jì)結(jié)果,或者統(tǒng)計(jì)結(jié)果可能過(guò)時(shí)了。在具體的事例中,可能沒(méi)有洞察數(shù)據(jù)分布的特定統(tǒng)計(jì)結(jié)果。相反,用戶(hù)倒可能具有在調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)中有用的第一手知識(shí),而這可能是無(wú)法通過(guò)其他途徑得到的。例如,用戶(hù)可能知道,將會(huì)在有更多的資源比如多CPU可用時(shí)執(zhí)行查詢(xún),即使系統(tǒng)通常是滿(mǎn)負(fù)荷的。在數(shù)據(jù)庫(kù)查詢(xún)調(diào)節(jié)過(guò)程期間,會(huì)證明這種信息是十分有用的。
發(fā)明內(nèi)容一種調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的方法,包括選擇數(shù)據(jù)庫(kù)查詢(xún);分析選定的數(shù)據(jù)庫(kù)查詢(xún),以確定選定的數(shù)據(jù)庫(kù)查詢(xún)中若干部分之間的關(guān)系;從多個(gè)可用的最優(yōu)化模式中選擇一個(gè)最優(yōu)化模式;根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)中至少一部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún);以及顯示修改后的數(shù)據(jù)庫(kù)查詢(xún)。這種分析可以確定數(shù)據(jù)庫(kù)查詢(xún)之內(nèi)的標(biāo)記,標(biāo)記是由分隔符分開(kāi)的若干單詞。多個(gè)可用的最優(yōu)化模式可能包括基于成本的和基于規(guī)則的模式?;诔杀镜哪J娇赡馨‵irst_Rows(第一行)模式和All_Rows(所有行)模式。這種方法可能進(jìn)一步包括確定一種與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。這種方法可能進(jìn)一步包括比較與使用選定的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本和與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。這種方法可能進(jìn)一步包括分析選定的數(shù)據(jù)庫(kù)查詢(xún),以確定該數(shù)據(jù)庫(kù)查詢(xún)是否包括至少一個(gè)子查詢(xún),其中的子句包含有NOTEXISTS、NOTIN和ALL中至少一個(gè)。這種方法可能進(jìn)一步包括提示用戶(hù),根據(jù)該數(shù)據(jù)庫(kù)查詢(xún)是否包括包含有NOTEXISTS、NOTIN和ALL中至少一個(gè)的子句,選擇在調(diào)節(jié)期間使用的優(yōu)先設(shè)置。這種優(yōu)先設(shè)置可能包括重寫(xiě)優(yōu)先設(shè)置,以便使用戶(hù)能夠選擇兩種轉(zhuǎn)換之一一種是NOTEXISTS運(yùn)算符轉(zhuǎn)換為NOTIN運(yùn)算符,另一種是選定的數(shù)據(jù)庫(kù)查詢(xún)轉(zhuǎn)換為外部的連接。這種優(yōu)先設(shè)置可能包括重寫(xiě)優(yōu)先設(shè)置,以便使用戶(hù)能夠選擇將ALL運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換為一個(gè)連接或者外部連接。這種優(yōu)先設(shè)置可能包括重寫(xiě)優(yōu)先設(shè)置,以便使用戶(hù)能夠選擇是否使用NOTEXISTS運(yùn)算符和外部連接之一,轉(zhuǎn)換NOTIN運(yùn)算符連接的子查詢(xún)。計(jì)算機(jī)存儲(chǔ)介質(zhì)包括用于調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的、計(jì)算機(jī)可執(zhí)行的代碼,其中包括用于使用戶(hù)選擇數(shù)據(jù)庫(kù)查詢(xún)的、計(jì)算機(jī)可執(zhí)行的代碼;用于分析選定的數(shù)據(jù)庫(kù)查詢(xún)以確定選定之?dāng)?shù)據(jù)庫(kù)查詢(xún)中若干部分之間關(guān)系的、計(jì)算機(jī)可執(zhí)行的代碼;用于使用戶(hù)從多個(gè)可用的最優(yōu)化模式中選擇一個(gè)最優(yōu)化模式的、計(jì)算機(jī)可執(zhí)行的代碼;用于根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)中至少一部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún)的、計(jì)算機(jī)可執(zhí)行的代碼;以及用于顯示修改后的數(shù)據(jù)庫(kù)查詢(xún)的、計(jì)算機(jī)可執(zhí)行的代碼。用于調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的、編程的計(jì)算機(jī)系統(tǒng)包括一臺(tái)顯示器——用于向用戶(hù)顯示至少一個(gè)數(shù)據(jù)庫(kù)查詢(xún);一種用戶(hù)輸入——使用戶(hù)從顯示的數(shù)據(jù)庫(kù)查詢(xún)之中選擇一個(gè)數(shù)據(jù)庫(kù)查詢(xún),從多個(gè)可用的最優(yōu)化模式中選擇一個(gè)最優(yōu)化模式;以及一個(gè)處理器——用于分析選定的數(shù)據(jù)庫(kù)查詢(xún),以確定選定的數(shù)據(jù)庫(kù)查詢(xún)中若干部分之間的關(guān)系,并且用于根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)中至少一部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún);修改后的數(shù)據(jù)庫(kù)查詢(xún),通過(guò)該顯示器向用戶(hù)顯示。附圖簡(jiǎn)要說(shuō)明下列附圖僅僅描述了說(shuō)明性的實(shí)例,為了更完全地評(píng)價(jià)和理解下列介紹而提供。圖1是一個(gè)框圖,用于介紹依據(jù)一個(gè)實(shí)施例的一個(gè)數(shù)據(jù)庫(kù)查詢(xún)調(diào)節(jié)過(guò)程;圖2顯示了包括一個(gè)SQL語(yǔ)句的一個(gè)對(duì)話(huà)顯示;圖3顯示了一個(gè)選擇最優(yōu)化模式對(duì)話(huà)顯示;圖4顯示了一個(gè)優(yōu)先設(shè)置窗口顯示;圖5顯示了一個(gè)檢驗(yàn)SQL對(duì)話(huà)顯示;圖6顯示了一個(gè)結(jié)果窗口顯示;圖7顯示了一個(gè)編輯或者說(shuō)調(diào)節(jié)窗口顯示;圖8顯示了一個(gè)詳細(xì)結(jié)果窗口顯示;圖9是一個(gè)計(jì)算機(jī)系統(tǒng)的框圖,本系統(tǒng)和方法可以應(yīng)用在其中;以及圖10至圖13是顯示多種SQL語(yǔ)句中表格層次的示意圖。具體實(shí)施例方式在介紹附圖中展示的本公開(kāi)文件的優(yōu)選實(shí)施例時(shí),為清晰起見(jiàn)采用了特定的技術(shù)。不過(guò),本公開(kāi)文件并非試圖限于由此選擇的特定技術(shù),應(yīng)當(dāng)理解,每個(gè)特定的要素包括了在類(lèi)似方式下運(yùn)行的所有技術(shù)上的等效物。本公開(kāi)文件涉及為了提高性能而自動(dòng)調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的系統(tǒng)和方法。例如,本系統(tǒng)和方法的形式可能是數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS),它能夠調(diào)節(jié)結(jié)構(gòu)化查詢(xún)語(yǔ)言(SQL)的語(yǔ)句,以產(chǎn)生最優(yōu)的執(zhí)行方案。在一方面,本公開(kāi)文件涉及的系統(tǒng)和方法用于在數(shù)據(jù)庫(kù)結(jié)構(gòu)的上下文中分析數(shù)據(jù)庫(kù)查詢(xún),并且修改和/或重構(gòu)該查詢(xún),因此它能夠在DBMS結(jié)構(gòu)的上下文之內(nèi)執(zhí)行。此外,本公開(kāi)文件的系統(tǒng)和方法能夠使用數(shù)據(jù)庫(kù)關(guān)系結(jié)構(gòu)來(lái)使該查詢(xún)使用的DBMS資源最小化,并確保該查詢(xún)能夠完成。實(shí)現(xiàn)這些結(jié)果的一種方法是將SQL語(yǔ)句剖分成定制的數(shù)據(jù)結(jié)構(gòu),它容許SQL語(yǔ)句的修改和重構(gòu)。舉例來(lái)說(shuō),如在某個(gè)FROM子句中的每個(gè)表格都可以檢驗(yàn)以保證引用的完整性,并且可以對(duì)照如某個(gè)用戶(hù)的WHERE條件,就可以為了正確的外部連接說(shuō)明而檢驗(yàn)這個(gè)WHERE條件。本系統(tǒng)分析SQL語(yǔ)句并保持追蹤每個(gè)標(biāo)記表格是如何連接的,以及SQL語(yǔ)句若干部分之間的關(guān)系。標(biāo)記可能是SQL語(yǔ)句之內(nèi)由分隔符分開(kāi)的任何單詞。表示表格列名稱(chēng)的標(biāo)記可以用于確認(rèn)SQL語(yǔ)句內(nèi)部存在的連接和其它關(guān)系。然后,系統(tǒng)和方法可以改變例如連接的次序,并且可以移動(dòng)子查詢(xún)以調(diào)節(jié)SQL語(yǔ)句,達(dá)到最高性能。系統(tǒng)和方法的實(shí)現(xiàn)形式可以是在計(jì)算機(jī)系統(tǒng)——比如主機(jī)、個(gè)人計(jì)算機(jī)(PC)、手持計(jì)算機(jī)等等——中運(yùn)行的軟件應(yīng)用程序。計(jì)算機(jī)系統(tǒng)可以連接到數(shù)據(jù)庫(kù)。這種連接可以是例如通過(guò)直接連接——比如直接的硬布線(xiàn)或者無(wú)線(xiàn)連接,通過(guò)網(wǎng)絡(luò)連接——比如局域網(wǎng),或者通過(guò)因特網(wǎng)。圖9中顯示了能夠?qū)崿F(xiàn)本系統(tǒng)和方法之計(jì)算機(jī)系統(tǒng)的一個(gè)實(shí)例。該計(jì)算機(jī)系統(tǒng)一般地成為系統(tǒng)200,可能包括中央處理單元(CPU)202、存儲(chǔ)器204、打印機(jī)接口206、顯示單元208、LAN(局域網(wǎng))數(shù)據(jù)傳輸控制器210、LAN接口212、網(wǎng)絡(luò)控制器214、內(nèi)部總線(xiàn)216以及一臺(tái)或多臺(tái)輸入設(shè)備218,比如鍵盤(pán)、鼠標(biāo)等等。如圖所示,系統(tǒng)200可以通過(guò)連接裝置222連接到數(shù)據(jù)庫(kù)。圖1描述了一個(gè)為提高性能而調(diào)節(jié)SQL語(yǔ)句的過(guò)程,依據(jù)本公開(kāi)文件的一個(gè)實(shí)施例。用戶(hù)首先選擇他們需要調(diào)節(jié)的一個(gè)SQL語(yǔ)句(步驟S2)。例如,從顯示單元208上顯示的SQL編輯窗口,通過(guò)將光標(biāo)放置在SQL語(yǔ)句的起點(diǎn),按下鼠標(biāo)的左鍵,拖動(dòng)到該SQL語(yǔ)句的末端,然后釋放鼠標(biāo)鍵,用戶(hù)能夠選中他們需要調(diào)節(jié)的一個(gè)SQL語(yǔ)句。這就選中了該SQL語(yǔ)句。然后用戶(hù)能夠通過(guò)例如單擊某個(gè)適當(dāng)?shù)陌粹o,從一個(gè)工具菜單(未顯示)選擇一個(gè)SQL調(diào)節(jié)器選件。然后,選中的要調(diào)節(jié)的SQL語(yǔ)句顯示在SQL調(diào)節(jié)器窗口1中(步驟S4),如圖2所示。然后用戶(hù)就能夠考察顯示的SQL語(yǔ)句2,以核實(shí)它就是他們需要調(diào)節(jié)的SQL語(yǔ)句。然后用戶(hù)可以選擇單擊后退按鈕3、下一步按鈕4、完成按鈕5或者取消按鈕6。后退按鈕3返回前一個(gè)窗口,使用戶(hù)選擇一個(gè)不同的SQL語(yǔ)句。取消按鈕6退出SQL調(diào)節(jié)器而不對(duì)顯示的SQL語(yǔ)句2進(jìn)行任何改變。下一步按鈕4移動(dòng)到下一個(gè)窗口(在圖3中顯示),使用戶(hù)選擇最優(yōu)化模式設(shè)置,下面還要介紹。完成按鈕5使用當(dāng)前的最優(yōu)化模式設(shè)置運(yùn)行SQL調(diào)節(jié)過(guò)程。本系統(tǒng)能夠采用數(shù)種最優(yōu)化模式和使用數(shù)種不同的重寫(xiě)優(yōu)先設(shè)置來(lái)運(yùn)行。用戶(hù)單擊下一步按鈕4之后,本系統(tǒng)分析該SQL語(yǔ)句(步驟S6)并顯示選擇最優(yōu)化模式窗口11,如同3所示。檢驗(yàn)該SQL語(yǔ)句以確定例如在該語(yǔ)句中存在著什么運(yùn)算符、函數(shù)等等。系統(tǒng)也檢驗(yàn)該SQL語(yǔ)句之內(nèi)的任何子查詢(xún)是否連接了NOTEXISTS、NOTIN和ALL子句。本系統(tǒng)也檢驗(yàn)表格統(tǒng)計(jì)。例如,可能要檢驗(yàn)對(duì)表格執(zhí)行ANALYZE命令時(shí)由某個(gè)系統(tǒng)比如Oracle產(chǎn)生的表格統(tǒng)計(jì)。表格統(tǒng)計(jì)可能包括行數(shù)(NUM_ROWS)、最高峰之下的數(shù)據(jù)塊數(shù)(如已經(jīng)格式化過(guò)的、接收數(shù)據(jù)的數(shù)據(jù)塊的數(shù)目,無(wú)論這些數(shù)據(jù)塊當(dāng)前包含著數(shù)據(jù)還是空著)(BLOCKS)、分配給表格的、還沒(méi)有使用的數(shù)據(jù)塊的數(shù)目(EMPTY_BLOCKS)、以字節(jié)計(jì)算的、每個(gè)數(shù)據(jù)塊中的平均可用空閑空間(AVG_SPACE)、鏈接行的數(shù)目(CHAIN_COUNT)以及以字節(jié)計(jì)算的平均行長(zhǎng)度,包括行的頭部(AVG_ROW_LEN)。如果存在足夠的信息(如對(duì)于有關(guān)的表格存在統(tǒng)計(jì)數(shù)據(jù)),系統(tǒng)就自動(dòng)選擇一個(gè)最優(yōu)化模式。選定的最優(yōu)化模式由圓按鈕7-9指示。例如,可能會(huì)自動(dòng)選擇基于成本的最優(yōu)化(FIRSTROW或ALLROW)模式,因?yàn)橛嘘P(guān)的表格存在統(tǒng)計(jì)數(shù)據(jù)時(shí)它將會(huì)產(chǎn)生很好的結(jié)果。在步驟S8中,如果在表格統(tǒng)計(jì)中沒(méi)有足夠的信息使系統(tǒng)自動(dòng)選擇一種最優(yōu)化模式,或者如果用戶(hù)需要改變系統(tǒng)自動(dòng)設(shè)置的最優(yōu)化模式,用戶(hù)通過(guò)單擊選擇最優(yōu)化模式窗口11中的圓按鈕7-9之一,可以手工地選擇最優(yōu)化模式,如圖3所示。用戶(hù)從窗口11中通過(guò)單擊優(yōu)先設(shè)置按鈕10,也可以修改重寫(xiě)優(yōu)先設(shè)置設(shè)置,下面還要更詳細(xì)地介紹。一種基于成本的最優(yōu)化模式成為ALL_ROW模式。如果在SQL語(yǔ)句中至少一個(gè)引用的表格存在統(tǒng)計(jì)數(shù)據(jù),系統(tǒng)就會(huì)默認(rèn)地自動(dòng)選擇ALL_ROW模式。ALL_ROW模式為批量處理提供了快速的吞吐率。然后,用戶(hù)通過(guò)單擊圓按鈕8,可以選擇FIRSTROW模式,除非該SQL語(yǔ)句包含著集合運(yùn)算符(如UNION、INTERSECT、MINUS、UNIONALL)、GROUPBY子句、FORUPDATE子句、聚合函數(shù)或者DISTINCT運(yùn)算符。如果該SQL語(yǔ)句包含著集合運(yùn)算符(如UNION、INTERSECT、MINUS、UNIONALL)、GROUPBY子句、FORUPDATE子句、聚合函數(shù)或者DISTINCT運(yùn)算符,用戶(hù)就不能選擇FIRSTROW模式。用戶(hù)通過(guò)單擊圓按鈕7,也可以手工選擇ALL_ROW模式。當(dāng)不能以其它方式確定對(duì)話(huà)所使用的最優(yōu)化模式時(shí),系統(tǒng)也可能自動(dòng)選擇FIRSTROW模式。如果對(duì)行處理需要快速響應(yīng)時(shí)間,可以手工選擇FIRSTROW模式。另一種模式稱(chēng)為基于規(guī)則的模式。如果對(duì)于任何引用的表格都沒(méi)有統(tǒng)計(jì)數(shù)據(jù),系統(tǒng)就會(huì)地自動(dòng)選擇基于規(guī)則的模式。通過(guò)單擊圓按鈕9,可以手工選擇基于規(guī)則的模式。如果在分析處理(步驟S6)期間確定SQL語(yǔ)句包括連接了NOTEXISTS、NOTIN或ALL子句的子查詢(xún),就使窗口11(圖3)中的優(yōu)先設(shè)置按鈕10活化。單擊優(yōu)先設(shè)置按鈕10是用戶(hù)指定重寫(xiě)優(yōu)先設(shè)置,用于重寫(xiě)連接了NOTIN運(yùn)算符、NOTEXISTS運(yùn)算符和ALL運(yùn)算符的子查詢(xún)。例如,能夠指定NOTEXISTS運(yùn)算符的重寫(xiě)優(yōu)先設(shè)置,使用戶(hù)能夠選擇將NOTEXISTS運(yùn)算符轉(zhuǎn)換為NOTIN運(yùn)算符和/或?qū)⒃撜Z(yǔ)句轉(zhuǎn)換為外部連接。能夠指定ALL運(yùn)算符的重寫(xiě)優(yōu)先設(shè)置,使用戶(hù)選擇將該語(yǔ)句轉(zhuǎn)換為連接或外部連接。能夠指定NOTIN運(yùn)算符的重寫(xiě)優(yōu)先設(shè)置,使用戶(hù)能夠選擇將NOTIN運(yùn)算符轉(zhuǎn)換為NOTEXISTS運(yùn)算符將該語(yǔ)句轉(zhuǎn)換為外部連接。通過(guò)選擇某些選件,對(duì)轉(zhuǎn)換到外層的界面列規(guī)定為NOTNULL的事例進(jìn)行限制,用戶(hù)可以進(jìn)一步規(guī)定重寫(xiě)優(yōu)先設(shè)置。用戶(hù)也可以指定本系統(tǒng),如果需要,就對(duì)語(yǔ)句全都進(jìn)行轉(zhuǎn)換并增加ISNOTNULL準(zhǔn)則。用戶(hù)單擊優(yōu)先設(shè)置按鈕10時(shí),將顯示優(yōu)先設(shè)置窗口50,如圖4所示。然后,通過(guò)單擊調(diào)節(jié)器標(biāo)簽51,將顯示SQL調(diào)節(jié)器優(yōu)先設(shè)置頁(yè)52。這個(gè)窗口中的選件,使得用戶(hù)能夠?yàn)檫B接了運(yùn)算符ALL、NOTIN和NOTEXISTS的子查詢(xún)?cè)O(shè)置重寫(xiě)優(yōu)先設(shè)置,如前所述。在圖4所示的實(shí)例中,要為NOTEXISTS運(yùn)算符設(shè)置重寫(xiě)優(yōu)先設(shè)置,用戶(hù)就從下拉菜單53中選擇NOTEXISTS運(yùn)算符。這就顯示了對(duì)于NOTEXISTS運(yùn)算符可用的選件的列表。例如,然后通過(guò)對(duì)選件“通過(guò)NOTEXISTS運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到NOTIN”(復(fù)選框55)和“通過(guò)NOTEXISTS運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到外部連接”(復(fù)選框56)選擇或不選擇適當(dāng)?shù)膹?fù)選框,用戶(hù)可以指定是否使本系統(tǒng)能夠使用NOTIN和/或外部連接來(lái)轉(zhuǎn)換連接了NOTEXISTS運(yùn)算符的子查詢(xún)。如果選定了“通過(guò)NOTEXISTS運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到NOTIN”(復(fù)選框55)選件,選件框57和58變?yōu)榛罨?。選件框57使用戶(hù)選擇“對(duì)外部查詢(xún)的連接列檢驗(yàn)NOTNULL條件”選件,選件框58使用戶(hù)選擇“對(duì)子查詢(xún)的連接列檢驗(yàn)NOTNULL條件”選件。用戶(hù)分別通過(guò)選擇或不選擇復(fù)選框59和60,可以在這些選件中選擇一個(gè)或者兩個(gè)都選。然后,對(duì)于每個(gè)選定的選件框,轉(zhuǎn)換選件變?yōu)榛罨@?,分別通過(guò)單擊圓按鈕61和63,可以對(duì)外部查詢(xún)和子查詢(xún)選擇“僅當(dāng)列規(guī)定為NOTNULL時(shí)轉(zhuǎn)換”;分別通過(guò)單擊圓按鈕62和64,可以選擇“如果需要,全都轉(zhuǎn)換并增加“ISNOTNULL””。然后用戶(hù)可以單擊“OK”按鈕54以保存指定的優(yōu)先設(shè)置,并退出優(yōu)先設(shè)置窗口。選擇取消按鈕66會(huì)退出窗口52,但不保存對(duì)優(yōu)先設(shè)置所作的任何改變。選擇幫助按鈕65會(huì)向用戶(hù)顯示幫助菜單。以類(lèi)似的方式,要為ALL運(yùn)算符設(shè)置重寫(xiě)優(yōu)先設(shè)置,用戶(hù)就從下拉菜單53中選擇“ALL”運(yùn)算符以顯示選件列表。然后,將會(huì)為用戶(hù)提供某些選件,通過(guò)選擇或不選擇“通過(guò)ALL運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到連接或外部連接”選件,指定是否使本系統(tǒng)能夠把通過(guò)ALL運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到連接或外部連接。如果用戶(hù)選擇了這個(gè)選件,那么將會(huì)為用戶(hù)提供某些選件,“對(duì)外部查詢(xún)的連接列檢驗(yàn)NOTNULL條件”和“對(duì)子查詢(xún)的連接列檢驗(yàn)NOTNULL條件”。然后,用戶(hù)可以選擇這些選件中的一個(gè),或者兩個(gè)都選。然后,對(duì)于這些選定的選件中的每一個(gè),會(huì)為用戶(hù)提供兩個(gè)轉(zhuǎn)換選件,“僅當(dāng)列規(guī)定為NOTNULL時(shí)轉(zhuǎn)換”和“如果需要,全都轉(zhuǎn)換并增加“ISNOTNULL””。然后,用戶(hù)可以單擊“OK”按鈕54以保存指定的優(yōu)先設(shè)置,并退出優(yōu)先設(shè)置窗口。要為NOTIN運(yùn)算符設(shè)置重寫(xiě)優(yōu)先設(shè)置,用戶(hù)就從下拉菜單53中選擇NOTIN運(yùn)算符以顯示選件列表。然后用戶(hù)通過(guò)選擇或不選擇選件“通過(guò)NOTIN運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到NOTEXISTS”和“通過(guò)NOTIN運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換到外部連接”,可以指定是否使本系統(tǒng)能夠使用NOTEXISTS運(yùn)算符和/或外部連接來(lái)轉(zhuǎn)換由NOTIN運(yùn)算符連接的子查詢(xún)。對(duì)于每個(gè)選定的選件,然后為用戶(hù)提供一個(gè)選件,以便對(duì)外部查詢(xún)的連接列檢驗(yàn)NOTNULL條件和對(duì)子查詢(xún)的連接列檢驗(yàn)NOTNULL條件。用戶(hù)可以選擇這些選件中的一個(gè),或者兩個(gè)都選。然后,對(duì)于每個(gè)選定的選件,轉(zhuǎn)換選件變?yōu)榛罨?。換句話(huà)說(shuō),給用戶(hù)選擇權(quán),決定是僅當(dāng)列規(guī)定為NOTNULL時(shí)轉(zhuǎn)換,還是如果需要,全都轉(zhuǎn)換并增加“ISNOTNULL”。因此,用戶(hù)可以為外部查詢(xún)和/或子查詢(xún)的連接列選擇一個(gè)轉(zhuǎn)換選件。用戶(hù)單擊“OK”按鈕54以保存指定的優(yōu)先設(shè)置,并退出優(yōu)先設(shè)置窗口。退出優(yōu)先設(shè)置窗口之后,顯示返回選擇最優(yōu)化模式窗口11(圖3)。步驟S8完成之后,用戶(hù)對(duì)最優(yōu)化模式和優(yōu)先設(shè)置選擇滿(mǎn)意,通過(guò)單擊下一步按鈕8,就能繼續(xù)處理。在步驟S10中,本系統(tǒng)為了引用的完整性、外部連接和/或NULL邏輯問(wèn)題而檢驗(yàn)SQL語(yǔ)句。如果發(fā)現(xiàn)錯(cuò)誤或無(wú)效之處,就會(huì)顯示改動(dòng)該SQL語(yǔ)句以糾正這些問(wèn)題的特定建議。例如,對(duì)于非法的外部連接——它可能導(dǎo)致非法的結(jié)果集,可能會(huì)顯示建議。對(duì)于導(dǎo)致非法結(jié)果集的NULL邏輯問(wèn)題、HAVING子句的不正確使用、笛卡爾乘積、連接準(zhǔn)則中為了更好地使用索引的表達(dá)式、非連接準(zhǔn)則中為了更好地使用索引的表達(dá)式以及沒(méi)有索引的外關(guān)鍵字等等,也可能顯示建議。然后在步驟S12中,向用戶(hù)顯示檢驗(yàn)SQL窗口70,如圖5所示。窗口部分73顯示了該語(yǔ)句中每個(gè)子查詢(xún)的圖示。SQL語(yǔ)句中的每個(gè)表格顯示為一個(gè)框,其頭部包含著表格的名稱(chēng)和別名。對(duì)每個(gè)表格也顯示主關(guān)鍵字、外關(guān)鍵字和獨(dú)特外關(guān)鍵字。表格之間的一條綠線(xiàn)表示正確的連接。如果一條紅線(xiàn)連接著表格,該連接包含著某個(gè)錯(cuò)誤(比如違背了引用的完整性或者不適當(dāng)?shù)耐獠窟B接)。如果一條藍(lán)線(xiàn)連接著表格,該連接由于缺乏引用的完整性而是無(wú)效的。對(duì)SQL語(yǔ)句建議的改正顯示在窗口部分71中。用戶(hù)可以按照需要調(diào)整檢驗(yàn)SQL窗口70的尺寸,以觀察任何窗口部分中包含的所有信息。單擊“下一個(gè)SQL模塊”按鈕72和前一個(gè)SQL模塊”按鈕74,會(huì)選中藍(lán)色SQL語(yǔ)句中的各個(gè)子查詢(xún),并且僅僅顯示與選中子子查詢(xún)相關(guān)聯(lián)的圖示。然后用戶(hù)可以決定(步驟S14)要調(diào)節(jié)哪個(gè)SQL語(yǔ)句,原始語(yǔ)句或者修改后的語(yǔ)句。例如,單擊“調(diào)節(jié)原始SQL”按鈕76,會(huì)調(diào)節(jié)在檢驗(yàn)SQL窗口70底部區(qū)域75中顯示的原始SQL語(yǔ)句。單擊“調(diào)節(jié)修改后SQL”按鈕78,會(huì)執(zhí)行檢驗(yàn)SQL窗口70右側(cè)區(qū)域71中顯示的、建議的改正,然后調(diào)節(jié)改正后的SQL語(yǔ)句。在步驟S16中,通過(guò)執(zhí)行一個(gè)或多個(gè)步驟使語(yǔ)句最優(yōu)化,調(diào)節(jié)選定的SQL語(yǔ)句。例如,系統(tǒng)可以在連接準(zhǔn)則中作出傳遞性的改變,可以確定所有的子查詢(xún)變換,可以確定需要時(shí)非連接準(zhǔn)則中的傳遞性,可以確定連接次序。系統(tǒng)可以產(chǎn)生幾個(gè)變換后的SQL語(yǔ)句。然后系統(tǒng)可以確定哪個(gè)變換后的SQL語(yǔ)句具有最佳的性能,并以此對(duì)結(jié)果SQL語(yǔ)句排序。調(diào)節(jié)或變化一個(gè)SQL語(yǔ)句時(shí),如果需要,本系統(tǒng)可以檢驗(yàn)?zāi)硞€(gè)周?chē)樵?xún)的若干列是否屬于同一表格并作出傳遞性的改變。如果它們不屬于同一表格,系統(tǒng)就檢驗(yàn)是否有任何連接準(zhǔn)則引用了連接子查詢(xún)的一列,并確認(rèn)等價(jià)列。本系統(tǒng)對(duì)連接子查詢(xún)的每一列都這樣做,然后在一次操作中使用傳遞性質(zhì)來(lái)產(chǎn)生等價(jià)列的置換,以發(fā)現(xiàn)其中所有列都屬于同一表格的一個(gè)組。本系統(tǒng)對(duì)通過(guò)NOTIN運(yùn)算符連接的、非關(guān)聯(lián)的子查詢(xún)和與NOTIN、NOTEXISTS或ALL運(yùn)算符連接的、關(guān)聯(lián)的子查詢(xún),都可以作出傳遞性的改變。本系統(tǒng)通過(guò)評(píng)價(jià)每個(gè)子查詢(xún)和為每個(gè)變換分配一個(gè)等級(jí),也可以確定對(duì)SQL語(yǔ)法所進(jìn)行的所有子查詢(xún)變換。變換可以是強(qiáng)制的(全部或絕不),也可以是任選的。然后,這種信息用于產(chǎn)生多種不同的SQL版本。例如,SQL語(yǔ)句包含四個(gè)子查詢(xún)時(shí),本系統(tǒng)可能不把任何一個(gè)子查詢(xún)分配為“全都變換”等級(jí),把一個(gè)分配為“絕不變換”等級(jí),而把三個(gè)分配為“任選”等級(jí),以產(chǎn)生可能的替代SQL語(yǔ)句。換句話(huà)說(shuō),變換的類(lèi)型決定了該變換是否應(yīng)當(dāng)全都進(jìn)行、絕不進(jìn)行或者可選地進(jìn)行。例如,某些變換可能是需要的,因?yàn)檫M(jìn)行變換之后優(yōu)化器將使用更好的方案。在這種情況下,變換應(yīng)當(dāng)全都進(jìn)行。所以,該變換會(huì)分配給最高的等級(jí)。某些變換可能是不需要的,由于進(jìn)行變換之后優(yōu)化器將使用效率更低的方案。在這種情況下,該變換不應(yīng)當(dāng)進(jìn)行。所以,該變換會(huì)分配給最低的等級(jí)。某些變換被選用后可能會(huì)也可能不會(huì)產(chǎn)生更好的最優(yōu)化方案,由于它可能還取決于其它因素。在這種情況下,該變換可以是可選地進(jìn)行。所以,該變換會(huì)分配給中間的等級(jí)。進(jìn)行了子查詢(xún)變換之后,本系統(tǒng)確認(rèn)非連接準(zhǔn)則中的等價(jià)列——它們能夠相互替換——并進(jìn)行替換。這樣做使本系統(tǒng)能夠重寫(xiě)SQL語(yǔ)句,讓數(shù)據(jù)庫(kù)(比如ORACLE)利用連接的關(guān)鍵字索引。例如,在下列SQL語(yǔ)句中,對(duì)DEPENDENTS子查詢(xún)的e.emp_seq準(zhǔn)則能夠連接到a.emp_seq或t.emp_seq。SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDe.emp_seqIN(SELECTemp_seqFROMdependentsWHERErelation=‘SPOUSE’)如下(第5行)所示,把e.emp_seq轉(zhuǎn)換到a.emp_seq使數(shù)據(jù)庫(kù)能夠使用連接到ASSIGNMENTS的關(guān)鍵字索引SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDa.emp_seqIN(SELECTemp_seqFROMdependentsWHERErelation=‘SPOUSE’)在等價(jià)列中存在著等價(jià)連接準(zhǔn)則時(shí),不同的列都能夠替換另一列。不過(guò),本系統(tǒng)也可以使用同連接準(zhǔn)則相與的非連接準(zhǔn)則的傳遞性。如果非連接準(zhǔn)則是同連接準(zhǔn)則相或,就不應(yīng)當(dāng)使用它產(chǎn)生的傳遞性。如果某個(gè)多列運(yùn)算對(duì)象具有傳遞性,本系統(tǒng)對(duì)該運(yùn)算對(duì)象增加若干列,并將相應(yīng)的列復(fù)制到選擇列表。所有的多列傳遞性都用于每個(gè)變換,原始語(yǔ)句除外。如果運(yùn)算對(duì)象通過(guò)某個(gè)外部連接的準(zhǔn)則等價(jià)于另一列,不能使用等價(jià)列。如果某個(gè)FROM子句具有嵌套選擇語(yǔ)句——它不具有GROUPBY語(yǔ)法或聚集——并且主查詢(xún)具有引用主查詢(xún)和嵌套選擇之間連接列之一的非連接準(zhǔn)則,本系統(tǒng)就在該SQL語(yǔ)句的所有拷貝中,復(fù)制嵌套選擇語(yǔ)句中的非連接準(zhǔn)則,包括原始語(yǔ)句。本系統(tǒng)能夠使用一種ORDERED線(xiàn)索來(lái)確定連接次序。這種ORDERED線(xiàn)索迫使優(yōu)化器依照表格在SQL語(yǔ)句中的FROM子句中出現(xiàn)的次序連接表格。這就使得寫(xiě)入的SQL語(yǔ)句以特定的次序連接FROM子句中引用的表格。系統(tǒng)首先不使用ORDERED線(xiàn)索來(lái)測(cè)試SQL語(yǔ)句。然后,本系統(tǒng)使用ORDERED線(xiàn)索來(lái)產(chǎn)生另外的置換,具有不同的驅(qū)動(dòng)表格,以強(qiáng)制實(shí)現(xiàn)某種特定的連接次序——驅(qū)動(dòng)表格是例如嵌套的循環(huán)連接運(yùn)算中的某個(gè)父表格。驅(qū)動(dòng)表格中的每一行都能夠用于在連接的表格中發(fā)現(xiàn)匹配的行以完成連接運(yùn)算。如果變換后SQL語(yǔ)句的默認(rèn)連接比原始的SQL語(yǔ)句具有更好的成本/行值,那么最可能的情況是,ORDERED線(xiàn)索將產(chǎn)生一個(gè)比利用默認(rèn)連接次序的初始變換效率更高的方案但是成本也更高的行。本系統(tǒng)能夠顯示ORDERED變換,作為一種可行的最佳解決方案。為了從產(chǎn)生的不同SQL語(yǔ)句中的每一個(gè)中確定最佳性能,本系統(tǒng)對(duì)原始的SQL語(yǔ)句和重寫(xiě)過(guò)程產(chǎn)生的每個(gè)SQL語(yǔ)句產(chǎn)生一種成本統(tǒng)計(jì)數(shù)據(jù)。在產(chǎn)生了與該SQL語(yǔ)句相關(guān)聯(lián)的方案后,確定成本。例如,Oracle的EXPLAINPLAN語(yǔ)句,可以用于產(chǎn)生優(yōu)化器執(zhí)行該SQL語(yǔ)句所用的方案。該EXPLAINPLAN語(yǔ)句能夠?qū)υ揝QL語(yǔ)句運(yùn)行以獲得執(zhí)行方案,其中描述了優(yōu)化器執(zhí)行該SQL語(yǔ)句時(shí)計(jì)劃要使用的步驟。Oracle也會(huì)為該方案中的每一步驟提供一個(gè)數(shù)字(如成本)。該成本是執(zhí)行方案中該步驟的一個(gè)相對(duì)數(shù)字。對(duì)于該方案中的所有步驟,可以對(duì)成本求和以獲得該方案的總成本。本系統(tǒng)能夠?qū)?shù)據(jù)庫(kù)算出的成本除以行數(shù),對(duì)每個(gè)SQL語(yǔ)句產(chǎn)生成本/行值。根據(jù)該方案需要的邏輯讀的數(shù)目,也可以確定成本。確定了成本之后,本系統(tǒng)以上升的次序(從最低到最高成本)對(duì)SQL語(yǔ)句進(jìn)行排序。在步驟18中,本系統(tǒng)在結(jié)果對(duì)話(huà)窗口90中,顯示原始的SQL語(yǔ)句和成本最低的SQL語(yǔ)句,如圖6所示。原始的SQL語(yǔ)句顯示在窗口部分92中,建議的修改SQL語(yǔ)句顯示在窗口部分94中。然后,用戶(hù)可以比較建議的修改SQL語(yǔ)句和原始的SQL語(yǔ)句,觀察變化,然后選擇他們是否想要以調(diào)節(jié)后的SQL語(yǔ)句替換原始的SQL語(yǔ)句。然后單擊替換SQL按紐100,就會(huì)以窗口94所示的、建議的修改SQL語(yǔ)句替換原始的SQL語(yǔ)句。系統(tǒng)在編輯或者說(shuō)調(diào)節(jié)窗口104中,增加注釋并顯示調(diào)節(jié)后的SQL語(yǔ)句,如圖7所示。如圖7所示,注釋可能包括日期標(biāo)志、表明語(yǔ)句已經(jīng)調(diào)節(jié)和標(biāo)識(shí)所用最優(yōu)化模式(在這個(gè)實(shí)例中是ALL_ROWS)的信息。單擊后退按鈕96返回前一個(gè)窗口。單擊更多細(xì)節(jié)按鈕98打開(kāi)詳細(xì)結(jié)果窗口106,如圖8所示。調(diào)節(jié)后的SQL語(yǔ)句顯示在窗口部分108中。行110顯示了原始的SQL語(yǔ)句的成本統(tǒng)計(jì)項(xiàng)目,一個(gè)或多個(gè)行112顯示了調(diào)節(jié)改變后的SQL語(yǔ)句的成本統(tǒng)計(jì)數(shù)據(jù)。統(tǒng)計(jì)項(xiàng)目可能包括占用時(shí)間114——執(zhí)行該SQL需要的時(shí)間量(以秒記)、CPU時(shí)間116——執(zhí)行該SQL需要的每秒的CPU周期數(shù)目、邏輯讀取118——執(zhí)行該SQL需要的邏輯讀取的數(shù)目、實(shí)際讀取120——執(zhí)行該SQL需要的實(shí)際讀取的數(shù)目、行數(shù)122——SQL返回的行數(shù)以及成本/行數(shù)124——數(shù)據(jù)庫(kù)的成本除以行數(shù)。詳細(xì)結(jié)果窗口106使用戶(hù)能夠觀察每個(gè)語(yǔ)句的成本統(tǒng)計(jì)數(shù)據(jù),以幫助用戶(hù)選擇最適合其需要的SQL。在包括編輯器功能的系統(tǒng)中,用戶(hù)也可以選擇打開(kāi)調(diào)節(jié)后的語(yǔ)句,以進(jìn)行進(jìn)一步的編輯。如果在SQL中有某個(gè)結(jié)合變量,單擊“結(jié)合”按紐126就會(huì)顯示一個(gè)對(duì)話(huà)框,在執(zhí)行該SQL語(yǔ)句之前,用戶(hù)能夠在其中為該變量指定一個(gè)數(shù)值。單擊“執(zhí)行”按紐128會(huì)產(chǎn)生選定語(yǔ)句的統(tǒng)計(jì)數(shù)據(jù)。單擊“全部執(zhí)行”按紐130會(huì)產(chǎn)生列出的所有SQL語(yǔ)句的統(tǒng)計(jì)數(shù)據(jù)。用戶(hù)可以單擊“打印”按紐132來(lái)打印當(dāng)前在窗口中顯示的信息。用戶(hù)可以單擊“保存”按紐134把這個(gè)窗口中的信息保存為文本文件,以便將來(lái)引用。用戶(hù)可以在表格中選擇另外的SQL條目,單擊“PAFO”(為Oracle的方案分析器)按紐138在方案窗口中顯示代碼。單擊“替換SQL”按紐140,以調(diào)節(jié)后的SQL替換原始的SQL。單擊“后退”按紐136返回結(jié)果窗口90(圖6)。單擊“取消”按紐144退出本系統(tǒng)而不改變?cè)嫉腟QL。以下說(shuō)明列出并介紹了多種術(shù)語(yǔ)——本說(shuō)明書(shū)自始至終使用這些術(shù)語(yǔ)來(lái)引用SQL語(yǔ)句的部分或?qū)傩浴约氨鞠到y(tǒng)為調(diào)節(jié)SQL語(yǔ)句所用的某些概念。本說(shuō)明書(shū)自始至終使用這些術(shù)語(yǔ)來(lái)介紹本系統(tǒng)調(diào)節(jié)SQL語(yǔ)句所用的算法。A.分支和嵌套當(dāng)某個(gè)查詢(xún)具有子查詢(xún)時(shí),從頂端(主查詢(xún))到底部的路徑為一“分支”?!扒短椎募?jí)別”是分支中子查詢(xún)的數(shù)目。主查詢(xún)被視為處于“級(jí)別”=1。直接在它下面的子查詢(xún)處于“級(jí)別”=2,依此類(lèi)推??紤]以下的SQL,為了易于引用,已經(jīng)加上了行號(hào)。1.SELECT*FROMemployees2.WHEREemp_seqIN3.(SELECTemp_seq4.FROMtime_sheetst5.WHEREt.rpt_date=‘01-MAY-98’6.ANDt.proj_seq=7.(SELECTproj_seqFROMprojects8.WHEREname=‘EXPLAINSQLDEVELOPMENT’))9.ANDhiredate>SYSDATE-10分支從主查詢(xún)LEVEL=1(從第1行開(kāi)始)延伸到LEVEL=2(從第3行開(kāi)始),再到LEVEL=3最后的子查詢(xún)(從第7行開(kāi)始)。在這個(gè)實(shí)例中,“嵌套的級(jí)別”為2,因?yàn)橹鞑樵?xún)具有一個(gè)子查詢(xún),這個(gè)子查詢(xún)又有一個(gè)子查詢(xún)。以下SQL語(yǔ)句包含兩個(gè)分支1.SELECT*FROMemployees2.WHEREemp_seqIN3.(SELECTemp_seq4.FROMtimesheetst5.WHEREt.rpt_date=‘01-MAY-98’6.ANDt.proj_seq=7.(SELECTproj_seqFROMprojects8.WHEREname=‘EXPLAINSQLDEVELOPMENT’))9.ANDhiredate>SYSDATE-1010.ANDemp_seqIN11.(SELECTemp_seqFROMdependents12.WHEREbirthdate>‘01-JAN-67’)這個(gè)SQL語(yǔ)句的第一個(gè)分支與前一個(gè)實(shí)例相同。不過(guò),這個(gè)SQL語(yǔ)句還具有第二個(gè)分支。主查詢(xún)(從第1行開(kāi)始)為第1級(jí)別。第2級(jí)別從11行開(kāi)始。這個(gè)第二分支的嵌套級(jí)別等于1。B.最頂端的父級(jí)布爾運(yùn)算符當(dāng)WHERE子句中存在OR運(yùn)算符時(shí),在合并或者將某個(gè)子查詢(xún)移入FROM子句之前,應(yīng)當(dāng)謹(jǐn)慎。如果OR是父級(jí)布爾運(yùn)算符,就不應(yīng)當(dāng)進(jìn)行合并或移動(dòng)。以下的事例說(shuō)明了這一點(diǎn)。對(duì)于SQL語(yǔ)句SELECTe.emp_seqFROMemployeeseWHEREhiredate>SYSDATE-155ORemp_seqIN(SELECTemp_seqFROMassignmentsWHEREproj_seq=1)如果我們不考慮OR運(yùn)算符,子查詢(xún)可以合并如下SELECTe.emp_seq,x.emp_seqFROMemployeese,(SELECTemp_seqFROMassignmentsWHEREproj_seq=1)xWHEREe.hiredate>SYSDATE-155ORe.emp_seq=x.emp_seq不過(guò),在子查詢(xún)中沒(méi)有連接的行時(shí),這項(xiàng)連接現(xiàn)在將變?yōu)榈芽柍朔e。例如,當(dāng)準(zhǔn)則“e.emp_seq=x.emp_seq”求值為FALSE,但是非連接準(zhǔn)則求值為T(mén)RUE時(shí),無(wú)論如何來(lái)自子查詢(xún)的行都將被連接。對(duì)于這個(gè)特定的EMPLOYEES行,無(wú)論連接來(lái)自子查詢(xún)的哪一行,非連接準(zhǔn)則將永遠(yuǎn)求值為T(mén)RUE。這就產(chǎn)生了笛卡爾乘積。以下實(shí)例說(shuō)明了當(dāng)準(zhǔn)則前面有NOT時(shí),這個(gè)問(wèn)題可能會(huì)變得更加困難。例如,給定SQL語(yǔ)句SELECTe.emp_seqFROMemployeeseWHERENOT(hiredate>SYSDATE-155ORemp_seqIN(SELECTemp_seqFROMassignmentsWHEREproj_seq=1))使用DeMorgan規(guī)則,NOT反轉(zhuǎn)括號(hào)內(nèi)的布爾和關(guān)系運(yùn)算符。不過(guò),本系統(tǒng)可以使用使用DeMorgan規(guī)則消除NOT運(yùn)算符,得出以下SQL。反轉(zhuǎn)的布爾和關(guān)系運(yùn)算符有下劃線(xiàn)。進(jìn)行反轉(zhuǎn)首先可能簡(jiǎn)化了該過(guò)程。SELECTe.emp_seqFROMemployeeseWHEREhiredate<=SYSDATE-155ANDemp_seqNOTIN(SELECTemp_seqFROMassignmentsWHEREproj_seq=1)C.關(guān)聯(lián)到多個(gè)SQL模塊關(guān)聯(lián)的子查詢(xún)能夠被關(guān)聯(lián)到多于一個(gè)SQL模塊,如以下實(shí)例所示1.SELECT*FROMemployeese2.WHEREEXISTS3.(SELECTnullFROMassignmentsa4.WHEREa.emp_seq=e.emp_seq5.ANDEXISTS6.(SELECTnullFROMtime_sheetst7.WHEREt.emp_seq=e.emp_seq8.ANDt.proj_seq=a.proj_seq))對(duì)TIME_SHEETS(第6行)的子查詢(xún)(通過(guò)第7行)既關(guān)聯(lián)到外層的(對(duì)ASSIGNMENTS的)查詢(xún),又(通過(guò)第8行)關(guān)聯(lián)到對(duì)EMPLOYEES的主查詢(xún)。D.關(guān)聯(lián)準(zhǔn)則在上面的SQL語(yǔ)句中,第7行和第8行的準(zhǔn)則稱(chēng)為“關(guān)聯(lián)準(zhǔn)則”。這些準(zhǔn)則不是“連接準(zhǔn)則”,但是在子查詢(xún)執(zhí)行時(shí)引用查詢(xún)外部(比如“e.emp_seq”或“a.proj_seq”)像是常數(shù)的意義上,更像“非連接準(zhǔn)則”。在例程中可以檢驗(yàn)關(guān)聯(lián)準(zhǔn)則,以確保它們是用等價(jià)運(yùn)算符。不過(guò)應(yīng)當(dāng)注意,以這種方式檢驗(yàn)的關(guān)聯(lián)準(zhǔn)則應(yīng)當(dāng)是對(duì)應(yīng)于包括某個(gè)獨(dú)特索引的若干列。例如,以下查詢(xún)?cè)谧硬樵?xún)中具有兩個(gè)關(guān)聯(lián)準(zhǔn)則。不過(guò),有影響的只有一個(gè),即對(duì)于PROJ_SEQ的一個(gè),由于它是具有獨(dú)特索引的列。SELECT*FROMassignmentsaWHEREEXISTS(SELECTstart_dateFROMprojectspWHEREa.proj_seq=p.proj_seqANDa.start_date<p.start_date)E.非連接準(zhǔn)則在SQL語(yǔ)句中,下面的代碼引用某個(gè)非連接準(zhǔn)則時(shí),它要尋找的準(zhǔn)則為關(guān)系運(yùn)算符是而且另一個(gè)運(yùn)算對(duì)象或者是一個(gè)常數(shù)或者是一個(gè)子查詢(xún)。對(duì)于子查詢(xún)的這種假設(shè)是,由于用戶(hù)指定了作為關(guān)系運(yùn)算符,子查詢(xún)必須返回最多一個(gè)單行,這意味著一個(gè)常數(shù)。以下是非法WHERE子句的實(shí)例WHEREcol1=10+col2WHEREcol1>10以下是合法WHERE子句的實(shí)例WHEREcol1=lOWHEREcol1=(selectco12fromtabl)WHEREcol1=:Bind_VariableF.連接準(zhǔn)則下面引用連接準(zhǔn)則。在每種情況下,關(guān)系運(yùn)算符都應(yīng)當(dāng)是并且準(zhǔn)則的每一側(cè)都應(yīng)當(dāng)是單列的名稱(chēng),而不應(yīng)當(dāng)是表達(dá)式。G.子查詢(xún)接口典型情況下,外層查詢(xún)和子查詢(xún)之間的接口包含至少一個(gè)“關(guān)系運(yùn)算符”比如“IN”、“=”、“NOTEXISTS”等等。除了EXISTS和NOTEXISTS關(guān)系運(yùn)算符以外,所有關(guān)系運(yùn)算符之前都是一列或多列。運(yùn)算符之前的列稱(chēng)為“接口列”。在子查詢(xún)的對(duì)應(yīng)SELECT列表中的列也被稱(chēng)為“接口列”。根據(jù)它們是外層查詢(xún)的接口列還是子查詢(xún)的接口列,能夠區(qū)分這兩種類(lèi)型的“接口列”。這些列也可能不屬于子查詢(xún)之內(nèi)的對(duì)象,并且不與屬于子查詢(xún)內(nèi)表格的任何列關(guān)聯(lián),如以下代碼所示1.SELECT*FROMemployeese2.WHEREemp_seqIN3.(SELECTemp_seqFROMassignmentsa4.WHERE(e.hiredate,a.proj_seq)IN5.(SELECTrpt_date,proj_seqFROMtime_sheetst))列“e.hiredate”(第4行)不屬于子查詢(xún)(ASSIGNMENTS表格),并且不與ASSIGNMENTS內(nèi)的任何列關(guān)聯(lián)。本文檔將稱(chēng)外層查詢(xún)的這些列為“外來(lái)的”。如果某列是外來(lái)的,系統(tǒng)將試圖把它合并或者將它轉(zhuǎn)換到一個(gè)非關(guān)聯(lián)的子查詢(xún)。不過(guò),系統(tǒng)將不試圖移動(dòng)該子查詢(xún)。H.優(yōu)先設(shè)置變換SQL語(yǔ)句時(shí),空邏輯會(huì)引起許多問(wèn)題。如果在外層查詢(xún)中特定的列可為空,變換時(shí)可能出現(xiàn)不同的結(jié)果集。可以對(duì)變換進(jìn)行修改以確保不發(fā)生這樣的情況,盡管從性能上說(shuō)可能會(huì)付出某個(gè)小的代價(jià)。修改就是同某個(gè)準(zhǔn)則進(jìn)行與運(yùn)算,指定該列不可為空(如列ISNOTNULL)。由于對(duì)滿(mǎn)足原始準(zhǔn)則的每一行,該準(zhǔn)則必然成立,所以代價(jià)不會(huì)大。相反,在某些情況下性能還可能改善,因?yàn)檫@時(shí)優(yōu)化器比如ORACLE的優(yōu)化器就可能執(zhí)行一個(gè)反連接。在下面的算法中將會(huì)引用這些優(yōu)先設(shè)置。I.別名子查詢(xún)合并或移動(dòng)到FROM子句時(shí),外層查詢(xún)中的準(zhǔn)則應(yīng)當(dāng)通過(guò)某個(gè)別名被完全識(shí)別,例如,參見(jiàn)以下的實(shí)例。1.SELECT*FROMemployees2.WHEREemp_seqIN3.(SELECTemp_seq4.FROMtime_sheetst,projectsp5.WHEREt.rpt_date=‘01-MAY-98’6.ANDt.proj_seq=p.proj_seq7.ANDp.stop_dateISNULL)8.ANDhiredate>SYSDATE-10在這個(gè)實(shí)例中,應(yīng)當(dāng)為EMPLOYEES增加一個(gè)別名,而且該別名應(yīng)當(dāng)在屬于該表格的所有列之前。此外,子查詢(xún)也應(yīng)當(dāng)給予一個(gè)別名。為EMPLOYEES增加一個(gè)“e”別名,那么變換會(huì)是SELECTe.*FROMemployeese,(SELECTemp_seqFROMtime_sheetst,projectspWHEEREt.rpt_date=‘01-MAY-98’ANDt.proj_seq=p.proj_seqANDp.stop_dateISNULL)xWHEREe.emp_seq=x.emp_seqANDe.hiredate>SYSDATE-10如果某個(gè)子查詢(xún)包含聚集,在它被移進(jìn)FROM子句之前,應(yīng)當(dāng)給它一個(gè)別名。例如,以下的SQL語(yǔ)句在子查詢(xún)(第3行)中包含“max”聚集函數(shù)。1.SELECT*FROMsal_history2.WHERE(emp_seq,effective_date)IN3.(SELECTemp_seq,max(effective_date)4.FROMsal_history5.GROUPBYemp_seq)因此,該SQL語(yǔ)句應(yīng)當(dāng)進(jìn)行變換,給予聚集“MAX(EFFECTIVE_DATE)”一個(gè)別名如下SELECTs.*FROMsal_historys,(SELECTemp_seq,max(effective_date)clFROMsal_historyGROUPBYemp_seq)xWHEREs.emp_seq=x.emp_seqANDs.effective_date=x.c1這就產(chǎn)生了一個(gè)問(wèn)題,是否允許用戶(hù)通過(guò)隱含的知識(shí),為已知要返回獨(dú)特集合的子查詢(xún)?cè)O(shè)置旗標(biāo)。例如,SELECT*FROMemployeeseWHEREEXISTS(SELECTnullFROMprojectsp,assignmentsaWHEREp.proj_seq=a.proj_seqANDa.emp_seq=e.emp_seqANDp.name=‘EXPLAIN_SQL’)能夠轉(zhuǎn)換為SELECT*FROMemployeeseWHEREe.emp_seqIN(SELECTa.emp_seqFROMprojectsp,assignmentsaWHEREp.proj_seq=a.proj_seqANDp.name=‘EXPLAIN_SQL’)或者轉(zhuǎn)換為SELECTe.*FROMemployeese,projectsp,assignmentsaWHEREe.emp_seq=a.emp_seqANDp.proj_seq=a.proj_seqANDp.name=‘EXPLAIN_SQL’這兩種情況都是可能的,因?yàn)樽硬樵?xún)中低級(jí)別的表格在PROJ_SEQ和EMP_SEQ上都有PK。傳遞性允許我們說(shuō),因?yàn)镹AME——它也有一個(gè)UNQ索引——上的等價(jià),在PROJ_SEQ上有等價(jià)。所以,保證了子查詢(xún)每一EMPLOYEES行產(chǎn)生一行,這表明合并是可能的。既然已經(jīng)解釋了本系統(tǒng)所用的某些術(shù)語(yǔ)和概念,以下的實(shí)例就有助于介紹本系統(tǒng)變換SQL語(yǔ)句可能使用的算法。顯示的實(shí)例分為關(guān)聯(lián)的和非關(guān)聯(lián)的子查詢(xún),并以此識(shí)別。非關(guān)聯(lián)的子查詢(xún)是不與主查詢(xún)關(guān)聯(lián)的子查詢(xún)。也就是,在主查詢(xún)考察任何行之前,就可以邏輯地執(zhí)行非關(guān)聯(lián)的子查詢(xún)。換句話(huà)說(shuō),子查詢(xún)與主查詢(xún)獨(dú)立,并且可以作為有其本身答案的一個(gè)查詢(xún)而存在。與之相反,關(guān)聯(lián)的子查詢(xún)依賴(lài)于被主查詢(xún)考察的行。1.以下SQL語(yǔ)句混合了關(guān)聯(lián)的和非關(guān)聯(lián)的子查詢(xún)。在以下的SQL語(yǔ)句中,最后的子查詢(xún)是一個(gè)標(biāo)量子查詢(xún),并且由于外層子查詢(xún)對(duì)PROJ_SEQ和RPT_DATE都有等價(jià)準(zhǔn)則,而且EMP_SEQ列在選擇列表上,該子查詢(xún)能夠合并,盡管對(duì)SAL_HISTORY的子查詢(xún)不能。對(duì)于FROM子句中的嵌套查詢(xún)是否正確地識(shí)別為標(biāo)量,這是一個(gè)很好的試驗(yàn)。SELECT*FROMemployeesWHEREemp_seqIN(SELECTemp_seqFROMtime_sheetstWHEREproj_seq=(SELECTproj_seqFROMprojectsWHEREname=‘EXPLAINSQLDEVELOPMENT’)ANDrpt_date=(SELECTMAX(effective_date)FROMsal_historysWHEREs.emp_seq=t.emp_seq))應(yīng)當(dāng)變換為SELECTe.*FROMemployeese,time_sheetst,projectsp,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historysGROUPBYemp_seq)xWHEREe.emp_seq=t.emp_seqANDt.proj_seq=p.proj_seqANDp.name=‘EXPLAINSQLDEVELOPMENT’ANDt.emp_seq=x.emp_seqANDt.rpt_date=x.col12.以下實(shí)例是非關(guān)聯(lián)的,并且與前一個(gè)實(shí)例略有不同。基本的差異是對(duì)SAL_HISTORY的子查詢(xún)。在這種情況下該子查詢(xún)初始確定為可能返回多行。這表明在原始查詢(xún)中可能發(fā)生運(yùn)行錯(cuò)誤。這就防止了合并和移動(dòng)該子查詢(xún)。也就是,對(duì)SAL_HISTORY上的子查詢(xún)應(yīng)當(dāng)保持原樣。不過(guò),由于對(duì)RPT_DATE的準(zhǔn)則具有等價(jià)運(yùn)算符,該子查詢(xún)與TIME_SHEETS的合并仍然能夠發(fā)生,并且仍然可能遇到同樣的運(yùn)行錯(cuò)誤。換句話(huà)說(shuō),將不移動(dòng)對(duì)SAL_HISTORY的子查詢(xún),因?yàn)椴荒鼙WC產(chǎn)生標(biāo)量集。不過(guò),在能產(chǎn)生標(biāo)量集的情況下,對(duì)準(zhǔn)則“rpt_date=___”將產(chǎn)生一個(gè)單一的常數(shù)值。本系統(tǒng)將該子查詢(xún)視為等價(jià)于一個(gè)常數(shù),允許外層查詢(xún)與其圍繞的查詢(xún)合并并攜帶著嵌套的選擇。例如,以下SQL語(yǔ)句,SELECT*FROMemployeesWHEREemp_seqIN(SELECTemp_seqFROMtime_sheetstWHEREproj_seq=(SELECTproj_seqFROMprojectsWHEREname=‘EXPLAINSQLDEVELOPMENT’)ANDrpt_date=(SELECTeffective_dateFROMsal_historysWHEREsal>100)應(yīng)當(dāng)變換為SELECTe.*FROMemployeese,time_sheetst,projectspWHEREe.emp_seq=t.emp_seqANDt.proj_seq=p.proj_seqANDp.name=‘EXPLAINSQLDEVELOPMENT’ANDt.rpt_date=(SELECTeffective_dateFROMsal_historysWHEREsal>100)3.以下實(shí)例是關(guān)聯(lián)的,并且涉及ALL運(yùn)算符。如果某個(gè)子查詢(xún)不返回任何行,該準(zhǔn)則可能取值為T(mén)RUE。這表明該子查詢(xún)僅僅應(yīng)當(dāng)移動(dòng),并且作為外部連接而進(jìn)行,其中僅有外部連接的語(yǔ)法僅僅應(yīng)用于初始關(guān)聯(lián)準(zhǔn)則。進(jìn)行比較的原始列必須不考慮連接匹配。在外部連接發(fā)生之后,對(duì)增加的最后準(zhǔn)則進(jìn)行求值。例如,以下SQL語(yǔ)句,SELECTemp_seq,birthdateFROMemployeeseWHEREbirthdate<ALL(SELECTbirthdateFROMdependentsdWHEREe.emp_seq=d.emp_seq)能夠變換為SELECTe.emp_seq,e.birthdateFROMemployeese,(SELECTd.emp_seq,MIN(birthdate)col1,1col2FROMdependentsdGROUPBYemp_seq)xWHEREe.emp_seq=x.emp_seq(+)AND(e.birthdate<x.col1ORx.col2ISNULL)系統(tǒng)應(yīng)當(dāng)檢驗(yàn)確定任何新的外部連接的準(zhǔn)則是否與任何運(yùn)算對(duì)象進(jìn)行或運(yùn)算,因?yàn)檫@會(huì)產(chǎn)生分析錯(cuò)誤??赡苄枰箶?shù)據(jù)庫(kù)分析中間結(jié)果以判斷是否應(yīng)當(dāng)進(jìn)行過(guò)變換。如果不應(yīng)當(dāng)進(jìn)行過(guò)變換,那么對(duì)該子查詢(xún)就不應(yīng)當(dāng)進(jìn)行任何處理。4.以下實(shí)例是非關(guān)聯(lián)的,并且涉及具有GROUPBY語(yǔ)法的子查詢(xún)。即使子查詢(xún)具有GROUPBY子句,SELECT列表也不包含GROUPBY列表中的每一列。這表明復(fù)制的可能性不存在,除非DISTINCT關(guān)鍵字增加到該子查詢(xún)的SELECT列表。例如,以下SQL語(yǔ)句,SELECT*FROMemployeesWHEREemp_seqIN(SELECTemp_seqFROMassignmentsGROUPBYemp_seq,proj_seq)能夠變換為SELECTe.*FROMemployeese,(SELECTDISTINCTa.emp_seqFROMassignmentsaGROUPBYa.emp_seq,a.proj_seq)xWHEREe.emp_seq=x.emp_seq5.SQL語(yǔ)句可能僅僅包含聚集,而不包含GROUPBY子句。所以,它不需要DISTINCT關(guān)鍵字。以下實(shí)例是非關(guān)聯(lián)的。例如,以下SQL語(yǔ)句,SELECT*FROMemployeesWHEREhiredate=(SELECTMIN(effective_date)FROMsal_history)能夠變換為SELECTe.*FROMemployeese,(SELECTMIN(s.effective_date)col1FROMsal_historys)xWHEREe.hiredate=x.col16.以下實(shí)例是非關(guān)聯(lián)的,并且說(shuō)明了移動(dòng)到外層查詢(xún)時(shí)如何處理NOTIN運(yùn)算符?;疽c(diǎn)在于,系統(tǒng)應(yīng)當(dāng)轉(zhuǎn)換到外部連接,然后尋找“外部連接的行”(如子查詢(xún)的選擇列表上的不可空的列ISNULL(見(jiàn)下面的準(zhǔn)則“x.col1ISNULL”))。一個(gè)解救方案是向選擇列表增加一個(gè)常數(shù),比如1,因?yàn)闊o(wú)論個(gè)子查詢(xún)是否具有GROUPBY語(yǔ)法,它都會(huì)起作用。例如,以下SQL語(yǔ)句,SELECTemp_seqFROMemployeesWHEREhiredateNOTIN(SELECTeffective_dateFROMsal_history)能夠變換為SELECTe.emp_seqFROMemployeese,(SELECTDISTINCTeffective_date,1col1FROMsal_history)xWHEREe.hiredate=x.effective_date(+)ANDx.col1ISNULL7.以下實(shí)例類(lèi)似于上面的實(shí)例6,并且也是非關(guān)聯(lián)的。不過(guò),在這個(gè)實(shí)例中有多列連接到該子查詢(xún)。此外,這些列表示外層查詢(xún)中的多個(gè)表格。在這個(gè)實(shí)例中,可能會(huì)遇到一個(gè)問(wèn)題,因?yàn)樽儞Q不做分析??赡軙?huì)產(chǎn)生一個(gè)錯(cuò)誤信息“ORA-01417某個(gè)表格可以外部連接到最多一個(gè)其它表格”。所以,關(guān)系運(yùn)算符需要一個(gè)外部連接而連接到該子查詢(xún)的列是來(lái)自多個(gè)表格時(shí),不應(yīng)當(dāng)產(chǎn)生這條信息。例如,以下SQL語(yǔ)句,SELECTe.emp_seqFROMemployeese,dependentsdWHERE(e.hiredate,d.birthdate)NOTIN(SELECThiredate,d1.birthdateFROMemployeese1,dependentsd1WHEREe1.emp_seq=1001ANDe1.emp_seq=d1.emp_seqANDrelation=‘SPOUSE’)ANDe.emp_seq=d.emp_seqANDd.relation=‘SPOUSE’會(huì)不正確地變換為SELECTe.emp_seqFROMemployeese,dependentsd,(SELECTDISTINCTe1.hiredate,d1.birthdate,1col1FROMemployeese1,dependentsd1WHEREe1.emp_seq=1001ANDe1.emp_seq=d1.emp_seqANDd1.relation=‘SPOUSE’)xWHEREe.emp_seq=d.emp_seqANDd.relation=‘SPOUSE’ANDe.hiredate=x.hiredate(+)ANDd.birthdate=x.birthdate(+)ANDx.col1ISNULL8.以下的非關(guān)聯(lián)實(shí)例提供了一種雖然奇怪卻值得關(guān)注的情況。盡管這種情況在理論上很罕見(jiàn),但是它能夠發(fā)生。其原因在于,下面的子查詢(xún)是非關(guān)聯(lián)的但是卻連接到帶有EXISTS運(yùn)算符的外層查詢(xún)。一般說(shuō)來(lái),EXISTS運(yùn)算符僅僅用于關(guān)聯(lián)的子查詢(xún)。在任何情況下,該變換都是簡(jiǎn)單的只須把它移動(dòng)到不帶有連接子句的外層查詢(xún),并在子查詢(xún)中增加準(zhǔn)則“ROWNUM=1”,如下所示。例如,以下SQL語(yǔ)句,SELECT*FROMemployeesWHEREEXISTS(SELECT*FROMsal_historyWHEREsal<0)能夠變換為SELECTe.*FROMemployeese,(SELECT*FROMsal_historyWHEREsal<0ANDROWNUM=1)與原始的SQL語(yǔ)句相比,變換后的SQL語(yǔ)句的性能將得到極大的改善。因?yàn)楝F(xiàn)在子查詢(xún)僅僅執(zhí)行一次,而不是像在原始SQL語(yǔ)句中執(zhí)行那樣每行一次。9.以下實(shí)例是非關(guān)聯(lián)的,因?yàn)樽硬樵?xún)包含多于一個(gè)同名的列名稱(chēng)而列出。盡管列名稱(chēng)前面有表格別名,列名稱(chēng)還是應(yīng)當(dāng)給予一個(gè)別名。在外層查詢(xún)的SELECT列表中的星號(hào),也應(yīng)當(dāng)為了外層查詢(xún)中的每個(gè)表格而復(fù)制。注意以下所示變換中下劃線(xiàn)的項(xiàng)目。SQL語(yǔ)句,SELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seqAND(e.birthdate,d.birthdate)IN(SELECTe1.birthdate,d1.birthdateFROMemployeese1,dependentsd1WHEREe1.emp_seq=d1.emp_seqANDe1.hiredate=SYSDATE-100)能夠變換為SELECTe.*.d.*FROMemployeese,dependentsd,(SELECTDISTINCTe1.birthdatecol1,d1.birthdatecol2FROMemployeese1,dependentsd1WHEREe1.eep_seq=d1.emp_seqANDe1.hiredate=SYSDATE-100)xWHEREe.emp_seq=d.emp_seqANDe.birthdate=x.col1ANDd.birthdate=x.col210.以下實(shí)例是非關(guān)聯(lián)的,并且說(shuō)明了標(biāo)量子查詢(xún)和NOTIN運(yùn)算符。由于子查詢(xún)是標(biāo)量的,它就能夠與外層查詢(xún)合并為一個(gè)外部連接。關(guān)鍵是僅僅保留“外部連接的”行。通過(guò)把子查詢(xún)中帶有表格非空列的準(zhǔn)則同ISNULL運(yùn)算符進(jìn)行與運(yùn)算,就能夠做到這一點(diǎn)。一個(gè)更好的解決方案可能是使用行標(biāo)識(shí)(見(jiàn)下面第二個(gè)變換)。例如,SELECTemp_seqFROMemployeesWHEREhiredateNOTIN(SELECThiredateFROMemployeesWHEREemp_seq=999)能夠變換為SELECTe.emp_seqFROMemployeese,employeese1WHEREe.hiredate=e1.hiredate(+)ANDe1.emp_seq(+)=999ANDe1.emp_seqISNULL或者變換為SELECTe.emp_seqFROMemployeese,employeese1WHEREe.hiredate=e1.hiredate(+)ANDe1.emp_seq(+)=999ANDe1.rowidISNULL11.以下的關(guān)聯(lián)實(shí)例既包含關(guān)聯(lián)準(zhǔn)則,又包含非連接準(zhǔn)則。由于該子查詢(xún)保證唯一性,所以該子查詢(xún)能夠合并。例如,以下SQL語(yǔ)句,SELECT*FROMemployeeseWHEREEXISTS(SELECT*FROMprojectsp,assignmentsaWHEREp.proj_seq=a.proj_seqANDe.emp_seq=a.emp_seqANDp.name=‘EXPLAINSQLDEVELOPMENT’)能夠變換為SELECTe.*FROMemployeese,projectsp,assignmentsaWHEREp.proj_seq=a.proj_seqANDe.emp_seq=a.emp_seqANDp.name=‘EXPLAINSQLDEVELOPMENT’12.以下的關(guān)聯(lián)實(shí)例不同,因?yàn)镾ELECT列表包含不返回外層查詢(xún)的列。(事實(shí)上,如果在前面一個(gè)實(shí)例11中的子查詢(xún)具有選擇列表中的項(xiàng)目,變換也將會(huì)恰恰如此。注意,在前面一個(gè)實(shí)例11中,子查詢(xún)選擇列表上的星號(hào)不起作用。)例如,SELECT*FROMemployeeseWHEREEXISTS(SELECTrelationFROMdependentsdWHEREe.emp_seq=d.emp_seq)能夠變換為SELECTe.*FROMemployeese,(SELECTDISTINCTemp_seqFROMdependentsd)xWHEREe.emp_seq=x.emp_seq13.這個(gè)關(guān)聯(lián)的實(shí)例與前一個(gè)實(shí)例不同,因?yàn)镾ELECT列表列具有外層查詢(xún)中的對(duì)應(yīng)列。例如,SELECT*FROMsal_historys1WHEREeffectivedate>(SELECTMAX(effective_date)FROMsal_historys2WHEREs1.emp_seq=s2.emp_seq)能夠變換為SELECTs1.*FROMsal_historys1,(SELECTemp_seq,MAX(effectiw_date)col1FROMsal_historys2GROUPBYemp_seq)xWHEREs1.emp_seq=x.emp_seqANDs1.effective_date>x.col114.以下的非關(guān)聯(lián)實(shí)例說(shuō)明了通過(guò)NOTEXISTS運(yùn)算符連接的非關(guān)聯(lián)子查詢(xún)。例如,SELECT*FROMemployeesWHERENOTEXISTS(SELECT*FROMdependents)能夠變換為SELECTe.*FROMemployeese,(SELECTcount(*)col1FROMdependentsWHEREROWNUM=1)xWHEREx.col1=0注意,原始子查詢(xún)的SELECT列表改變?yōu)椤癈OUNT(*)”,并且子查詢(xún)?cè)黾恿恕癛OWNUM=1”準(zhǔn)則。15.以下的非關(guān)聯(lián)實(shí)例類(lèi)似于前一個(gè)實(shí)例14,只是該子查詢(xún)包含GROUPBY。變換也類(lèi)似于前一個(gè)實(shí)例14。例如,SELECT*FROMemployeesWHERENOTEXISTS(SELECTnullFROMsal_historyGROUPBYemp_seq)能夠變換為SELECTe.*FROMemployeese,(SELECTcount(*)col1FROMsal_historyWHEREROWNUM=1GROUPBYemp_seq)xWHEREx.col1=0在子查詢(xún)的SELECT列表中的任何內(nèi)容,都交換為“COUNT(*)”。16.以下是一個(gè)使用NOTEXISTS運(yùn)算符的關(guān)聯(lián)實(shí)例。例如,SELECTemp_seqFROMemployeeseWHERENOTEXISTS(SELECT*FROMsal_historysWHEREe.emp_seq=s.emp_seqANDeffective_date=SYSDATE)能夠變換為SELECTe.emp_seqFROMemployeese,sal_historysWHEREe.emp_seq=s.emp_seq(+)ANDeffective_date(+)=SYSDATEANDs.emp_seqISNULL17.以下的關(guān)聯(lián)實(shí)例說(shuō)明了以IN運(yùn)算符連接的集合子查詢(xún)。例如,SELECT*FROMsal_historys1WHEREeffectivedateIN(SELECTeffective_dateFROMsal_historys2WHEREs1.emp_seq=s2.emp_seqANDsal>100)能夠變換為SELECTs1.*FROMsal_historys1,sal_historys2WHEREs1.effective_date=s2.effective_dateANDs1.emp_seq=s2.emp_seqANDs2.sal>10018.以下的非關(guān)聯(lián)實(shí)例說(shuō)明了<ALL運(yùn)算符。例如,SELECT*FROMemployeesWHEREhiredate<ALL(SELECThiredateFROMemployeesWHEREbirthdate>‘01-JAN-87’)能夠變換為SELECTe.*FROMemployeese,(SELECTMIN(hiredate)col1FROMemployeesWHEREbirthdate>‘01-JAN-87’)xWHERE(hiredate<x.col1ORx.col1ISNULL)注意變換中“x.col1ISNULL”的使用。其要點(diǎn)在于,聚集函數(shù)總會(huì)返回一個(gè)值,即使沒(méi)有一行符合準(zhǔn)則。由于子查詢(xún)結(jié)果為空集時(shí)ALL運(yùn)算符永遠(yuǎn)取值TRUE,系統(tǒng)應(yīng)當(dāng)仍然返回外層查詢(xún)中的行。19.以下的非關(guān)聯(lián)實(shí)例類(lèi)似于前一個(gè)實(shí)例18。不過(guò)在這個(gè)實(shí)例中使用>ALL運(yùn)算符而不是<ALL運(yùn)算符。例如,SELECT*FROMemployeesWHEREhiredate>ALL(SELECThiredateFROMemployeesWHEREbirthdate>‘01-JAN-77’)能夠變換為SELECTe.*FROMemployeese,(SELECTMAX(hiredate)col1FROMemployeesWHEREbirthdate>‘01-JAN-77’)xWHERE(hiredate>x.col1ORx.col1ISNULL)20.以下的非關(guān)聯(lián)實(shí)例包括了可合并的集子查詢(xún)。例如,SELECT*FROMemployeesWHEREemp_seqNOTIN(SELECTemp_seqFROMsal_historyWHEREeffective_date=‘5-JUL-98’)能夠變換為SELECTe.*FROMemployeese,sal_historysWHEREe.emp_seq=s.emp_seq(+)ANDeffective_date(+)=‘5-JUL-98’ANDs.emp_seqISNULL21.以下的關(guān)聯(lián)實(shí)例類(lèi)似于前一個(gè)實(shí)例20,只是它是關(guān)聯(lián)的。這個(gè)實(shí)例說(shuō)明了如何把外部連接語(yǔ)法增加到關(guān)聯(lián)準(zhǔn)則。例如,SELECT*FROMassignmentsaWHEREstart_dateNOTIN(SELECTeffective_dateFROMsal_historysWHEREa.emp_seq=s.emp_seq)能夠變換為SELECTa.*FROMassignmentsa,sal_historysWHEREa.start_date=s.effective_date(+)ANDa.emp_seq=s.emp_seq(+)ANDs.emp_seqISNULL22.以下的非關(guān)聯(lián)實(shí)例類(lèi)似于前一個(gè)實(shí)例21。不過(guò)在這個(gè)實(shí)例中,子查詢(xún)有多個(gè)表格。下面的實(shí)例說(shuō)明了如何合并到外層查詢(xún)時(shí),如何把外部連接語(yǔ)法放置到子查詢(xún)之內(nèi)的連接準(zhǔn)則上。例如,SELECT*FROMstatus_listWHEREstatussNOTIN(SELECTp.statusFROMprojectsp,assignmentsaWHEREa.proj_seq=p.proj_seqANDp.name=‘EXPLAINSQLDEVELOPMENT’)能夠變換為SELECTs.*FROMstatus_lists,projectsp,assignmentsaWHEREs.status=p.status(+)ANDp.name(+)=‘EXPLAINSQLDEVELOPMENT’ANDa.proj_seq(+)=p.proj_seqANDa.ROWIDISNULL在子查詢(xún)中,在剛剛連接的表格上保證了唯一性(在這種情況下是別名“p”,因?yàn)閜.name是唯一的)。以連接的次序,最多一個(gè)最低的子級(jí)能夠非唯一,在這種情況下是別名“a”。連接次序是別名“s”,然后是“p”,然后是“a”。23.以下的關(guān)聯(lián)實(shí)例可能頗為復(fù)雜。由于NOTIN運(yùn)算符,它應(yīng)當(dāng)是外部連接。不過(guò),問(wèn)題是別名“e”和“a”都與子查詢(xún)關(guān)聯(lián)。因?yàn)樽硬樵?xún)只包含一個(gè)表格,子查詢(xún)應(yīng)當(dāng)是可合并的,所以我們無(wú)須保證唯一性。例如,SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqANDe.emp_seqNOTIN(SELECTt.emp_seqFROMtime_sheetstWHEREa.proj_seq=t.proj_seqANDt.rpt_date=‘20-FEB-94’)由于關(guān)聯(lián)準(zhǔn)則,該子查詢(xún)既不能合并,也不能移動(dòng)。如果子查詢(xún)的關(guān)聯(lián)準(zhǔn)則和接口列引用外層查詢(xún)中的多于一個(gè)表格,該子查詢(xún)能夠跳過(guò)。在這種情況下,一個(gè)關(guān)聯(lián)準(zhǔn)則引用別名“a”,外層查詢(xún)的接口引用“e.emp_seq”。若是系統(tǒng)要變換該子查詢(xún),變換就會(huì)以TIME_SHEETS被外部連接到多于一個(gè)表格而結(jié)束,而這是非法的。因此,以上SQL語(yǔ)句會(huì)不正確地合并到SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDe.emp_seq=t.emp_seq(+)ANDa.proj_seq=t.proj_seq(+)ANDt.rpt_date(+)=‘20-FEB-94’ANDt.emp_seqISNULL并被不正確地移動(dòng)到SELECT*FROMemployeese,assignmentsa,(SELECTt.emp_seq,t.proj_seq,1col1FROMtimesheetstWHEREt.rpt_date=‘20-FEB-94’)xWHEREe.emp_seq=a.emp_seqANDe.emp_seq=x.emp_seq(+)ANDa.proj_seq=x.proj_seq(+)ANDx.col1ISNULL這種兩種情況都會(huì)造成非法的外部連接,所以應(yīng)當(dāng)避免。24.這個(gè)關(guān)聯(lián)的實(shí)例類(lèi)似于上面的實(shí)例23。通過(guò)傳遞性,對(duì)于以下的原始語(yǔ)句,系統(tǒng)能夠變換原始語(yǔ)句,如實(shí)例23所示,然后執(zhí)行變換,因此消除了實(shí)例23中遇到的限制。例如,實(shí)例23中的原始語(yǔ)句能夠變換為SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqANDa.emp_seqNOTIN(SELECTt.emp_seqFROMtime_sheetstWHEREa.proj_seq=t.proj_seqANDt.rpt_date=‘20-FEB-94’)它又可變換為SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seq(+)ANDa.proj_seq=t.proj_seq(+)ANDt.rpt_date(+)=‘20-FEB-94’ANDt.emp_seqISNULL25.以下的關(guān)聯(lián)實(shí)例涉及標(biāo)量運(yùn)算符“=”。這個(gè)實(shí)例顯示了如何使用子查詢(xún)中的傳遞性來(lái)確定子查詢(xún)是標(biāo)量的;如“e.emp_seq=t.emp_seq=a.emp_seq”。例如,SELECT*FROMtime_sheetst,projectspWHEREt.proj_seq=p.proj_seqANDt.rpt_date=(SELECThiredateFROMemployeese,assignmentsaWHEREa.proj_seq=p.proj_seqANDe.emp_seq=a.emp_seqANDe.emp_seq=t.emp_seq)能夠變換為SELECT*FROMtime_sheetst,projectsp,employeese,assignmentsaWHEREt.proj_seq=p.proj_seqANDt.rpt_date=e.hiredateANDa.proj_seq=p.proj_seqANDe.emp_seq=t.emp_seqANDe.emp_seq=a.emp_seq26.以下的關(guān)聯(lián)實(shí)例涉及集合運(yùn)算符“IN”。例如,SELECT*FROMemployeeseWHEREemp_seqIN(SELECTa.emp_seqFROMassignmentsa,time_sheetstWHEREa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDa.proj_seq=1ANDt.rpt_date=‘20-FEB-94’)可以變換為SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDa.proj_seq=1ANDt.rpt_date=‘20-FEB-94’27.以下的關(guān)聯(lián)實(shí)例顯示了雖然關(guān)聯(lián)準(zhǔn)則涉及子查詢(xún)中多于一個(gè)表格,還是可能合并的情況。在這種情況下,“t.”通過(guò)接口把“e.”連接到子查詢(xún);然后“t.”通過(guò)PROJ_SEQ列與“a.”關(guān)聯(lián)。能夠應(yīng)用傳遞性,所以“t”既通過(guò)PROJ_SEQ又通過(guò)EMP_SEQ與“a”關(guān)聯(lián)。此外,連接時(shí)對(duì)“e”和“a”保證了唯一性。例如,SELECT*FROMtime_sheetstWHEREt.rpt_dateNOTIN(SELECThiredateFROMemployeese,assignmentsaWHEREa.proj_seq=t.proj_seqANDe.emp_seq=a.emp_seqANDe.emp_seq=t.emp_seq)能夠變換為SELECTt.*FROMtime_sheetst,employeese,assignmentsaWHEREt.rpt_date=e.hiredate(+)ANDt.emp_seq=e.emp_seq(+)ANDt.proj_seq=a.proj_seq(+)ANDt.emp_seq=a.emp_seq(+)AND(a.emp_seqISNULLORe.emp_seqISNULL)由于“a”和“e”是分別連接“t”的,系統(tǒng)需要對(duì)每個(gè)表格的不可空列增加ISNULL,并把它們用或連在一起。28.以下的關(guān)聯(lián)實(shí)例說(shuō)明了帶有GROUPBY子句的子查詢(xún)中SELECT列表上的聚集。例如,SELECT*FROMsal_historysWHEREeffective_dateIN(SELECTMAX(start_date)FROMassignmentsaWHEREs.emp_seq=a.emp_seqGROUPBYproj_seq)能夠變換為SELECT*FROMsal_historys,(SELECTDISTINCT.emp_seq,MAX(start_date)col1FROMassignmentsaGROUPBYproj_seq,emp_seq)xWHEREs.emp_seq=x.emp_seqANDeffective_date=x.col129.以下的非關(guān)聯(lián)實(shí)例說(shuō)明了子查詢(xún)移動(dòng)時(shí)把聚集變換為聚集的聚集。例如,SELECT*FROMassignmentsaWHEREstart_date<ANY(SELECTMIN(rpt_date)FROMtime_sheetsGROUPBYproj_seq)能夠變換為SELECT*FROMassignmentsa,(SELECTMAX(MIN(rpt_date))col1FROMtime_sheetsGROUPBYproj_seq)xWHEREa.start_date<x.col130.以下的關(guān)聯(lián)實(shí)例說(shuō)明了,通過(guò)像是“<ANY”的運(yùn)算符連接的子查詢(xún)不能變換。例如,SELECT*FROMassignmentsaWHEREstart_date<ANY(SELECTMIN(rpt_date)FROMtime_sheetstWHEREa.emp_seq=t.emp_seqGROUPBYproj_seq)會(huì)不正確地變換為SELECT*FROMassignmentsa,(SELECTemp_seq,MIN(rpt_date)col1FROMtime_sheetstGROUPBYproj_seq,emp_seq)xWHEREa.start_date<x.col1ANDa.emp_seq=x.emp_seq這種變換是不正確的,因?yàn)樽硬樵?xún)?nèi)匀皇且粋€(gè)集合,而不是所需要的標(biāo)量,如每EMP_SEQ,由于PROJ_SEQ的成組作用,仍然可能有許多MIN(rpt_date)值。就算該子查詢(xún)不具有GROUPBY子句,該變換也仍然不是毫無(wú)問(wèn)題的,因?yàn)樵撟儞Q會(huì)需要把關(guān)聯(lián)列放到SELECT列表上并進(jìn)行聚集以及聚集的聚集。雖然原始的GROUPBY列既不與HAVING子句關(guān)聯(lián),又不是它的一部分,系統(tǒng)也不能擺脫它。例如,該查詢(xún)可能會(huì)不正確地變換為SELECTe.*FROMemployeese,(SELECTemp_seq,MAX(rpt_date)col1FROMtime_sheetstGROUPBYt.emp_seq)xWHEREe.emp_seq=x.emp_seqANDe.hiredate<x.col1以上變換是不正確的,因?yàn)閷?duì)于同樣的PROJ_SEQ,可能會(huì)由某個(gè)rpt_date小于e.hiredate,而另一個(gè)rpt_date大于e.hiredate。在原始的查詢(xún)中,帶有MIN(rpt_date)的子查詢(xún)將返回行中的第一個(gè)數(shù)據(jù)。不過(guò),在以上的查詢(xún)中,該子查詢(xún)將返回最大值。31.以下的關(guān)聯(lián)實(shí)例是一個(gè)極好的實(shí)例,因?yàn)殛P(guān)聯(lián)準(zhǔn)則使用“<”運(yùn)算符而不是“=”運(yùn)算符,其中的子查詢(xún)不能移動(dòng)。例如,SELECT*FROMsal_historys1,employeeseWHEREe.emp_seq=s1.emp_seqANDs1.effective_date=(SELECTMIN(s2.effective_date)FROMsal_historys2WHEREe.emp_seq=s2.emp_seqANDe.hiredate<s2.effective_date)會(huì)不正確地變換為SELECT*FROMsal_historys1,employeese,(SELECTs2.emp_seq,s2.effective_date,MIN(s2.effective_date)col1FROMsal_historys2GROUPBYs2.emp_seq,s2.effective_date)xWHEREe.emp_seq=x.emp_seqANDs1.effective_date=x.col1ANDe.hiredate<x.effective_date進(jìn)行正確變換的一種方法可能是,將不等關(guān)聯(lián)中涉及的表格移動(dòng)到子查詢(xún)中,如下所示SELECT*FROMsal_historys1,(SELECTe.emp_seq,MIN(s2.effective_date)col1FROMsal_historys2,employeeseWHEREe.emp_seq=s2.emp_seqANDe.hiredate<s2.effective_dateGROUPBYe.emp_seq)xWHEREs1.emp_seq=x.emp_seqANDs1.effective_date=x.col1這種解決方案是將EMPLOYEES表格移動(dòng)到子查詢(xún)中,然后移動(dòng)子查詢(xún)。32.以下的關(guān)聯(lián)實(shí)例是一個(gè)不帶聚集的標(biāo)量子查詢(xún)。例如,SELECT*FROMsal_historysWHEREeffective_date=(SELECThiredateFROMemployeeseWHEREs.emp_seq=e.emp_seq)能夠變換為SELECTs.*FROMsal_historys,employeeseWHEREs.effective_date=e.hiredateANDs.emp_seq=e.emp_seq33.以下的關(guān)聯(lián)實(shí)例類(lèi)似于前一個(gè)實(shí)例32。不過(guò),在這個(gè)實(shí)例中在并非唯一關(guān)鍵字一部分的列上有另外的關(guān)聯(lián)準(zhǔn)則。處理關(guān)聯(lián)的子查詢(xún)時(shí)這可能是重要的;也就是對(duì)子查詢(xún)的PK或UNQ關(guān)鍵字的關(guān)聯(lián)準(zhǔn)則應(yīng)當(dāng)使用“=”運(yùn)算符,而另外的關(guān)聯(lián)準(zhǔn)則使用的運(yùn)算符則無(wú)關(guān)緊要。在這種情況下,關(guān)聯(lián)準(zhǔn)則“t.rpt_date>=a.start_date”不是唯一關(guān)鍵字的一部分。例如,SELECT*FROMtime_sheetstWHERErpt_date<(SELECTstop_dateFROMassignmentsaWHEREa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDt.rpt_date>=a.start_date)能夠變換為SELECTt.*FROMtime_sheetst,assignmentsaWHEREt.rpt_date<a.stop_dateANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDt.rpt_date>=a.start_date34.以下的關(guān)聯(lián)實(shí)例使用了標(biāo)量運(yùn)算符來(lái)連接標(biāo)量子查詢(xún),其中由于聚集和沒(méi)有GROUPBY子句,子查詢(xún)是標(biāo)量的。例如,SELECT*FROMemployeeseWHEREhiredate>(SELECTMIN(effective_date)FROMsal_historysWHEREe.emp_seq=s.emp_seq)能夠變換為其中SELECTe.*FROMemployeese,(SELECTemp_seq,MIN(effective_date)col1FROMsal_historysGROUPBYemp_seq)xWHEREe.emp_seq=x.emp_seqANDe.hiredate>x.col135.以下的關(guān)聯(lián)實(shí)例說(shuō)明了HAVING子句中的關(guān)聯(lián)。解決方案是,HAVING子句變?yōu)橥鈱硬樵?xún)中的準(zhǔn)則,在關(guān)聯(lián)準(zhǔn)則中比較的局部項(xiàng)目應(yīng)當(dāng)出現(xiàn)在子查詢(xún)的SELECT列表中。應(yīng)當(dāng)注意,另一個(gè)要校驗(yàn)的語(yǔ)法將是子查詢(xún)沒(méi)有GROUPBY子句,但確實(shí)具有HAVING子句。例如,SELECT*FROMemployeeseWHERENOTEXISTS(SELECTa.proj_seqFROMassignmentsa,time_sheetstWHEREa.proj_seq=t.proj_seqANDa.emp_seq=t.emp_seqANDe.emp_seq=a.emp_seqGROUPBYa.proj_seqHAVINGMIN(t.rpt_date)<e.hiredate)能夠轉(zhuǎn)換為SELECT*FROMemployeese,(SELECTa.proj_seq,a.emp_seq,MIN(t.rpt_date)col1,1col2FROMassignmentsa,time_sheetstWHEREa.proj_seq=t.proj_seqANDa.emp_seq=t.emp_seqGROUPBYa.proj_seq,a.emp_seq)xWHEREe.emp_seq=x.emp_seq(+)ANDx.col1<e.hiredate(+)ANDx.col2ISNULL36.以下是一個(gè)關(guān)聯(lián)的實(shí)例,其中運(yùn)算符是NOTIN運(yùn)算符,并且有不等關(guān)聯(lián)準(zhǔn)則。系統(tǒng)應(yīng)當(dāng)注意,它不必把EMP_SEQ列的另一個(gè)拷貝移動(dòng)到GROUPBY子句上,因?yàn)樗呀?jīng)在那里了。例如,SELECT*FROMsal_historys1WHEREs1.salNOTIN(SELECTMIN(sal)FROMsal_historys2WHEREs1.emp_seq?。絪2.emp_seqANDs1.effective_date=s2.effective_dateGROUPBYemp_seq)能夠變換為SELECTs1.*FROMsal_historys1,(SELECTemp_seq,effective_date,MIN(sal)col1,1col2FROMsal_historys2GROUPBYemp_seq,effective_date)xWHEREs1.sal=x.col1(+)ANDs1.emp_seq?。絰.emp_seq(+)ANDs1.effective_date=x.effective_date(+)ANDx.col2ISNULLorderbys1.emp_seq,s1.effective_date37.以下的關(guān)聯(lián)實(shí)例類(lèi)似于上面的實(shí)例30,只不過(guò)在實(shí)例30中子查詢(xún)不具有聚集。雖然這個(gè)查詢(xún)可能不實(shí)際,這個(gè)實(shí)例用于說(shuō)明,帶有GROUPBY的子查詢(xún)?yōu)槭裁床粦?yīng)當(dāng)對(duì)于任何的ANY、SOME或ALL運(yùn)算符移動(dòng)。例如,SELECT*FROMassignmentsaWHEREstart_date<ALL(SELECTrpt_dateFROMtime_sheetstWHEREa.emp_seq=t.emp_seqGROUPBYrpt_dateHAVINGCOUNT(*)>1)會(huì)不正確地變換為SELECTa.*FROMassignmentsa,(SELECTMIN(rpt_date)col1,emp_seq,1col2FROMtime_sheetstWHEREa.emp_seq=t.emp_seqGROUPBYrpt_date,emp_seqHAVINGCOUNT(*)>1)xWHERE(start_date<x.col1ORx.col2ISNULL)ANDa.emp_seq=x.emp_seq(+)問(wèn)題在于,對(duì)于外層查詢(xún),已經(jīng)有了RPT_DATE的組合,而且沒(méi)有連接準(zhǔn)則。因此,我們需要標(biāo)量時(shí),對(duì)EMP_SEQ我們就以每個(gè)連接一個(gè)集合而結(jié)束。38.以下的關(guān)聯(lián)實(shí)例說(shuō)明了由于不等關(guān)聯(lián)準(zhǔn)則,ANY、SOME或ALL子查詢(xún)不能移動(dòng)的情況。要移動(dòng),應(yīng)當(dāng)確保最多一行與原始外層查詢(xún)進(jìn)行比較。不過(guò),對(duì)于該變換中的不等連接準(zhǔn)則,可以連接多行。例如,SELECT*FROMsal_historys1WHEREsal<ANY(SELECTsalFROMsal_historys2WHEREs1.emp_seq?。絪2.emp_seqANDs1.effective_date=s2.effective_date)會(huì)不正確地變換為SELECTs1.*FROMsal_historys1,(SELECTemp_seq,effective_date,MAX(sal)col1FROMsal_historys2)xWHEREs1.sal<x.col1ANDs1.emp_seq?。絰.emp_seqANDs1.effective_date=x.effective_date39.以下是一個(gè)帶有“>ALL”運(yùn)算符的關(guān)聯(lián)實(shí)例。這個(gè)實(shí)例類(lèi)似于上面的實(shí)例3,只不過(guò)這個(gè)實(shí)例使用MAX函數(shù)而不是MIN函數(shù)。例如,SELECTemp_seq,birthdateFROMemployeeseWHEREbirthdate>ALL(SELECTbirthdateFROMdependentsdWHEREe.emp_seq=d.emp_seq)能夠變換為SELECTe.emp_seq,e.birthdateFROMemployeese,(SELECTd.emp_seq,MAX(birthdate)col1,1col2FROMdependentsdGROUPBYemp_seq)xWHEREe.emp_seq=x.emp_seq(+)AND(e.birthdate>x.col1ORx.col2ISNULL)40.以下的關(guān)聯(lián)實(shí)例說(shuō)明了“<ANY”運(yùn)算符。<ANY和“>ANY”運(yùn)算符之間的唯一差異是MAX變?yōu)镸IN。例如,SELECT*FROMsal_historys1WHEREemp_seq=1001ANDsal<ANY(SELECTsalFROMsal_historys2WHEREs1.emp_seq=s2.emp_seqANDs1.effective_date=s2.effective_date)能夠變換為SELECTs1.*FROMsal_historys1,(SELECTemp_seq,effective_date,MAX(sal)col1FROMsal_historys2GROUPBYemp_seq,effective_date)xWHEREemp_seq=1001ANDs1.sal<x.col1ANDs1.emp_seq=x.emp_seqANDs1.effective_date=x.effective_date41.以下的關(guān)聯(lián)實(shí)例說(shuō)明了標(biāo)量運(yùn)算符“=”。例如,SELECT*FROMemployeeseWHEREhiredate=(SELECTMIN(effective_date)FROMsal_historysWHEREe.emp_seq=s.emp_seq)能夠變換為SELECTe.*FROMemployeese,(SELECTemp_seq,MIN(effective_date)col1FROMsal_historysGROUPBYemp_seq)xWHEREhiredate=x.col1ANDe.emp_seq=x.emp_seq42.以下的關(guān)聯(lián)實(shí)例說(shuō)明了EXISTS運(yùn)算符,其中子查詢(xún)包含HAVING子句但是沒(méi)有GROUPBY和聚集。這里的要點(diǎn)在于在HAVING子句之前增加GROUPBY子句。例如,SELECT*FROMemployeeseWHEREEXISTS(SELECTnullFROMsal_historysWHEREe.emp_seq=s.emp_seqHAVINGCOUNT(*)>1)能夠變換為SELECTe.*FROMemployeese,(SELECTemp_seqFROMsal_historysGROUPBYemp_seqHAVINGCOUNT(*)>1)xWHEREe.emp_seq=x.emp_seq43.這個(gè)關(guān)聯(lián)的實(shí)例類(lèi)似于前面的實(shí)例42,其中有HAVING子句。不過(guò),在這個(gè)實(shí)例中也存在GROUP。例如,SELECT*FROMemployeeseWHEREEXISTS(SELECTnullFROMsal_historysWHEREe.emp_seq=s.emp_seqGROUPBYeffective_dateHAVINGCOUNT(*)>1)能夠變換為SELECTe.*FROMemployeese,(SELECTDISTINCTemp_seqFROMsal_historysGROUPBYeffective_date,emp_seqHAVINGCOUNT(*)>1)xWHEREe.emp_seq=x.emp_seq44.以下的非關(guān)聯(lián)實(shí)例說(shuō)明了由于EXISTS運(yùn)算符子查詢(xún)不能移動(dòng)的情況。其理由是這種解決方法向子查詢(xún)?cè)黾印癛OWNUM=1”準(zhǔn)則。不過(guò),HAVING子句能夠使檢索到的唯一行失去資格。在這個(gè)實(shí)例中,應(yīng)當(dāng)至少有兩行合格,否則子查詢(xún)返回空集。例如,SELECT*FROMemployeeseWHEREEXISTS(SELECTnullFROMsal_historysHAVINGCOUNT(*)>1)會(huì)不正確地變換為SELECT*FROMemployeese,(SELECTnullFROMsal_historysWHEREROWNUM=1HAVINGCOUNT(*)>1)45.下一個(gè)關(guān)聯(lián)的實(shí)例說(shuō)明了與上面多個(gè)級(jí)別關(guān)聯(lián)的子查詢(xún)。包括這個(gè)實(shí)例是因?yàn)樵谏弦还?jié)中,“限制”表明不應(yīng)當(dāng)試圖轉(zhuǎn)換這些類(lèi)型的關(guān)聯(lián)子查詢(xún)。其理由是它們相對(duì)比較復(fù)雜,盡管還是可能的,如下面所示。例如,SELECT*FROMemployeeseWHEREEXISTS(SELECTnullFROMassignmentsaWHEREa.emp_seq=e.emp_seqANDEXISTS(SELECTnullFROMtime_sheetstWHEREtemp_seq=e.emp_seqANDt.proj_seq=a.proj_seq))能夠首先變換為SELECTe.*FROMemployeeseWHEREEXISTS(SELECTnullFROMassignmentsa,(SELECTDISTINCTemp_seq,proj_seqFROMtime_sheetst)x1WHEREa.emp_seq=e.emp_seqANDx1.emp_seq=e.emp_seqANDx1.proj_seq=a.proj_seq)再變換為SELECTe.*FROMemployeese,(SELECTDISTINCTa.emp_seqcol1,x1.emp_seqcol2FROMassignmentsa,(SELECTDISTINCTemp_seq,proj_seqFROMtime_sheetst)x1WHEREx1.proj_seq=a.proj_seq)x2WHEREx2.col1=e.emp_seqANDx2.col2=e.emp_seq第一個(gè)變換相對(duì)比較簡(jiǎn)單。子查詢(xún)也許不能合并,所以就移動(dòng)它。這需要SELECT列表中的DISTINCT關(guān)鍵字,加上曾經(jīng)是要移動(dòng)到SELECT列表之關(guān)聯(lián)準(zhǔn)則一部分的局部列。此外,關(guān)聯(lián)的準(zhǔn)則會(huì)移動(dòng)到外層查詢(xún)。第二個(gè)變換稍微復(fù)雜一點(diǎn),因?yàn)楝F(xiàn)在有來(lái)自子查詢(xún)不同的局部表格的兩列,它們?cè)?jīng)具有相同的名稱(chēng),但是曾經(jīng)與外層查詢(xún)關(guān)聯(lián)。這表明它們移動(dòng)到SELECT列表時(shí)必須給這些列獨(dú)特的別名。然后系統(tǒng)只需把關(guān)聯(lián)的準(zhǔn)則移動(dòng)到外層查詢(xún)。為了更好地優(yōu)化這一點(diǎn),系統(tǒng)在移動(dòng)之前應(yīng)當(dāng)注意準(zhǔn)則的傳遞性。例如,我們有“a.emp_seq=e.emp_seq”,也有“x1.emp_seq=e.emp_seq”。這等價(jià)于說(shuō)“a.emp_seq=x1.emp_seq”。理解了這一點(diǎn),就會(huì)使子查詢(xún)中的連接效率更高,并會(huì)得出SELECTe.*FROMemployeese,(SELECTDISTINCTa.emp_seqcol1,x1.emp_seqcol2FROMassignmentsa,(SELECTDISTINCTemp_seq,proj_seqFROMtime_sheetst)x1WHEREx1.proj_seq=a.proj_seqANDa.emp_seq=x1.emp_seq)x2WHEREx2.col1=e.emp_seqANDx2.col2=e.emp_seq46.OR運(yùn)算符被視為子查詢(xún)的父級(jí)。以下的實(shí)例說(shuō)明了轉(zhuǎn)換為一個(gè)連接將產(chǎn)生錯(cuò)誤的答案。例如,SELECTcount(*)FROMemployeesWHEREhiredate>‘01-jan-97’ORemp_seqIN(SELECTemp_seqFROMsal_historyWHEREsal>100)如果不考慮OR,轉(zhuǎn)換將是SELECTcount(*)FROMemployeese,(SELECTDISTINCTemp_seqFROMsal_historyWHEREsal>100)xWHEREhiredate>‘01-jan-97’ORe.emp_seq=x.emp_seq看到這個(gè)問(wèn)題的一種方法是現(xiàn)在把OR轉(zhuǎn)換為一個(gè)UNIONALL,如下所示SELECTcount(*)FROMemployeese,(SELECTDISTINCTemp_seqFROMsal_historyWHEREsal>100)xWHEREhiredate>‘01-jan-97’UNIONALLSELECTcount(*)FROMemployeese,(SELECTDISTINCTemp_seqFROMsal_historyWHEREsal>100)xWHEREhiredate>‘01-jan-97’47.以下的實(shí)例涉及OR運(yùn)算中的關(guān)聯(lián)準(zhǔn)則。如果關(guān)聯(lián)準(zhǔn)則在OR運(yùn)算中,就不可能轉(zhuǎn)換為外部連接,并且轉(zhuǎn)換為NOTIN也很復(fù)雜。例如,SELECT*FROMemployeeseWHERENOTEXISTS(SELECT*FROMsal_historysWHEREs.effective_date=e.birthdateORs.effective_date=e.hiredate)如果轉(zhuǎn)換為NOT,系統(tǒng)應(yīng)當(dāng)做以下工作SELECT*FROMemployeeseWHEREbirthdateNOTIN(SELECTeffective_dateFROMsal_historys)ORhiredateNOTIN(SELECTeffective_dateFROMsal_historys)如果因?yàn)闀?huì)產(chǎn)生不可分析的語(yǔ)法而不可能轉(zhuǎn)換為外部連接SELECTe.*FROMemployeese,(SELECTDISTINCTeffective_dateFROMsal_history)xWHEREe.birthdate=x.effective_date(+)ORe.hiredate=x.effective_date(+)48.以下的實(shí)例說(shuō)明了原始子查詢(xún)可能產(chǎn)生空集時(shí)NOTIN到NOTEXISTS的變換。為了展示的目的,人為地強(qiáng)制子查詢(xún)產(chǎn)生一個(gè)空集。例如,SELECT*FROMemployeesWHEREhiredateNOTIN(SELECTeffective_dateFROMsal_historyWHERE1=2)應(yīng)當(dāng)變換如下以確保產(chǎn)生同樣的結(jié)果集SELECT*FROMemployeeseWHERENOTEXISTS(SELECT*FROMsal_historysWHERE1=2ANDe.hiredate=s.effective_date)AND(e.hiredateISNOTNULLORNOTEXISTS(SELECT*FROMsal_historyWHERE1=2)不過(guò),這種解決方法的一個(gè)問(wèn)題是我們又回到了原始狀態(tài)。49.以下的關(guān)聯(lián)實(shí)例說(shuō)明了帶有與外層查詢(xún)關(guān)聯(lián)的聚集的HAVING子句。例如,SELECT*FROMprojectspWHEREEXISTS(SELECTnullFROMtime_sheetstWHEREt.proj_seq=p.proj_seqGROUPBYemp_seqHAVINGMIN(t.rpt_date)=p.start_date)這種變換可能需要移動(dòng)聚集和關(guān)聯(lián)列到SELECT列表,如下所示SELECT*FROMprojectsp,(SELECTproj_seq,MIN(rpt_date)col1FROMtime_sheetsGROUPBYemp_seq,proj_seq)xWHEREp.proj_seq=x.proj_seqANDp.start_date=x.col150.以下的關(guān)聯(lián)實(shí)例展示了與NOTIN的合并。注意,變換中增加的準(zhǔn)則包含了連接到外層查詢(xún)的子查詢(xún)表格的ROWID。使用別名“t”而不是“a”的ROWID這一點(diǎn)很重要,因?yàn)椤皌”是連接次序中最低級(jí)別的子級(jí),“e”外部連接到“a”,然后“a”外部連接到“t”。例如,SELECTemp_seqFROMemployeeseWHEREe.hiredateNOTIN(SELECTstart_dateFROMassignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDt.rpt_date=‘01-jan-87’ANDa.proj_seq=1)能夠變換為SELECTe.emp_seqFROMemployeese,assignmentsa,time_sheetstWHEREe.hiredate=a.start_date(+)ANDe.emp_seq=a.emp_seq(+)ANDa.emp_seq=t.emp_seq(+)ANDa.proj_seq=t.proj_seq(+)ANDt.rpt_date(+)=‘01-jan-87’ANDa.proj_seq(+)=1ANDt.ROWIDisnull51.以下的關(guān)聯(lián)實(shí)例類(lèi)似于前一個(gè)實(shí)例50,只不過(guò)子查詢(xún)的接口列與子查詢(xún)中關(guān)聯(lián)表格不相同。例如START_DATE屬于ASSIGNMENTS,但是T.EMP_SEQ關(guān)聯(lián)卻屬于一個(gè)不同的表格。如果使用傳遞性,因?yàn)門(mén)和A之間的連接準(zhǔn)則,我們可以把T.EMP_SEQ轉(zhuǎn)換到A.EMP_SEQ。例如,SELECTemp_seqFROMemployeeseWHEREe.hiredateNOTIN(SELECTstart_dateFROMassignmentsa,time_sheetstWHEREe.emp_seq=t.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDt.rpt_date=‘01-jan-87’ANDa.proj_seq=1)首先增加傳遞性以產(chǎn)生SELECTemp_seqFROMemployeeseWHEREe.hiredateNOTIN(SELECTstart_dateFROMassignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDt.rpt_date=‘01-jan-87’ANDa.proj_seq=1)然后,我們就有了與前一個(gè)實(shí)例50相同的查詢(xún),這說(shuō)明發(fā)生了同樣的變換。52.這個(gè)關(guān)聯(lián)的實(shí)例類(lèi)似于實(shí)例50,只不過(guò)現(xiàn)在子查詢(xún)中對(duì)應(yīng)于接口列的表格是TIME_SHEETS。唯一的差異在于,EMPLOYEES外部連接到TIME_SHEETS,然后TIME_SHEETS外部連接到ASSIGNMENTS。所以,增加的準(zhǔn)則使用ASSIGNMENTS表格的ROWID,而不是像在實(shí)例50中的TIME_SHEETS表格。例如,SELECTemp_seqFROMemployeeseWHEREe.hiredateNOTIN(SELECTrpt_dateFROMassignmentsa,time_sheetstWHEREe.emp_seq=t.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDt.proj_seq=1)能夠變換為SELECTe.emp_seqFROMemployeese,assignmentsa,time_sheetstWHEREe.hiredate=t.rpt_date(+)ANDe.emp_seq=t.emp_seq(+)ANDt.emp_seq=a.emp_seq(+)ANDt.proj_seq=a.proj_seq(+)ANDt.proj_seq(+)=1ANDa.ROWIDisnull53.以下的關(guān)聯(lián)實(shí)例說(shuō)明了一個(gè)聚集的聚集不是一種可能的轉(zhuǎn)換。例如,SELECT*FROMprojectspWHEREstop_dateIN(SELECTMAX(MIN(rpt_date))FROMtime_sheetstWHEREt.proj_seq=p.proj_seqGROUPBYemp_seqHAVINGMIN(t.rpt_date)=p.start_date)會(huì)不得不錯(cuò)誤地轉(zhuǎn)換為SELECT*FROMprojectsp,(SELECTproj_seq,MIN(rpt_date)col1,MAX(MIN(rpt_date))col2FROMtime_sheetstGROUPBYemp_seq,proj_seq)xWHEREp.proj_seq=x.proj_seqANDp.start_date=x.col1ANDp.stop_date=x.col2不過(guò),這樣的SQL將不會(huì)編譯,所以應(yīng)當(dāng)避免。54.以下的關(guān)聯(lián)實(shí)例說(shuō)明了一個(gè)不等關(guān)聯(lián)準(zhǔn)則,以及聚集不是一種可能的轉(zhuǎn)換。例如,SELECT*FROMassignmentsaWHEREa.emp_seqIN(SELECTemp_seqFROMtime_sheetstWHEREt.proj_seq=a.proj_seqANDa.start_date>t.rpt_dateGROUPBYemp_seqHAVINGMAX(rpt_date)<a.stop_date)會(huì)錯(cuò)誤地變換為SELECT*FROMassignmentsa,(SELECTemp_seq,proj_seq,rpt_date,MAX(rpt_date)col1FROMtime_sheetstWHEREt.proj_seq=a.proj_seqANDa.start_date>t.rpt_dateGROUPBYemp_seq,proj_seq,rpt_date,)xWHEREa.emp_seq=x.emp_seqANDa.proj_seq=x.proj_seqANDa.start_date>x.rpt_dateANDa.stop_date>x.col1這里的問(wèn)題在于,由于不等準(zhǔn)則“a.start_date>t.rpt_date”,T.RPT_DATE將不得不移動(dòng)到SELECT列表以及GROUPBY。不過(guò),聚集也不能移動(dòng)到SELECT列表,因?yàn)樗鼘e(cuò)誤的組。事實(shí)上,現(xiàn)在MAX將等于RPT_DATE。55.以下的關(guān)聯(lián)實(shí)例也說(shuō)明了一個(gè)聚集的聚集不是一種可能的轉(zhuǎn)換。例如,SELECT*FROMassignmentsaWHEREa.stop_dateIN(SELECTMAX(MIN(rpt_date))FROMtime_sheetstWHEREt.proj_seq=a.proj_seqGROUPBYemp_seq)會(huì)錯(cuò)誤地變換為SELECT*FROMassignmentsa,(SELECTproj_seq,MAX(MIN(rpt_date))col1FROMtime_sheetstGROUPBYemp_seq,proj_seq)xWHEREa.stop_date=x.col1ANDa.proj_seq=x.proj_seq問(wèn)題在于,你不能在SELECT列表中具有標(biāo)量和聚集。最優(yōu)化以下進(jìn)一步列出系統(tǒng)或用戶(hù)選定了最優(yōu)化模式之后,本系統(tǒng)通過(guò)產(chǎn)生另外的SQL語(yǔ)句,用來(lái)優(yōu)化SQL語(yǔ)句的方法。最優(yōu)化目標(biāo)的線(xiàn)索應(yīng)當(dāng)包括在每個(gè)SQL語(yǔ)句變換中。系統(tǒng)將確定非連接準(zhǔn)則中的所有傳遞性,確定所有連接次序以及確定所有的不同子查詢(xún)變換。非連接傳遞性簡(jiǎn)要地看一看以下的查詢(xún),SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqANDe.emp_seqIN(SELECTemp_seqFROMdependentsWHERErelation=′SPOUSE′)在這個(gè)實(shí)例中,DEPENDENTS子查詢(xún)的準(zhǔn)則可以連接到“a.emp”或“t.emp_seq”,正如同原始的e.emp_seq”一樣。其它系統(tǒng)不會(huì)理解這一點(diǎn)。通過(guò)轉(zhuǎn)換到“a.empseq”,本系統(tǒng)允許數(shù)據(jù)庫(kù)使用ASSIGNMENTS上的連接鍵索引。另一種變換會(huì)是把“e.emp_seq”改變?yōu)椤癮.emp_seq”(第5行),如下所示1SELECT*FROMemployeese,assignmentsa,time_sheetst2WHEREe.emp_seq=a.emp_seq3ANDa.emp_seq=t.emp_seq4ANDa.proj_seq=t.proj_seq5ANDa.emp_seqIN(SELECTemp_seqFROMdependents6WHERErelation=′SPOUSE′)由于運(yùn)算對(duì)象“e.emp_seq”能夠被兩個(gè)其它值取代,該SQL能夠以三種方式寫(xiě)出(一種是原始方式,另外兩種是能夠取代“e.emp_seq”的不同值的數(shù))。多種非連接傳遞性下面介紹系統(tǒng)如何處理多種非連接傳遞性。例如,給定SQL語(yǔ)句,1SELECT*FROMemployeese,assignmentsa,time_sheetst2WHEREe.emp_seq=a.emp_seq3ANDa.emp_seq=t.emp_seq4ANDa.proj_seq=t.proj_seq5ANDa.proj_seq=(SELECTproj_seqFROMprojects6WHEREname=′EXPLAINSQLDEVELOPMENT′)7ANDe.emp_seqIN(SELECTemp_seqFROMdependents8WHERErelation=′SPOUSE′)在兩個(gè)不同的非連接準(zhǔn)則中,“a.proj_seq”(第5行)和“e.emp_seq”(第7行)兩個(gè)運(yùn)算對(duì)象能夠被等價(jià)的列取代。其它系統(tǒng)不會(huì)理解這一點(diǎn)。不過(guò),本系統(tǒng)通過(guò)把“e.emp_seq”(第7行)轉(zhuǎn)換到“a.emp_seq”,將允許數(shù)據(jù)庫(kù)使用ASSIGNMENTS上的連接鍵索引。對(duì)于“e.emp_seq”的準(zhǔn)則與上一個(gè)實(shí)例相同。本系統(tǒng)也能夠以“t.proj_seq”取代“a.proj_seq”(第5行)。這表明可能有6(2×3)種不同的SQL語(yǔ)句能夠使用(注意這包括原始值)。多列運(yùn)算對(duì)象如何處理包括多列的運(yùn)算對(duì)象?例如1SELECT*FROMemployeese,sal_historys2WHEREe.emp_seq=s.emp_seq3AND(s.emp_seq,s.effective_date)IN4(SELECTemp_seq,max(effective_date)5FROMsal_historys16WHEREeffective_date<=SYSDATE7GROUPBYemp_seq)準(zhǔn)則“s.emp_seq,seffective_date”(第3行)表示能夠應(yīng)用傳遞性的非連接準(zhǔn)則。由于連接子句說(shuō)明“e.emp_seq”和“s.emp_seq”是等價(jià)的,對(duì)于非連接準(zhǔn)則運(yùn)算對(duì)象就有兩種選擇。第一種是原始的,第二種是由“e.emp_seq”取代“s.emp_seq”。問(wèn)題在于這到底是否應(yīng)當(dāng)做。這個(gè)問(wèn)題的理由在于運(yùn)算對(duì)象中的兩列都引用同一個(gè)表格,并且在兩列中都有連接索引。即使在兩列中只有一個(gè)單列索引。答案是不要擔(dān)心,只要把其它列加到運(yùn)算對(duì)象上,并把對(duì)應(yīng)列加到SELECT列表中,如下所示SELECT*FROMemployeese,sal_historysWHEREe.emp_seq=s.emp_seqAND“(e.emp_seq,s.emp_seq,s.effective_date)IN”(SELECT“emp_seq”,emp_seq,max(effective_date)FROMsal_historys1WHEREeffective_date<=SYSDATEGROUPBYemp_seq)這就簡(jiǎn)化了判斷,并讓數(shù)據(jù)庫(kù)決定使用哪一個(gè)。非連接準(zhǔn)則進(jìn)行OR運(yùn)算如果查詢(xún)中存在進(jìn)行OR運(yùn)算的準(zhǔn)則怎么辦?如果非連接準(zhǔn)則與任何連接準(zhǔn)則進(jìn)行OR運(yùn)算,由于與連接準(zhǔn)則的OR運(yùn)算,不能使用傳遞性了。能夠使用的僅有的傳遞性是進(jìn)行AND運(yùn)算者。以下SQL說(shuō)明了帶有OR的查詢(xún),但是注意所有的連接準(zhǔn)則是與非連接準(zhǔn)則進(jìn)行AND運(yùn)算。SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=t.proj_seqAND(e.emp_seqIN(SELECTemp_seqFROMdependentsWHERErelation=′SPOUSE′)ORt.rpt_date=SYSDATE-7)以下的SQL不使用括號(hào)來(lái)指定準(zhǔn)則的優(yōu)先次序。使用默認(rèn)的優(yōu)先次序——AND在OR之前執(zhí)行。1SELECT*FROMemploveese,assignmentsa,time_sheetst2WHEREe.emp_seq=a.emp_seq3ORe.emp_seqIN(SELECTemp_seqFROMdependents4WHERErelation=′SPOUSE′)5ANDa.emp_seq=t.emp_seq6ANDa.proj_seq=t.proj_seq在這種情況下,在第5行和第6行中只有與非連接準(zhǔn)則進(jìn)行AND運(yùn)算的連接準(zhǔn)則?!癳.emp_seq=a.emp_seq”的傳遞性不能使用。并且由于沒(méi)有與非連接準(zhǔn)則進(jìn)行AND運(yùn)算的連接準(zhǔn)則引用“e.emp_seq”,就沒(méi)有傳遞值。外部連接如果查詢(xún)中存在非連接準(zhǔn)則但是有外部連接怎么辦?下一個(gè)實(shí)例給出了說(shuō)明了SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seq(+)ANDa.emp_seq=t.emp_seq(+)ANDa.proj_seq=t.proj_seq(+)ANDe.emp_seqIN(SELECTemp_seqFROMdependentsWHERErelation=′SPOUSE′)由于這里的非連接準(zhǔn)則在“e.emp_seq”上有一個(gè)運(yùn)算對(duì)象,并且在來(lái)自非外部連接表格的等價(jià)列處沒(méi)有連接準(zhǔn)則,就沒(méi)有傳遞值。以下的實(shí)例與前一個(gè)略有不同。SELECT*FROMemployeese,assignmentsa,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seq(+)ANDa.proj_seq=t.proj_seq(+)ANDe.emp_seqIN(SELECTemp_seqFROMdependentsWHERErelation=′SPOUSE′)在這個(gè)實(shí)例中,TIME_SHEETS是僅有的外部連接表格。所以在這個(gè)實(shí)例中,傳遞性“e.emp_seq=a.emp_seq”能夠使用,但是不能使“e.emp_seq”等于“t.emp_seq”。簡(jiǎn)單非連接準(zhǔn)則的傳遞性以下的查詢(xún)將被用于解釋這個(gè)概念。1SELECT*FROMemployeese,dependentsd2WHEREe.emp_seq=d.emp_seq3AND“d.emp_seq=1001”非連接準(zhǔn)則為“d.emp_seq=1001”(第3行)。由于基于連接準(zhǔn)則的傳遞性,該查詢(xún)可以重寫(xiě)為SELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seqAND“e.emp_seq=1001”現(xiàn)在這個(gè)非連接準(zhǔn)則在EMPLOYEES表格上了。這應(yīng)當(dāng)視為單列運(yùn)算對(duì)象帶有兩個(gè)可能值的傳遞性。非連接準(zhǔn)則和嵌套選擇的傳遞性這是一個(gè)單列傳遞性的區(qū)域,它可能是極為有益的。如果嵌套選擇在選擇列表中不具有GROUPBY語(yǔ)法和聚集,并且在引用連接列之一的主查詢(xún)中有非連接準(zhǔn)則,這種非連接準(zhǔn)則就可以移動(dòng)到嵌套選擇中。例如,非連接準(zhǔn)則是“e.emp_seqBETWEEN1001and1010”(第4行)。1SELECT*FROMemployeese,2(SELECTDISTINCTemp_seqFROMdependents)x3WHEREe.emp_seq=x.emp_seq4AND“e.emp_seqBETWEEN1001and1010”因?yàn)檫B接準(zhǔn)則和傳遞性,該查詢(xún)可以重寫(xiě)如下SELECT*FROMemployeese,(SELECTDISTINCTemp_seqFROMdependentsWHERE“emp_seqBETWEEN1001and1010”)xWHEREe.emp_seq=x.emp_seqANDe.emp_seqBETWEEN1001and1010其要點(diǎn)在于不把它視為能夠接受多個(gè)值的單列運(yùn)算對(duì)象,而是簡(jiǎn)單地在嵌套的選擇中復(fù)制準(zhǔn)則。驅(qū)動(dòng)表格可能有帶有沒(méi)有索引之非連接準(zhǔn)則的查詢(xún)。例如,一個(gè)索引搜索沒(méi)有辦法開(kāi)始查詢(xún)??赡苡写_實(shí)具有有索引之非連接準(zhǔn)則的查詢(xún)。以及最后可能有不帶有非連接準(zhǔn)則的查詢(xún)。另一個(gè)重要的考慮為連接準(zhǔn)則是不是在兩面都有索引。所有這些都必須考慮到最優(yōu)化模式是什么。注意,下面引用的發(fā)連接準(zhǔn)則包括了一個(gè)運(yùn)算對(duì)象是一個(gè)子查詢(xún)的情況。也要注意,對(duì)于帶有多于一個(gè)表格的所有子查詢(xún)以及主查詢(xún),都應(yīng)當(dāng)確定潛在的驅(qū)動(dòng)表格。如果非連接準(zhǔn)則存在確定驅(qū)動(dòng)表格是根據(jù)使用的最優(yōu)化模式。FIRSTROWS如果最優(yōu)化模式設(shè)置為FIRSTROWS,那么對(duì)于表格/視圖或者From子句中的嵌套選擇(它不是外部連接的表格),對(duì)有索引的非連接準(zhǔn)則和沒(méi)有索引的非連接準(zhǔn)則的數(shù)目進(jìn)行計(jì)數(shù)。如果表格具有任何有索引的非連接準(zhǔn)則,那么表格能夠用于驅(qū)動(dòng)查詢(xún)。如果所有表格都沒(méi)有有索引的非連接準(zhǔn)則,那么潛在的驅(qū)動(dòng)表格就是帶有任何沒(méi)有索引的非連接準(zhǔn)則者。ALLROWS如果最優(yōu)化模式設(shè)置為ALLROWS,那么對(duì)于表格/視圖或者From子句中的嵌套選擇(它不是外部連接的表格),只須非連接準(zhǔn)則的數(shù)目進(jìn)行計(jì)數(shù),無(wú)論是有索引的還是沒(méi)有索引的。潛在的驅(qū)動(dòng)表格就是帶有任何非連接準(zhǔn)則者。(該計(jì)數(shù)后來(lái)將用于確定連接次序。)以下SQL語(yǔ)句將用于說(shuō)明最優(yōu)化模式和變換兩個(gè)方面。SELECT*FROMemployeese,dependentsd,assignmentsaWHEREe.emp_seq=d.emp_seqANDe.emp_seq=a.emp_seqANDlnamelike‘SM%’ANDfname=‘ED’ANDrelation=‘SPOUSE’對(duì)于上面的SQL,如果最優(yōu)化模式為FIRSTROWS,因?yàn)長(zhǎng)NAME(我們可以忘記FNAME是連接索引的一部分這一事實(shí))上的有索引的非連接準(zhǔn)則,EMPLOYEES可以是驅(qū)動(dòng)表格。RELATION上的非連接準(zhǔn)則是沒(méi)有索引的,所以IEPENDENTS不能是驅(qū)動(dòng)表格。此外,ASSIGNMENTS上沒(méi)有非連接準(zhǔn)則。所以,僅有的潛在驅(qū)動(dòng)表格是EMPLOYEES。對(duì)于上面的SQL,如果最優(yōu)化模式為ALLROWS,因?yàn)镋MPLOYEES和DEPENDENTS都有非連接準(zhǔn)則,它們都可以是驅(qū)動(dòng)表。而且,ASSIGNMENTS沒(méi)有非連接準(zhǔn)則,因而不能是驅(qū)動(dòng)表。如果沒(méi)有非連接準(zhǔn)則如果絕對(duì)沒(méi)有非連接準(zhǔn)則,而且我們或者通過(guò)引用的完整性,或者通過(guò)用戶(hù)連接,知道了層次(其中使用唯一索引一方是父級(jí)一方,而使用非唯一索引一方是子級(jí)一方),那么驅(qū)動(dòng)表格應(yīng)當(dāng)是最頂端的父級(jí)。對(duì)于FIRSTROWS和ALLROWS兩種最優(yōu)化模式,都應(yīng)當(dāng)如此。例如,假設(shè)在以下的實(shí)例中沒(méi)有引用的完整性SELECT*FROMemployeese,dependentsd,assignmentsaWHEREe.emp_seq=d.emp_seqANDe.emp_seq=a.emp_seqEMPLOYEES和DEPENDENTS之間的連接,使用了EMPLOYEES一方的唯一索引和DEPENDENTS一方的非唯一索引。所以,EMPLOYEES視為父級(jí),而DEPENDENTS視為一個(gè)子級(jí)。EMPLOYEES和ASSIGNMENTS之間的連接,使用了EMPLOYEES一方的唯一索引。不過(guò),在ASSIGNMENTS一方?jīng)]有索引(有一個(gè)索引包括EMP_SEQ但是不作為導(dǎo)引列)。下一節(jié)“如果沒(méi)有索引的連接準(zhǔn)則”將解釋這一點(diǎn)的重要性。所以對(duì)于上面的實(shí)例,EMPLOYEES會(huì)是驅(qū)動(dòng)查詢(xún)的唯一候選者(盡管在下一節(jié)中你將看到,由于缺乏連接索引,ASSIGNMENTS也可以被視為潛在的驅(qū)動(dòng)者)。一個(gè)查詢(xún)中有不止一個(gè)表格能夠被視為最頂端的表格時(shí)怎么辦?以下的SQL可說(shuō)明。SELECT*FROMemployeese,dept_historydh,departmentsdWHEREe.emp_seq=dh.emp_seqANDdh.dept_seq=d.dept_seq在這種情況下,EMPLOYEES和DEPENDENTS都是DEPT_HISTORY的父級(jí)。所以,兩者都能夠被試用為驅(qū)動(dòng)表格。沒(méi)有索引的連接準(zhǔn)則如果某個(gè)表格的連接沒(méi)有索引,那么該表格是驅(qū)動(dòng)查詢(xún)的一個(gè)候選者,如果最優(yōu)化模式為ALLROWS的話(huà)。注意,即使該表格不具有任何非連接準(zhǔn)則而其它表格卻有,該表格也能夠驅(qū)動(dòng)一個(gè)ALLROWS查詢(xún)。如果最優(yōu)化模式為FIRSTROWS,這樣一個(gè)表格就不會(huì)如此對(duì)待,除非表格上有非連接準(zhǔn)則。例如,使用前面的規(guī)則,給予帶有有索引之準(zhǔn)則的表格優(yōu)先設(shè)置。以下的實(shí)例說(shuō)明了SELECT*FROMemployeese,assignmentsa,projectspWHEREa.proj_seq=p.proj_seqANDe.emp_seq=a.emp_seq在上面的查詢(xún)中,ASSIGNMENTS在“a.proj_seq”上不具有所引。所以ASSIGNMENTS也是ALLROWS最優(yōu)化模式下的驅(qū)動(dòng)查詢(xún)的一個(gè)候選者。外部連接如果某個(gè)表格是外部連接的,它就不應(yīng)當(dāng)用作驅(qū)動(dòng)表格。所以,如以下實(shí)例所示,即使在DEPENDENTS上有某個(gè)非連接準(zhǔn)則,DEPENDENTS仍然不能用于驅(qū)動(dòng)查詢(xún)。SELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seq(+)ANDd.relation(+)=‘SPOUSE’FROM子句嵌套選擇以下的查詢(xún)將說(shuō)明外部連接帶來(lái)的問(wèn)題。由于嵌套選擇作為非連接準(zhǔn)則中的一個(gè)子查詢(xún),該子查詢(xún)應(yīng)當(dāng)永遠(yuǎn)是一個(gè)驅(qū)動(dòng)表格。事實(shí)上,所有不是外部連接的嵌套SELECTS都首先連接,無(wú)論它們是否具有非連接準(zhǔn)則。在以下的查詢(xún)中,子查詢(xún)首先連接時(shí)出現(xiàn)了最佳方案,因而效率更高地驅(qū)動(dòng)了歷史記錄的選擇。在下面的ORDERED線(xiàn)索一節(jié)還要討論這一點(diǎn)。SELECTe.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seqFROMemployeese,sal_historys,job_historyj,dept_historyd,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historyGROUPBYemp_seq)x1,(SELECTemp_seq,MAX(effective_date)col1FROMjob_historyGROUPBYemp_seq)x2,(SELECTemp_seq,MAX(effective_date)col1FROMdept_historyGROUPBYemp_seq)x3WHEREe.emp_seq=s.emp_seqANDe.emp_seq=j(luò).emp_seqANDe.emp_seq=d.emp_seqANDs.emp_seq=x1.emp_seqANDs.effective_date=x1.col1ANDj.emp_seq=x2.emp_seqANDj.effective_date=x2.col1ANDd.emp_seq=x3.emp_seqANDd.effective_date=x3.col1視圖理想情況下,系統(tǒng)應(yīng)當(dāng)為非連接準(zhǔn)則檢驗(yàn)視圖定義本身,同時(shí)檢驗(yàn)查詢(xún)包含該視圖。如果視圖定義包含一個(gè)視圖,你就不會(huì)遞歸地檢驗(yàn)該視圖了。一個(gè)級(jí)別就足夠了,往往這也是全部需要。也要記住視圖可能是多個(gè)表格的一個(gè)連接。為了簡(jiǎn)化處理,把視圖看作一個(gè)潛在的驅(qū)動(dòng)表格。連接次序在決定連接次序之前,系統(tǒng)需要知道從何處開(kāi)始。例如,什么是潛在的驅(qū)動(dòng)表格/視圖或者From子句中的嵌套選擇。(參見(jiàn)上面的驅(qū)動(dòng)表格。)ORDERED線(xiàn)索將用于指定連接次序。首先,對(duì)于我們將要指定連接次序的SQL語(yǔ)句,不用ORDERED線(xiàn)索對(duì)它進(jìn)行測(cè)試。例如,這將是(不用ORDERED線(xiàn)索)測(cè)試的第一種置換。其它置換將根據(jù)決定的不同驅(qū)動(dòng)表格。如果某個(gè)SQL語(yǔ)句具有能夠驅(qū)動(dòng)查詢(xún)的兩個(gè)表格,那么至少將有三種置換原始的和兩種使用ORDERED線(xiàn)索和不同驅(qū)動(dòng)表格的。采取驅(qū)動(dòng)表格之一??匆幌翭ROM子句中對(duì)象之間的層次,檢驗(yàn)?zāi)膫€(gè)連接例程將遇到“最多的”非連接準(zhǔn)則(其中FIRSTROWS尋找有索引的非連接準(zhǔn)則——如果它們存在,否則尋找沒(méi)有索引的非連接準(zhǔn)則;ALLROWS只是尋找最多的非連接準(zhǔn)則,無(wú)論是否有索引)。所有對(duì)象以非連接準(zhǔn)則連接之后,其它的連接就無(wú)關(guān)緊要了,所以不產(chǎn)生那些表格的變化。以下的實(shí)例將予以說(shuō)明。實(shí)例1下面的實(shí)例是用于ALLROWS最優(yōu)化模式。SELECTe.*FROMemployeese,time_sheetst,projectsp,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historysWHEREsal>100GROUPBYemp_seq)xWHEREe.emp_seq=t.emp_seqANDt.proj_seq=p.proj_seqANDp.name=‘PAFO’ANDt.emp_seq=x.emp_seqANDt.rpt_date=x.col1在PROJECTS上有一個(gè)非連接準(zhǔn)則,對(duì)于嵌套選擇也有一個(gè)。這個(gè)實(shí)例的層次顯示在圖10中。如圖10所示,該層次把嵌套的選擇描述為EMPLOYEES的一個(gè)子級(jí)。在這種情況下可以這樣做,因?yàn)槲覀冎繱AL_HISTORY是EMPLOYEES的一個(gè)子級(jí)。虛線(xiàn)顯示了這種關(guān)系是通過(guò)傳遞性的,正如下面還要進(jìn)一步介紹的。因?yàn)閭鬟f性,如果PROJECTS用作驅(qū)動(dòng)表格,我們會(huì)希望在最多非連接準(zhǔn)則的方向上連接。這表明我們希望盡快獲得嵌套的選擇。所以該連接應(yīng)當(dāng)是PROJECTS->TIME_SHEETS->nestedselect->EMPLOYEES.如果嵌套的選擇用作驅(qū)動(dòng)者,該連接應(yīng)當(dāng)是nestedselect->TIME_SHEETS->PROJECTS->EMPLOYEES實(shí)際情況是,在前面的SQL中所有非連接準(zhǔn)則也都有索引,所以會(huì)使用相同的連接次序。實(shí)例2SELECT*FROMemployeese,(SELECTemp_SeqFROMdependents)xWHEREe.emp_seq=x.emp_seqANDe.emp_seqBETWEEN1001and1010下面的實(shí)例是用于FIRSTROWS或者ALLROWS最優(yōu)化模式。EMPLOYEES和嵌套的選擇之間的連接準(zhǔn)則在雙方都是有索引的。不過(guò),由于非連接準(zhǔn)則應(yīng)當(dāng)在嵌套的選擇中復(fù)制(回顧上面關(guān)于傳遞性一節(jié)),那么兩個(gè)對(duì)象都能夠驅(qū)動(dòng)查詢(xún)。實(shí)例3這個(gè)查詢(xún)意在用于FIRSTROWS最優(yōu)化模式。這是使用的標(biāo)準(zhǔn)歷史數(shù)據(jù)查詢(xún)。這里的要點(diǎn)在于,每個(gè)準(zhǔn)則中有運(yùn)算對(duì)象之一的非連接準(zhǔn)則是一個(gè)子查詢(xún)。由于在每種情況下其它運(yùn)算對(duì)象都是有索引的,它們被視為有索引的非連接準(zhǔn)則。SELECTe.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seqFROMemployeese,sal_historys,job_historyj,dept_historydWHEREe.emp_seq=s.emp_seqANDe.emp_seq=j(luò).emp_seqANDe.emp_seq=d.emp_seqANDs.effective_date=(SELECTMAX(effective_date)FROMsal_historys1WHEREs.emp_seq=s1.emp_seqANDeffective_date<=SYSDATE)ANDj.effective_date=(SELECTMAX(effectiv_ate)FROMjob_historyj1WHEREj.emp_seq=j(luò)1.emp_seqANDeffective_date<=SYSDATE)ANDd.effective_date=(SELECTMAX(effective_date)FROMdept_historyd1WHEREd.emp_seq=d1.emp_seqANDeffective_date<=SYSDATE)這個(gè)實(shí)例的層次顯示在圖11中。虛線(xiàn)表示了傳遞的連接。由于每一個(gè)歷史表格都有有索引的非連接準(zhǔn)則,因而它們能夠直接連接。所以,任何歷史表格都能成為驅(qū)動(dòng)表格。除了默認(rèn)的以外,不同的連接次序如下SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES或者SAL_HISTORY->JOB_HISTORY->DEPT_HISTORY->EMPLOYEES或者DEPT_HISTORY->SAL_HISTORY->JOB_HISTORY->EMPLOYEES或者DEPT_HISTORY->JOB_HISTORY->DEPT_HISTORY->EMPLOYEES或者JOB_HISTORY->DEPT_HISTORY->SAL_HISTORY->EMPLOYEES或者JOB_HISTORY->SAL_HISTORY->DEPT_HISTORY->EMPLOYEES實(shí)例4那么,如果實(shí)例3中的子查詢(xún)移動(dòng)到FROM子句中怎么辦?現(xiàn)在嵌套的選擇就有可能驅(qū)動(dòng)查詢(xún)。假設(shè)這是在ALLROWS最優(yōu)化模式下。SELECTe.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seqFROMemployeese,sal_historys,job_historyj,dept_historyd,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historyWHEREeffective_date<=SYSDATEGROUPBYemp_seq)x1,(SELECTemp_seq,MAX(effective_date)col1FROMjob_historyWHEREeffective_date<=SYSDATEGROUPBYemp_seq)x2,(SELECTemp_seq,MAX(effective_date)col1FROMdept_historyWHEREeffective_date<=SYSDATEGROUPBYemp_seq)x3WHEREe.emp_seq=s.emp_seqANDe.emp_seq=j(luò).emp_seqANDe.emp_seq=d.emp_seqANDs.emp_seq=x1.emp_seqANDs.effectivedate=x1.col1ANDj.emp_seq=x2.emp_seqANDj.effective_date=x2.col1ANDd.emp_seq=x3.emp_seqANDd.effective_date=x3.col1這個(gè)實(shí)例的層次顯示在圖12中。注意,由于EMP_SEQ的傳遞性,在歷史表格之間有傳遞的連接準(zhǔn)則。例如,由于“s.emp_seq=x1.emp_seq”,以及“s.emp_seq=e.emp_seq”,以及“e.emp_seq=j(luò).emp_seq”,以及“j.emp_seq=x2.emp_seq”,所以“x1.emp_seq=x2.emp_seq”。此外,注意對(duì)于歷史表格,沒(méi)有非連接準(zhǔn)則,只有嵌套的選擇。所以歷史表格都不能驅(qū)動(dòng)查詢(xún)。在上面論述的任何情況下,對(duì)于驅(qū)動(dòng)表格,F(xiàn)ROM子句中的嵌套子查詢(xún)永遠(yuǎn)都能是驅(qū)動(dòng)者。現(xiàn)在我們具有更多的可能連接次序。為了使它更便于觀察,給嵌套的選擇以別名;SAL_HISTORY上的嵌套選擇是S.N.;DEPT_HISTORY上的嵌套選擇是DN;等等。此外,正如前面所述,系統(tǒng)不管沒(méi)有非連接準(zhǔn)則之對(duì)象的重新排列。S.N.->DN->JN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEESS.N.->JN->DN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEESDN->S.N.->JN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEESDN->JN->S.N.->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEESJN->DN->S.N.->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEESJN->S.N.->DN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES再次注意,后面的表格在其次序中保持不變。初始次序可能變化,但是對(duì)于不同的連接次序它總是保持不變。集群表格如果某個(gè)表格組合在查詢(xún)中的一個(gè)其它表格之內(nèi),那些表格就應(yīng)當(dāng)一起連接,而不要其它表格的中間連接。例如,ASSIGNMENTS、PROJECTS和TIME_SHEETS在相同的散列集群中。以下的查詢(xún)說(shuō)明了SELECT*FROMemployeese,assignmentsa,projectsp,time_sheetstWHEREe.emp_seq=a.emp_seqANDa.emp_seq=t.emp_seqANDa.proj_seq=p.proj_seqANDa.proj_seq=t.proj_seqANDt.rpt_dateBETWEEN′01-JAN-97′AND′30-JAN-97′這個(gè)實(shí)例的層次顯示在圖13中。傳遞的連接關(guān)系由圖13中的虛線(xiàn)顯示。僅有TIME_SHEETS具有非連接準(zhǔn)則。所以TIME_SHEETS將是唯一的驅(qū)動(dòng)者。由于集群和別處缺乏非連接準(zhǔn)則,所有的集群表格都應(yīng)當(dāng)依次連接如下TIME_SHEETS->ASSIGNMENTS->PROJECTS->EMPLOYEESORDERED線(xiàn)索ORDERED線(xiàn)索永遠(yuǎn)可用。不過(guò),如果連接準(zhǔn)則允許連接的次序,系統(tǒng)的效率將更高。這往往表明增加與當(dāng)前連接準(zhǔn)則中傳遞性對(duì)應(yīng)的連接準(zhǔn)則。挑選連接次序時(shí),系統(tǒng)必須檢驗(yàn)是否存在顯式的連接準(zhǔn)則。如果沒(méi)有,那么系統(tǒng)應(yīng)當(dāng)通過(guò)傳遞性檢驗(yàn)連接準(zhǔn)則的隱含之處。如果存在隱含的連接準(zhǔn)則,該準(zhǔn)則應(yīng)當(dāng)在測(cè)試之前加到查詢(xún)中。由于參數(shù)已經(jīng)嵌入在ORDERED線(xiàn)索之內(nèi),隱含的連接準(zhǔn)則應(yīng)當(dāng)繼續(xù)留在ORDERED線(xiàn)索中。允許用戶(hù)手工使用ORDERED線(xiàn)索時(shí),系統(tǒng)以這種方式處理連接次序,因?yàn)椴恍枰獮榱似渌顑?yōu)化模式而修改SQL文本。對(duì)于下面的實(shí)例,雖然表格X1和X2之間沒(méi)有顯式的連接準(zhǔn)則,通過(guò)傳遞性確實(shí)存在一個(gè)連接。檢驗(yàn)的方法是沿著從X1到X2的連接路徑。例如,從X1到S,連接為“x1.emp_seq=s.emp_seqANDx1.col1=s.effective_ate”。從S到E連接也通過(guò)EMP_SEQ。這就隱含了“x1.emp_seq=e.emp_seq”。繼續(xù)沿著該連接路徑到X2,從E到D也通過(guò)EMP_SEQ。因此可以說(shuō)“x1.emp_seq=d.emp_seq”。最后該路徑通過(guò)“d.emp_seq=x2.emp_seqANDd.effective_date=x2.col1”從D到X2。所以,該路徑最后為“x1.emp_seq=x2.emp_seq”。由于ORDERED線(xiàn)索需要X1連接X(jué)2,并且隱含連接準(zhǔn)則“x1.emp_seq=x2.emp_seq”存在,應(yīng)當(dāng)增加該準(zhǔn)則作為ORDERED的一個(gè)參數(shù)。為了獲得X2和X3之間的傳遞連接準(zhǔn)則,可以執(zhí)行同樣的過(guò)程。例如,“x2.emp_seq=x3.emp_seq”。由于X3并非顯式地連接到E,系統(tǒng)應(yīng)當(dāng)包括連接準(zhǔn)則“x3.emp_seq=e.emp_seq”。對(duì)于隱含的連接準(zhǔn)則,建議的ORDERED線(xiàn)索格式如下SELECT/*+ORDERED(x1,x2,x3,e,s,j,d,“x1.emp_seq=x2.emp_seq”,“x2.emp_seq=x3.emp_seq”,“x3.emp_seq=e.emp_seq”)*/e.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seqFROMemployeese,sal_historys,job_historyj,dept_historyd,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historyGROUPBYemp_seq)x1,(SELECTemp_seq,MAX(effective_date)col1FROMjob_historyGROUPBYemp_seq)x2,(SELECTemp_seq,MAX(effective_date)col1FROMdept_historyGROUPBYemp_seq)x3WHEREe.emp_seq=s.emp_seqANDe.emp_seq=j(luò).emp_seqANDe.emp_seq=d.emp_seqANDs.emp_seq=x1.emp_seqANDs.effectivedate=x1.col1ANDj.emp_seq=x2.emp_seqANDj.effective_date=x2.col1ANDd.emp_seq=x3.emp_seqANDd.effective_date=x3.col1FROM子句中的嵌套選擇如果嵌套的選擇在FROM子句中,并且非連接準(zhǔn)則在主SQL模塊中引用它,系統(tǒng)將核實(shí)把該準(zhǔn)則移動(dòng)到嵌套SELECT的WHERE子句中。例如SQL語(yǔ)句,SELECT*FROMemployeese,(SELECTDISTINCTemp_seq,relationFROMdependentsdWHEREbirthdate>‘01-jan-80’)xWHEREe.emp_seq=x.emp_seqANDx.relation=‘SPOUSE’能夠變換為SELECT*FROMemployeese,(SELECTDISTNCTemp_seq,relationFROMdependentsdWHEREbirthdate>‘01-jan-80’ANDrelation=‘SPOUSE’)xWHEREe.emp_seq=x.emp_seq在這種情況下,非連接準(zhǔn)則移動(dòng)到子查詢(xún),以便進(jìn)一步減少先前合格的、連接后要過(guò)濾的行數(shù)。應(yīng)當(dāng)注意,雖然某些數(shù)據(jù)庫(kù)可能已經(jīng)考慮到這一點(diǎn),把該準(zhǔn)則移動(dòng)到WHERE子句還是有益的,加之更便于指定線(xiàn)索。進(jìn)行NOT運(yùn)算的邏輯一般說(shuō)來(lái),以?xún)?yōu)化而論,本文不考慮進(jìn)行NOT運(yùn)算的準(zhǔn)則,因?yàn)樗鼰o(wú)關(guān)緊要。換句話(huà)說(shuō),典型情況下數(shù)據(jù)庫(kù)自動(dòng)處理進(jìn)行NOT運(yùn)算之準(zhǔn)則的調(diào)換。NVL函數(shù)如果該函數(shù)的默認(rèn)參數(shù)不等于運(yùn)算對(duì)象常數(shù),那么返回NULL時(shí)WHERENVL(cost,0)=10將取值為WHERE0=10。所以,由于默認(rèn)值(0)不等于10,NVL函數(shù)能夠去掉,因此允許準(zhǔn)則使用索引。如果準(zhǔn)則不能使用索引,就什么都不做。如果該列不是可空的,那么也什么都不做,因?yàn)橥耆珱](méi)有要NVL函數(shù)的理由。WHERENVL(cost,0)=0不應(yīng)當(dāng)調(diào)換,除非存在著其它有索引的準(zhǔn)則。例如,要是這種情況確實(shí)發(fā)生了,系統(tǒng)會(huì)不得不調(diào)換為WHEREcost=0ORcostISNULL。那仍然會(huì)需要不用其它有索引之準(zhǔn)則的全表格掃描。例如,看一看下面的實(shí)例SELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seqANDe.hiredate=SYSDATE-7ANDNVL(d.birthdate,’01-JAN-80’)=’01-JAN-80’能夠變換為現(xiàn)在,這能夠進(jìn)一步變換為SELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seqANDe.hiredate=SYSDATE-7AND(d.birthdate=’01-JAN-80’ORd.birthdateISNULL)SELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seqANDe.hiredate=SYSDATE-7ANDd.birthdate=’01-JAN-80’UNIONALLSELECT*FROMemployeese,dependentsdWHEREe.emp_seq=d.emp_seqANDe.hiredate=SYSDATE-7ANDd.birthdateISNULL分別優(yōu)化每個(gè)SQL模塊(如每個(gè)嵌套的查詢(xún))變得更加可能了。此外,注意該變換不包括底層模塊中標(biāo)準(zhǔn)的不等式。它不必如此,因?yàn)镺R在同一列。下面將更詳細(xì)地討論進(jìn)行OR運(yùn)算的準(zhǔn)則。進(jìn)行OR運(yùn)算的準(zhǔn)則以下實(shí)例介紹了系統(tǒng)如何處理進(jìn)行OR運(yùn)算的準(zhǔn)則。例如,SQL語(yǔ)句,select*fromtabwhereA=10ORB=20能夠重寫(xiě)為select*fromtabwhere(A=10)UNIONALLSelect*fromtabwhere(A?。?0)AND(B=20)如果列A和B可空,那么該方法會(huì)是某個(gè)WHERE子句寫(xiě)為,select*fromtabwhere(A=10)UNIONALLselect*fromtabwhere(A!=10ORAISNULL)AND(B=20)寫(xiě)成如下形式的WHERE子句whereA=10or(B=20ANDC=1)能夠重寫(xiě)為WHEREA=10UNIONALLWHEREA?。?0AND(B=20ANDC=1)如果列是可空的,應(yīng)當(dāng)增加‘ISNOTNULL’。新方案運(yùn)算位圖鍵迭代某個(gè)子查詢(xún)輸出多個(gè)值,然后去往位圖索引時(shí),就會(huì)發(fā)生這種情況。遇到IN等運(yùn)算符時(shí),也要檢驗(yàn)是否發(fā)生這種情況。過(guò)去對(duì)于位圖索引中的IN運(yùn)算符,是BITMAPOR處理多值情況。其它線(xiàn)索在數(shù)據(jù)倉(cāng)庫(kù)中,可以使用一種星形模式來(lái)描述一個(gè)或多個(gè)非常大的事實(shí)表格,表格中包含著數(shù)據(jù)倉(cāng)庫(kù)中的主要信息和若干個(gè)維數(shù)小得多的表格(如查找表格),每個(gè)小表格包含著事實(shí)表格中某個(gè)具體屬性條目有關(guān)的信息。星形查詢(xún)是事實(shí)表格和若干查找表格之間的一種連接。每個(gè)查找表格連接事實(shí)表格,是使用一種主鍵到外來(lái)鍵的連接。不過(guò),查找表格并不相互連接。星形變換是一種基于成本的查詢(xún)變換,致力于高效地執(zhí)行星形查詢(xún)。雖然星形最優(yōu)化可能對(duì)于小維數(shù)和致密的事實(shí)表格很適用,但是如果以下的任何一條成立的話(huà),星形變換也可以被視為一種替代方案。例如,假若維數(shù)大或者假若事實(shí)表格稀疏,星形變換可能有用。此外,對(duì)于并非所有維的表格都具有限定性謂語(yǔ)的查詢(xún),星形變換可能有用。星形變換不依賴(lài)于計(jì)算維表格的笛卡爾乘積,這使它更適于事實(shí)表格稀疏和維數(shù)大的情況,這種情況會(huì)導(dǎo)致大的笛卡爾乘積,而與事實(shí)表格中實(shí)際匹配的行卻不多。此外,星形變換不是依賴(lài)于連接索引,而是基于位圖索引與事實(shí)表格中各列的結(jié)合。因此該變換能夠結(jié)合與限定維嚴(yán)格對(duì)應(yīng)的索引。沒(méi)有必要產(chǎn)生許多連接索引,其中不同的列次序匹配不同查詢(xún)中限定維的不同模式?!癝TAR_TRANSFORMATION”使本系統(tǒng)使用最好的方案,其中使用了變換。在事實(shí)表格中有位圖索引和維表格中有足夠的準(zhǔn)則時(shí),就會(huì)發(fā)生這種情況。帶有特定特征的表格不支持星形變換。例如,帶有以下特征的表格不支持。帶有與位圖存取路徑不兼容之表格線(xiàn)索的表格,帶有太少的位圖索引的表格(為了優(yōu)化器考慮產(chǎn)生一個(gè)子查詢(xún),事實(shí)表格一列上應(yīng)當(dāng)有一個(gè)位圖索引),遠(yuǎn)程表格(不過(guò),在產(chǎn)生的子查詢(xún)中允許遠(yuǎn)程維表格),反連接表格,在子查詢(xún)中已經(jīng)用作維表格的表格,視圖真正分離而不是視圖部分的表格,具有良好的單表格存取路徑的表格以及對(duì)于變換來(lái)說(shuō)太小而不值得做的表格。以下實(shí)例說(shuō)明了在查詢(xún)中早期減少嵌套選擇的結(jié)果。例如,如果用戶(hù)輸入下面帶有FROM子句中的嵌套選擇的查詢(xún)。SELECTe.*FROMemployeese,time_sheetst,projectsp,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historysGROUPBYemp_seq)xWHEREe.emp_seq=t.emp_seqANDt.proj_seq=p.proj_seqANDp.name=‘PAFO’ANDt.emp_seq=x.emp_seqANDt.rpt_date=x.col1“ANDx.col1<SYSDATE”用戶(hù)應(yīng)當(dāng)放置了帶有嵌套選擇的準(zhǔn)則,如下所示。那樣的話(huà),就能夠早期減少嵌套選擇的結(jié)果。SELECTe.*FROMemployeese,time_sheetst,projectsp,(SELECTemp_seq,MAX(effective_date)col1FROMsal_historysGROUPBYemp_seq“HAVINGMAX(effective_date)<SYSDATE)”xWHEREe.emp_seq=t.emp_seqANDt.proj_seq=p.proj_seqANDp.name=‘PAFO’ANDt.emp_seq=x.emp_seqANDt.rpt_date=x.col1OBJECTINSTANCE如果某個(gè)表格不在最優(yōu)化期間存取,系統(tǒng)將不能在SQL語(yǔ)句中鑒別是哪個(gè)表格。例如,在以下的SQL語(yǔ)句中,ASSIGNMENTS和PROJECTS都是僅僅由它們的索引存取在ALLROWS模式下表示的。換句話(huà)說(shuō),該表格不必存取。所以,如果用戶(hù)對(duì)ASSIGNMENTS單擊索引操作,在該SQL中將不會(huì)選中任何內(nèi)容來(lái)確認(rèn)該方案和該SQL之間的關(guān)系。SELECT*FROMemployeese,(SELECTDISTINCTemp_seqFROMassignmentsa,projectspWHEREa.proj_seq=p.proj_seq)xWHEREe.emp_seq=x.emp_seq系統(tǒng)至少應(yīng)當(dāng)檢驗(yàn)該表格在整個(gè)SQL語(yǔ)句中是不是唯一的。如果是,那么用戶(hù)單擊索引操作時(shí),系統(tǒng)應(yīng)當(dāng)選中該表格。OBJECTINSTANCE在FROM子句中有嵌套選擇時(shí),本系統(tǒng)不考慮給予嵌套選擇的OBJECT_INSTANCE值,以及給予嵌套選擇內(nèi)部對(duì)象的OBJECT_INSTANCE值。改變SQL如果用戶(hù)希望FIRSTROWS模式,一般說(shuō)來(lái)在把子查詢(xún)移動(dòng)到FROM子句中它不會(huì)有意義。合并總是好的,但是不必移動(dòng)。例如檢驗(yàn)歷史數(shù)據(jù)查詢(xún)的實(shí)例。事實(shí)上,離開(kāi)關(guān)聯(lián)的子查詢(xún),或者甚至把不關(guān)聯(lián)的轉(zhuǎn)換為關(guān)聯(lián)的可能有意義。增加ORDERED線(xiàn)索時(shí),它申請(qǐng)一個(gè)不同于指定的原始SQL的連接次序,系統(tǒng)重新排列FROM子句并傳遞到數(shù)據(jù)庫(kù)。不過(guò),系統(tǒng)重新排列時(shí),它仍然顯示帶有參數(shù)的原始ORDERED線(xiàn)索。由于參數(shù)不是實(shí)際線(xiàn)索語(yǔ)法的一部分,顯示SQL的HINTS模式時(shí),系統(tǒng)丟棄了ORDERED線(xiàn)索的參數(shù)。例如,如果EDIT窗口中的原始SQL為SELECT/*+HINT1ORDERED(s,d,e,j)*/*FROMemployeese,sal_historys,job_historyj,dept_historydWHEREe.emp_seq=s.emp_seqANDe.emp_seq=j(luò).emp_seqANDe.emp_seq=d.emp_seqANDs.sal>500ANDj.job_seq=10ANDd.effective_date=j(luò).effective_dateANDs.effective_date=j(luò).effective_datetheHINTS1windowshoulddisplaySELECT/*+ORDERED*/*FROMsal_historys,dept_historyd,employeese,job_historyjWHEREe.emp_seq=s.emp_seqANDe.emp_seq=j(luò).emp_seqANDe.emp_seq=d.emp_seqANDs.sal>500ANDj.job_seq=10ANDd.effective_date=j(luò).effective-dateANDs.effective_date=j(luò).effective_date這與關(guān)鍵字HINTS1的消失一致,再加上FROM子句的變化。換句話(huà)說(shuō),對(duì)于特定的模式,SQL窗口應(yīng)當(dāng)原原本本地顯示傳遞到數(shù)據(jù)庫(kù)的內(nèi)容。當(dāng)連接準(zhǔn)則增加到ORIERED線(xiàn)索時(shí),應(yīng)當(dāng)這樣做。報(bào)告從產(chǎn)生一種直方圖來(lái)說(shuō),推薦哪些“有索引的列(單列索引)”也許有益,會(huì)是一種有用的報(bào)告。由于僅僅對(duì)于不具有正態(tài)分布的列,才應(yīng)當(dāng)構(gòu)造直方圖,我們需要找到不具有正態(tài)分布的列?!熬€(xiàn)索”對(duì)于ALLROWS,“連接到表格”索引大于表格時(shí),表示FULL。SQL檢驗(yàn)如果子查詢(xún)以關(guān)系運(yùn)算符NOTIN或任何形式的ALL連接,系統(tǒng)就能夠顯示以下消息,并選中該子查詢(xún)——如果可能的話(huà)“如果子查詢(xún)不返回行(空集),包括該子查詢(xún)的準(zhǔn)則將取值為T(mén)RUE,換句話(huà)說(shuō),子查詢(xún)不返回行時(shí),它的作用與NOTEXISTS完全相同?!备淖僑QL子查詢(xún)返回了將饋入引用同一表格之準(zhǔn)則的列時(shí),應(yīng)當(dāng)改變?cè)撟硬樵?xún)的選擇列表,使它包含ROWID。例如,看一看下面的歷史查詢(xún),SELECT*FROMemployeese,sal_historys1WHEREe.emp_seq=s1.emp_seqANDs1.effective_date=(SELECTmax(effective_date)FROMsal_historys2WHEREe.emp_seq=s2.emp_seqANDs2.effective_date<=SYSDATE)可以變換為SELECT*FROMemployeese,sal_historys1WHEREe.emp_seq=s1.emp_seqANDs1.“ROWID”=(SELECT“ROWID”FROMsal_historys2WHEREe.emp_seq=s.emp_seqANDs2.effective_date<=SYSDATE)線(xiàn)索應(yīng)用線(xiàn)索時(shí),用戶(hù)必須負(fù)責(zé)查看線(xiàn)索是否見(jiàn)效。本系統(tǒng)能夠提供反饋,通知用戶(hù)線(xiàn)索確實(shí)具有所需的效果。例如,系統(tǒng)可能通知用戶(hù)ORDERED線(xiàn)索是否以指定的次序連接。對(duì)于包括NOTIN或NOTEXISTS子查詢(xún)的查詢(xún),可以應(yīng)用傳遞性,所以外層查詢(xún)中的連接列屬于同一表格。這就合并了NOTIN和NOTEXISTS子查詢(xún),因?yàn)橐粋€(gè)表格不能外部連接到多于一個(gè)表格。例如以下的SQL語(yǔ)句,SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqAND(e.emp_seq,a.start_date)NOTIN(SELECTemp_seq,rpt_dateFROMtime_sheets)能夠轉(zhuǎn)換為SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqAND(a.emp_seq,a.start_date)NOTIN(SELECTemp_seq,rpt_dateFROMtime_sheets)然后它能夠轉(zhuǎn)換為SELECTe.*,a.*FROMemployeese,assignmentsa,time_sheetst1WHEREe.emp_seq=a.emp_seqANDa.emp_seq=t1.emp_seq(+)ANDa.start_date=t1.rpt_date(+)ANDt1.ROWIDISNULL以下的實(shí)例說(shuō)明了合并要連接的NOTIN和NOTEXISTS子查詢(xún)。例如,SQL語(yǔ)句,SELECT*FROMemployeeseWHERENOTEXISTS(SELECT*FROMassignmentsaWHEREe.emp_seq=a.emp_seq)將轉(zhuǎn)換為SELECT/*+ALL_ROWS*/e.*FROMemployeese,(SELECTDISTINCT1col2,a.emp_seqcol1FROMassignmentsa)t1WHEREe.emp_seq=t1.col1(+)ANDt1.col2ISNULL不過(guò),該子查詢(xún)應(yīng)當(dāng)合并如下SELECTe.*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seq(+)ANDa.emp_seqISNULL系統(tǒng)通過(guò)把外層的連接列中的常數(shù)移動(dòng)到子查詢(xún)中,能夠把SQL4轉(zhuǎn)換到SQL5再轉(zhuǎn)換到SQL6,如下所示。例如,原始SQL語(yǔ)句,SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqAND(e.emp_seq,′22-FEB-94′)NOTIN(SELECTemp_seq,rpt_dateFROMtime_sheets)SQL4能夠變換為SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqANDe.emp_seqNOTIN(SELECTemp_seqFROMtime_sheetsWHERErpt_date=′22-FEB-94′)SQL5它能夠變換為SELECTe.*,a.*FROMemployeese,assignmentsa,time_sheetst1WHEREe.emp_seq=a.emp_seqANDa.emp_seq=t1.emp_seq(+)ANDt1.rpt_date(+)=′22-FEB-94′ANDt1.ROWIDISNULLSQL6以下的查詢(xún)不能轉(zhuǎn)換,因?yàn)槿绻喜ⅲ撟硬樵?xún)表格必須外部連接到一個(gè)表格。該子查詢(xún)不能外部連接到一個(gè)單獨(dú)的常數(shù)。SELECT*FROMemployeese,assignmentsaWHEREe.emp_seq=a.emp_seqAND′22-FEB-94′N(xiāo)OTIN(SELECTrpt_dateFROMtime._sheets)SQL7如果一個(gè)子查詢(xún)的連接列是一個(gè)常數(shù),就能夠執(zhí)行合并,如果連接時(shí)所有表格都唯一的話(huà)。合并該子查詢(xún)時(shí),常數(shù)Θ設(shè)置為NOTEQUALS對(duì)應(yīng)的外層連接列,并且與‘<child>.ROWIDISNULL’進(jìn)行OR運(yùn)算。例如,SQL語(yǔ)句,SELECT*FROMemployeeseWHERE(e.emp_seq,lname)NOTIN(SELECTemp_seq,′SMITH′FROMtime_sheetsWHEREproj_seq=1ANDrpt_date=′22-feb-94′)SQL8能夠變換為SELECTe.*FROMemployeese,time_sheetst1WHEREe.emp_seq=t1.emp_seq(+)ANDproj_seq(+)=1ANDrpt_date(+)=′22-feb-94′AND(t1.ROWIDISNULLORlname<>′SMITH′)SQL9試圖變換SQL語(yǔ)句時(shí)必須謹(jǐn)慎。例如,可能試圖把以下的SQL語(yǔ)句SELECT*FROMemployeeseWHEREemp_seqNOTIN(SELECTa.emp_seqFROMprojectsp,assignmentsaWHEREa.proj_seq=p.proj_seqANDp.name=′EXPLAINSQLDEVELOPMENT′)ORDERBY1變換為以下的SELECT/*+ALL_ROWS*/e.*FROMemployeese,projectsp,assignmentsaWHEREe.emp_seq=a.emp_seq(+)ANDa.proj_seq=p.proj_seq(+)ANDp.name(+)=′EXPLAINSQLDEVELOPMENT′ANDp.ROWIDISNULLORDERBY1不過(guò),這會(huì)是不正確的,由于不可能把這里的原始SQL合并到外部查詢(xún)。這會(huì)導(dǎo)致一種不正確的變換。如果系統(tǒng)試圖增加帶有任意表格的‘ROWIDISNULL’子句,可能發(fā)生另一個(gè)問(wèn)題。例如,有時(shí)系統(tǒng)也許挑選項(xiàng)目表格,有時(shí)它也許挑選分配表格,取決于FROM子句中的次序。這會(huì)是不正確的。應(yīng)當(dāng)謹(jǐn)慎地確保最低級(jí)別的子級(jí)表格為空(如項(xiàng)目表格)。否則,向子表格(在這種情況下是項(xiàng)目)連接準(zhǔn)則將是不適當(dāng)?shù)?。在變換期間,應(yīng)當(dāng)遵循以下的規(guī)則和方針。A)只有滿(mǎn)足以下條件,本系統(tǒng)才應(yīng)當(dāng)進(jìn)行變換i)在連接次序中的所有中間表格都應(yīng)當(dāng)連接以保證唯一性。ii)可以有多于一個(gè)分支。不過(guò),最多只能有一個(gè)最低級(jí)別的子表格可為非唯一。按次序加如時(shí),所有其它的表格都應(yīng)當(dāng)是唯一的。換句話(huà)說(shuō),檢驗(yàn)以上的SQL時(shí),分配表格就是帶有連接子查詢(xún)列的表格。由于它不是最低級(jí)別的子級(jí)(項(xiàng)目表格連接它),它在選擇列表中或者在WHERE子句中的列連接帶有=運(yùn)算符的常數(shù),必然形成一個(gè)獨(dú)特的鍵。不過(guò),emp_seq不是唯一的列。所以這個(gè)子查詢(xún)不能合并。不過(guò),項(xiàng)目名稱(chēng)是唯一的列時(shí),下面的實(shí)例SQL10能夠轉(zhuǎn)換。iii)如果子查詢(xún)連接列之一是一個(gè)常數(shù),所有表格都應(yīng)當(dāng)連接以保證唯一性。iv)沒(méi)有聚集函數(shù)(只要沒(méi)有聚集,GROUPBY、DISTINCT和HAVING都可以。合并時(shí),忽略GROUPBY和DISTINCT并把HAVING準(zhǔn)則移動(dòng)到WHERE子句)v)沒(méi)有CONNECTBY語(yǔ)法vi)沒(méi)有集合運(yùn)算(如UNION、MINUS)vii)子查詢(xún)不包含外部連接。B)對(duì)于每個(gè)更低級(jí)別的子級(jí),增加‘<child>.ROWIDISNULL’并用OR連在一起。C)如果在外層的連接列中有一個(gè)常數(shù)并且有其它的連接列,改變它為與子查詢(xún)WHERE子句的相等準(zhǔn)則。D)如果在子查詢(xún)的連接列中的一個(gè)常數(shù)中有一個(gè)常數(shù),設(shè)置該常數(shù)為NOTEQUALS對(duì)應(yīng)的外層連接列并把它與‘<child>.ROWIDISNULL’進(jìn)行OR運(yùn)算。SELECT*FROMstatus_listWHEREstatusNOTIN(SELECTp.statusFROMprojectsp,assignmentsaWHEREa.proj_seq=p.proj_seqANDp.name=′EXPLAINSQLDEVELOPMENT′)SQL10確定一個(gè)外部連接是否能夠發(fā)生時(shí),關(guān)聯(lián)的子查詢(xún)可能會(huì)產(chǎn)生一個(gè)問(wèn)題。確切地說(shuō),當(dāng)NOTIN運(yùn)算符連接到關(guān)聯(lián)的子查詢(xún)時(shí),外層查詢(xún)中的連接列必須屬于與子查詢(xún)關(guān)聯(lián)的表格相同的表格。例如,參見(jiàn)下面的SQL語(yǔ)句。子查詢(xún)中的連接列應(yīng)當(dāng)屬于與子查詢(xún)關(guān)聯(lián)的表格相同的表格。在下面的實(shí)例中,HIREDATE列屬于“e.”以及關(guān)聯(lián)準(zhǔn)則之一,而其它關(guān)聯(lián)準(zhǔn)則引用“a.”所以合并是不可能的。SELECT*FROMtime_sheetstWHEREt.rpt_dateNOTIN(SELECThiredateFROMemployeese,assignmentsaWHEREa.proj_seq=t.proj_seqANDe.emp_seq=a.emp_seqANDe.emp_seq=t.emp_seq)SQL11“[NOTIN]子查詢(xún)中的連接列必須屬于與子查詢(xún)關(guān)聯(lián)的表格相同的表格”不是必需的,只要上面的規(guī)則/方針A)i)和A)ii)成立。不過(guò),因?yàn)橥獠窟B接,外層查詢(xún)中對(duì)應(yīng)的連接列應(yīng)當(dāng)屬于同一表格。如果進(jìn)行轉(zhuǎn)換,分配表格既需要外部連接到TIME_SHEETS,又需要外部連接到EMPLOYEES。這是不合法的。不過(guò),可以應(yīng)用傳遞性來(lái)把上面顯示的SQL11語(yǔ)句轉(zhuǎn)換為下面顯示的SQL12。然后SQL12可以合并到下面顯示的SQL13。這種合并是可能的,因?yàn)镋MPLOYEES和ASSIGNMENTS在連接列上都有唯一的索引。SELECT*FROMtime_sheetstWHEREt.rpt_dateNOTIN(SELECThiredateFROMemployeese,assignmentsaWHEREa.proj_seq=t.proj_seqANDt.emp_seq=a.emp_seqANDe.emp_seq=t.emp_seq)SQL12SELECT*FROMtime_sheetst,employeese,assignmentsaWHEREe.hiredate(+)=t.rpt_dateANDa.proj_seq(+)=t.proj_seqANDa.emp_seq(+)=t.emp_seqANDe.emp_seq(+)=t.emp_seqAND(a.rowidISNULLore.rowidISNULL)SQL13也應(yīng)當(dāng)注意,你不能合并在子查詢(xún)SELECT子句中帶有non-column(常數(shù)、函數(shù)等等)的NOTEXISTS或NOTIN子查詢(xún)。例如,可以把以下的SQL14試圖變換為SQL15。不過(guò),因?yàn)閠.rpt_date=’22-FEB-94’,SQL15產(chǎn)生的結(jié)果集與SQL14不同。該準(zhǔn)則可以改變?yōu)閠.rpt_date<>’22-FEB-94’。不過(guò),我們將不得不保證原始子查詢(xún)返回至少一行。這就破環(huán)了變換的目的,因?yàn)槲覀儾坏貌槐3衷撟硬樵?xún)。SELECT*FROMtime_sheetstWHERE(t.emp_seq,t.rpt_date)NOTIN(SELECTemp_seq,′22-FEB-94′FROMemployees)SQL14SELECT/*+ALL_ROWS*/t.*FROMtime_sheetst,employeest1WHEREt.emp_seq=t1.emp_seq(+)ANDt.rpt_date=′22-FEB-94′ANDt1.ROWIDISNULLSQL15設(shè)置NOTIN、NOTEXISTS子查詢(xún)可以為查詢(xún)?nèi)绻\(yùn)算符是NOTIN或者NOTEXISTS,可以調(diào)用以下的例程,試圖確定它是否應(yīng)當(dāng)試圖把子查詢(xún)轉(zhuǎn)換為一個(gè)連接。<<codebegin>>IFsubquerycontainsaggregateinSelectlistORsubquerycontainsaggregateinHAVINGclauseORsubquerycontainsConnectBysyntaxORsubquerycontainssetoperationTHENRETURNFALSELOOPovereachtableXintheFROMlist,ifthereismorethan1joincriterion,applytransitivitysothetablejointothesametable,ifpossible.InitializeUnique_listtoemptyNon_Unqiue_table=nullLOOPovereachTABLEintheFROMlistcontaininginterfacecolumnsIFCheckTableUniqueIndexColsreturnTRUE(CheckTableUniqueIndexColsroutinechecksforagiventable,whetherallthecolumnsofitsanyoneuniqueindexesarepresentinthewhereclauseandhavea′=′operationandtheotheroperandisaconstantoracorrelated.)THENaddTABLEtotheUnique_listELSEIFNon_Unqiue_tableisnullTHENNon_Unqiue_table=TABLEELSERETURNFALSEENDLOOPovereachTABLEintheFROMlistcontaininginterfacecolumnsLOOPovereachTABLEintheFROMlistcontaininginterfacecolumnsIFCheck_Unique(TABLE,interfacetableofthesurroundingquery,Unique_list,Non_Unique_table)returnsFALSERETURNFALSEENDLOOPovereachtableintheFROMlistcontaininginterfacecolumns(Makesurealltableisjoined)LOOPovereachTABLEIFTABLEnotinunique_listandTABLE<>Non_unique_tableTHENRETURNFALSEENDLOOPovereachTABLERETURNTRUE<<codeend>>檢驗(yàn)唯一性輸入TABLEPARENT_TABLENONUNIQUE_TABLE<<codebegin>>LOOPovereachtableYjoinedtoTABLEIFY=PARENT_TABLEcontinueloopIFYisinUnique_listorYisNon_unique_table(ifYisalreadyjoined,cannotjointoanothertable)THENRETURNFALSELOOPovereachindexofYIFallindexedcolumnsarejoinedtoXwith=operatorORindexcolumns=constantTHENaddYtoUnique_listIFCheck_Unique(Y,X,Unique_list,Non_unique_table)returnsFALSETHENRETURNFALSEBREAK(uniqueindexfound,noneedtosearchanymore)ENDLOOPovereachindexofYIFYnotinUnique_listIFNon_unique_tableisnullNon_unique_table=Y(jié)(SinceYisnotunique,makesurenoothertableisjoinedtoY)LOOPovereachtableZjoinedtoYIFZnotinUnique_listandZ<>Non_unique_tableTHENRETURNFALSEENDLOOPovereachtableZjoinedtoYELSERETURNFALSEENDLOOPovereachtableYjoinedtoTABLERETURNTRUE<<codeend>>如果某個(gè)WHERE子句準(zhǔn)則僅僅引用FROM子句中嵌套選擇內(nèi)的表格,就把它移動(dòng)到該嵌套選擇。例如,以下的SQLSELECT*FROMemployeese,(SELECTDISTINCTemp_seq,relationFROMdependentsdWHEREbirthdate>′01-jan-80′)xWHEREe.emp_seq=x.emp_seqANDx.reLation=′SPOUSE′能夠轉(zhuǎn)換為SELECT*FROMemployeese,(SELECTDISTINCTemp_seq,relationFROMdependentsdWHEREbirthdate>′01-jan-80′ANDx.relation=′SPOUSE′)xWHEREe.emp_seq=x.emp_seq如果某個(gè)HAVING子句準(zhǔn)則不涉及組函數(shù),它就能夠移動(dòng)到WHERE子句。例如,以下的SQL語(yǔ)句SELECTLNAME,count(*)FROMemployeesGROUPBYLNAMEHAVINGLNAME<′D′能夠變換為SELECTLNAME,count(*)FROMemployeesWHERELNAME<′D′GROUPBYLNAME使用按照本說(shuō)明書(shū)的指導(dǎo)編程的一臺(tái)或多臺(tái)常規(guī)的通用數(shù)字計(jì)算機(jī)和/或服務(wù)器,可以方便地實(shí)現(xiàn)本公開(kāi)文件。根據(jù)本公開(kāi)文件的指導(dǎo),可以容易地準(zhǔn)備適當(dāng)?shù)能浖a。此外,雖然以上的介紹引用了特定的數(shù)據(jù)庫(kù)系統(tǒng)(如Oracle),但是應(yīng)當(dāng)理解,本公開(kāi)文件不限于任何具體的數(shù)據(jù)庫(kù)或數(shù)據(jù)庫(kù)系統(tǒng)的類(lèi)型??紤]到以上的指導(dǎo),本公開(kāi)文件許多另外的修改和變化都是可能的。所以應(yīng)當(dāng)理解,在附帶的權(quán)利要求書(shū)的范疇之內(nèi),本公開(kāi)文件的實(shí)現(xiàn)方式可以不同于本文中介紹的特定方式。權(quán)利要求1.一種調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的方法,包括選擇數(shù)據(jù)庫(kù)查詢(xún);分析選定的數(shù)據(jù)庫(kù)查詢(xún)以確定選定的數(shù)據(jù)庫(kù)查詢(xún)的若干部分之間的關(guān)系;從多個(gè)可用的最優(yōu)化模式中選擇最優(yōu)化模式;根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)的至少一個(gè)部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún);以及顯示修改后的數(shù)據(jù)庫(kù)查詢(xún)。2.根據(jù)權(quán)利要求1的方法,其特征在于,該分析確定數(shù)據(jù)庫(kù)查詢(xún)之內(nèi)的標(biāo)記,標(biāo)記是由分隔符分開(kāi)的單詞。3.根據(jù)權(quán)利要求1的方法,其特征在于,多個(gè)可用的最優(yōu)化模式包括基于成本的和基于規(guī)則的模式。4.根據(jù)權(quán)利要求3的方法,其特征在于,基于成本的模式包括First_Rows模式和All_Rows模式。5.根據(jù)權(quán)利要求1的方法,進(jìn)一步包括確定與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。6.根據(jù)權(quán)利要求5的方法,進(jìn)一步包括比較兩種成本,一種是與使用選定的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本,另一種是與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。7.根據(jù)權(quán)利要求1的方法,進(jìn)一步包括分析選定的數(shù)據(jù)庫(kù)查詢(xún),以確定該數(shù)據(jù)庫(kù)查詢(xún)是否包括由NOTEXISTS、NOTIN和ALL子句中至少一個(gè)連接的至少一個(gè)子查詢(xún)。8.根據(jù)權(quán)利要求7的方法,進(jìn)一步包括提示用戶(hù)根據(jù)該數(shù)據(jù)庫(kù)查詢(xún)是否包括NOTEXISTS、NOTIN和ALL子句中的至少一個(gè),選擇調(diào)節(jié)期間使用的優(yōu)先設(shè)置。9.根據(jù)權(quán)利要求8的方法,其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠在從NOTEXISTS運(yùn)算符到NOTIN運(yùn)算符的轉(zhuǎn)換和從選定的數(shù)據(jù)庫(kù)查詢(xún)到外部連接的轉(zhuǎn)換中,選擇至少一個(gè)。10.根據(jù)權(quán)利要求8的方法,其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠選擇把ALL運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換為一個(gè)連接或外部連接。11.根據(jù)權(quán)利要求8的方法,其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠選擇是否使用一個(gè)NOTEXISTS運(yùn)算符和一個(gè)外部連接中的至少一個(gè),對(duì)NOTIN運(yùn)算符連接的子查詢(xún)進(jìn)行轉(zhuǎn)換。12.一種包括用于調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的計(jì)算機(jī)可執(zhí)行代碼的計(jì)算機(jī)存儲(chǔ)介質(zhì),包括使用戶(hù)選擇數(shù)據(jù)庫(kù)查詢(xún)的計(jì)算機(jī)可執(zhí)行代碼;用于分析選定的數(shù)據(jù)庫(kù)查詢(xún)以確定選定的數(shù)據(jù)庫(kù)查詢(xún)的若干部分之間關(guān)系的計(jì)算機(jī)可執(zhí)行代碼;使用戶(hù)從多個(gè)可用的最優(yōu)化模式中選擇最優(yōu)化模式的計(jì)算機(jī)可執(zhí)行代碼;用于根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)的至少一個(gè)部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún)的計(jì)算機(jī)可執(zhí)行代碼;以及用于顯示修改后的數(shù)據(jù)庫(kù)查詢(xún)的計(jì)算機(jī)可執(zhí)行代碼。13.根據(jù)權(quán)利要求12的計(jì)算機(jī)存儲(chǔ)介質(zhì),其特征在于,該分析確定數(shù)據(jù)庫(kù)查詢(xún)之內(nèi)的標(biāo)記,標(biāo)記是由分隔符分開(kāi)的單詞。14.根據(jù)權(quán)利要求12的計(jì)算機(jī)存儲(chǔ)介質(zhì),其特征在于,多個(gè)可用的最優(yōu)化模式包括基于成本的和基于規(guī)則的模式。15.根據(jù)權(quán)利要求14的計(jì)算機(jī)存儲(chǔ)介質(zhì),其特征在于,基于成本的模式包括First_Rows模式和All_Rows模式。16.根據(jù)權(quán)利要求12的計(jì)算機(jī)存儲(chǔ)介質(zhì),進(jìn)一步包括用于確定與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本的代碼。17.根據(jù)權(quán)利要求16的計(jì)算機(jī)存儲(chǔ)介質(zhì),進(jìn)一步包括用于比較兩種成本的代碼,一種是與使用選定的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本,另一種是與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。18.根據(jù)權(quán)利要求12的計(jì)算機(jī)存儲(chǔ)介質(zhì),進(jìn)一步包括用于分析選定的數(shù)據(jù)庫(kù)查詢(xún)的代碼,以確定該數(shù)據(jù)庫(kù)查詢(xún)是否包括由NOTEXISTS、NOTIN和ALL子句中至少一個(gè)連接的至少一個(gè)子查詢(xún)。19.根據(jù)權(quán)利要求18的計(jì)算機(jī)存儲(chǔ)介質(zhì),進(jìn)一步包括用于提示用戶(hù)根據(jù)該數(shù)據(jù)庫(kù)查詢(xún)是否包括NOTEXISTS、NOTIN和ALL子句中的至少一個(gè),選擇調(diào)節(jié)期間使用的優(yōu)先設(shè)置的代碼。20.根據(jù)權(quán)利要求19的計(jì)算機(jī)存儲(chǔ)介質(zhì),其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠在從NOTEXISTS運(yùn)算符到NOTIN運(yùn)算符的轉(zhuǎn)換和從選定的數(shù)據(jù)庫(kù)查詢(xún)到外部連接的轉(zhuǎn)換中,選擇至少一個(gè)。21.根據(jù)權(quán)利要求19的計(jì)算機(jī)存儲(chǔ)介質(zhì),其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠選擇把ALL運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換為一個(gè)連接或外部連接。22.根據(jù)權(quán)利要求19的計(jì)算機(jī)存儲(chǔ)介質(zhì),其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠選擇是否使用一個(gè)NOTEXISTS運(yùn)算符和一個(gè)外部連接中的至少一個(gè),對(duì)NOTIN運(yùn)算符連接的子查詢(xún)進(jìn)行轉(zhuǎn)換。23.一種用于調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的、編程的計(jì)算機(jī)系統(tǒng),包括一種顯示器,用于向用戶(hù)顯示至少一個(gè)數(shù)據(jù)庫(kù)查詢(xún);一種用戶(hù)輸入,使用戶(hù)從顯示的數(shù)據(jù)庫(kù)查詢(xún)中選擇一個(gè)數(shù)據(jù)庫(kù)查詢(xún),從多個(gè)可用的最優(yōu)化模式中選擇一個(gè)最優(yōu)化模式;以及一種處理器,用于分析選定的數(shù)據(jù)庫(kù)查詢(xún)以確定選定的數(shù)據(jù)庫(kù)查詢(xún)的若干部分之間關(guān)系,并用于根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)的至少一個(gè)部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún),修改后的數(shù)據(jù)庫(kù)查詢(xún)通過(guò)顯示器向用戶(hù)顯示。24.根據(jù)權(quán)利要求23的系統(tǒng),其特征在于,該分析確定數(shù)據(jù)庫(kù)查詢(xún)之內(nèi)的標(biāo)記,標(biāo)記是由分隔符分開(kāi)的單詞。25.根據(jù)權(quán)利要求23的系統(tǒng),其特征在于,多個(gè)可用的最優(yōu)化模式包括基于成本的和基于規(guī)則的模式。26.根據(jù)權(quán)利要求25的系統(tǒng),其特征在于,基于成本的模式包括First_Rows模式和All_Rows模式。27.根據(jù)權(quán)利要求23的系統(tǒng),其特征在于,該處理器確定與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。28.根據(jù)權(quán)利要求27的系統(tǒng),其特征在于,該處理器比較兩種成本的代碼,一種是與使用選定的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本,另一種是與使用調(diào)節(jié)后的數(shù)據(jù)庫(kù)查詢(xún)相關(guān)聯(lián)的成本。29.根據(jù)權(quán)利要求23的系統(tǒng),其特征在于,該處理器分析選定的數(shù)據(jù)庫(kù)查詢(xún)的代碼,以確定該數(shù)據(jù)庫(kù)查詢(xún)是否包括由NOTEXISTS、NOTIN和ALL子句中至少一個(gè)連接的至少一個(gè)子查詢(xún)。30.根據(jù)權(quán)利要求29的系統(tǒng),其特征在于,該處理器提示用戶(hù)根據(jù)該數(shù)據(jù)庫(kù)查詢(xún)是否包括NOTEXISTS、NOTIN和ALL子句中的至少一個(gè),選擇調(diào)節(jié)期間使用的優(yōu)先設(shè)置。31.根據(jù)權(quán)利要求30的系統(tǒng),其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠在從NOTEXISTS運(yùn)算符到NOTIN運(yùn)算符的轉(zhuǎn)換和從選定的數(shù)據(jù)庫(kù)查詢(xún)到外部連接的轉(zhuǎn)換中,選擇至少一個(gè)。32.根據(jù)權(quán)利要求30的系統(tǒng),其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠選擇把ALL運(yùn)算符連接的子查詢(xún)轉(zhuǎn)換為一個(gè)連接或外部連接。33.根據(jù)權(quán)利要求30的系統(tǒng),其特征在于,該優(yōu)先設(shè)置包括重寫(xiě)優(yōu)先設(shè)置,使得用戶(hù)能夠選擇是否使用一個(gè)NOTEXISTS運(yùn)算符和一個(gè)外部連接中的至少一個(gè),對(duì)NOTIN運(yùn)算符連接的子查詢(xún)進(jìn)行轉(zhuǎn)換。全文摘要一種調(diào)節(jié)數(shù)據(jù)庫(kù)查詢(xún)的方法包括選擇數(shù)據(jù)庫(kù)查詢(xún);分析選定的數(shù)據(jù)庫(kù)查詢(xún)以確定選定的數(shù)據(jù)庫(kù)查詢(xún)的若干部分之間的關(guān)系;從多個(gè)可用的最優(yōu)化模式中選擇最優(yōu)化模式;根據(jù)確定的關(guān)系和選定的最優(yōu)化模式,通過(guò)修改選定的數(shù)據(jù)庫(kù)查詢(xún)的至少一個(gè)部分,調(diào)節(jié)選定的數(shù)據(jù)庫(kù)查詢(xún)以及顯示修改后的數(shù)據(jù)庫(kù)查詢(xún)。文檔編號(hào)G06F17/30GK1592905SQ01811820公開(kāi)日2005年3月9日申請(qǐng)日期2001年5月25日優(yōu)先權(quán)日2000年5月26日發(fā)明者愛(ài)德華·凱茨尤茲庫(kù),蒙諾·薩拉庫(kù)瑪,翰-瓦農(nóng)·沃,約翰·文森特,托馬斯·沃林,喬伊斯·勞申請(qǐng)人:計(jì)算機(jī)聯(lián)合思想公司