現在你可以通過字符串建立索引提高性能
許多PL/SQL程序對數據進行操作通常是通過使用SQL在數據庫中直接操作數據你經常還需要在PL/SQL程序本身內聲明和管理數據這個程序數據可能由一些單獨的值(標量)組成但是在其他許多情況下你可能要處理更復雜的數據結構從記錄到對象(對象類型的實例)甚至是列表
列表(以及以更復雜的方式表示的數組)是程序員工具箱中最重要的元素為了創建和管理這些列表PL/SQL提供了各種各樣稱作集合的結構如嵌套表可變數組和關聯數組
在Oraclei第版中引入的關聯數組替代了索引表(它在Oracle中替代了PL/SQL表)關聯數組引入了重要的新功能在Oraclei第版中你現在可以
定義在其內部包含其它集合的集合這些被叫做多層集合的列表使你能夠在PL/SQL數據結構內部更加直觀和直接地對現實世界的情況建模我在Oracle雜志年/月號的文章多層次的編程中介紹過這個特性
我們可以創建通過字符串來建立索引行的集合(並可快速進行檢索)例如公司的名字在該集合中可以是行號
本篇文章說明怎樣通過串來對關聯數組建立索引和怎樣定義這樣的集合
用字符串來建立索引
有一個新的方法可用來定義和操作PL/SQL特定的集合特別是你除了使用行號這樣的整數值來建立索引以外你還可以通過字符串來建立索引這個方法提供了相當重要的額外靈活性請看清單中的例子
在清單中第行聲明了一個通過最大長度為個字符的串建立了索引的存儲數字的關聯數組類型第行和第行基於這個類型聲明了個關聯數組第行聲明了一個變量來存儲集合中的行號第行聲明了一個變量來存儲極限值(最低和最高的行索引值)請注意因為這個變量會接收一個基於串索引的值所以它被聲明為一個字符串在第行和第行中我將值賦給了country_population每次我都把國家的人口數賦給集合中的一行那一行的索引就是它的國名在第行中我從集合中檢索出一個值請注意我通過國名來確定那一行而腳本將返回相應的人口數從第行到第行我得到第一個定義的行值然後顯示它接著顯示那個國家的人口數數據庫是怎樣確定第一行的呢?第一行是通過數據庫中字符集特定的排序順序來確定的從第行到第行我使用對第一個定義的行值的相同的過程來得到最後一個定義的行值
對於字符串索引的集合你可能需要慢慢地習慣但是這種集合通過調用FIRSTLASTPRIOR和NEXT方法得到的返回值是字符串而不是數
字符串索引集合的使用
為什麼你應該使用字符串而不是數來建立索引呢?假設你需要在你的程序中對員工的信息進行一些大量的處理你可能需反復地處理一組選定的雇員的信息例如按雇員的ID號碼姓氏和社會保險號碼(對於美國以外的一些國家或者是相應的身份證號碼)來搜索員工
當然你可以使用SQL來完成這些任務但這遠不是最高效的實現方式如果你需要多次處理一組數量很大的靜態數據那麼你可以改為把這組數據從數據庫中移到一組集合中訪問基於集合的數據比使用SQL引擎來訪問數據要快得多
接下去你可以利用這些集合的基於字符串和基於整數的索引來模仿表(你已經把該表的數據從數據庫中傳出來了)的主鍵和特有的索引這個方法的一個簡單的例子已在清單的代碼中展示出
在清單中第行到第行聲明了兩個關聯數組類型注意我可以在INDEX BY子句中利用%TYPE在其它的子句中使用PLS_INTEGER代替BINARY_INTEGER這些都是Oraclei Release 的新功能在第行到第行我聲明了將用來提供進入數據的多個快速入口點的集合從第行到第行load_arrays過程顯示了從數據庫表將數據傳送到一個或多個(在該實例中是個集合)是多麼得容易我通過使用不同的字段值作為關鍵字把整行的雇員數據作為一個記錄存放到每一個集合中在第行中我把姓氏用作索引值在第行中我使用社會安全號碼作為索引值在第行中主關鍵字作為索引值(它是一個把整數索引作為一個智能關鍵字的相當傳統的應用)在第行中我通過使用字符串和整數索引值對兩個不同集合中的工資域進行比較
用字符串作索引的多層次集合
我已經創建了一個有趣的新實用程序叫做Codecheck它利用了 Oraclei第版集合的一些增強特性該程序包仔細審查ALL_ARGUMENT數據字典視圖的內容以便分析特定的程序包和單獨的應用程序其代碼是否符合編碼標准或揭示一些設計問題(例如不明確的超負荷)
ALL_ARGUMENTS包含關於每個存儲在數據庫(連接的用戶在其上擁有EXECUTE權限中)的過程和函數的每個參數或自變量的信息ALL_ARGUMENTS中的單一行包含關於一個自變量(或者在某些情況下一個自變量的一個域(field)或一個元素)的信息下面是為ALL_ARGUMENT定義的字段的一個子集
名字 空值? 類型
OWNER 非空值 VARCHAR()
OBJECT_NAME VARCHAR()
PACKAGE_NAME
; VARCHAR()
OVERLOAD VARCHAR()
ARGUMENT_NAME VARCHAR()
POSITION 非空值 NUMBER
DATA_LEVEL 非空值 NUMBER
DATA_TYPE VARCHAR()
DEFAULT_VALUE LONG
IN_OUT VARCHAR()
很快你就會看到嵌入在這些行中的層次每個對象(OWNEROBJECT_NAME)可能超載(overload)(如果不超載或是一個負數則OVERLOAD是空值)overloading中的每一個自變量都有一個位置而在那個位置內你可以有自變量信息的多個層次換句話說
OBJECT_NAME
OVERLOAD
ARGUMENT_NAME
POSITION
LEVEL
由於篇幅所限我不可能提供Codecheck程序包中太多實用程序的實現無論如何我很高興與您分享我為了輕松地快速分析ALL_ARGUMENTS的內容而把它的數據傳送到我的集合中而寫的代碼
我在Codecheck程序包上進行第一次傳送中我定義了一個可以簡單地映射數據字典視圖的集合類型和集合如下所示
CREATE OR REPLACE PACKAGE BODY Codecheck
IS
TYPE args_t IS TABLE OF
all_arguments%ROWTYPE
INDEX BY BINARY_INTEGER;
arguments args_t;
正如清單所示我通過使用定義的集合只使用了很少量的代碼它就可以為特定的程序獲得數據並把它插入到我的集合中
定義嵌套的集合
但是我在寫完清單中的代碼後馬上意識到我正在以過時的方式思考問題我的計劃是先填滿我的集合接著寫一些復雜的代碼來掃描自變量集合然後查找一些事情諸如
一個程序包中特有程序的代號和名字我可能一共有個程序但由於超載因而只有個不同的程序名
頂級自變量項(其DATA_LEVEL = )
這就是在集合中用於標識一個程序結束和另一個程序開始的那些自變量
解決在ALL_ARGUMENTS視圖中數據的組織問題並寫出所需要的代碼是我的任務
假如我定義多個嵌套的集合來存儲這個數據將會怎樣呢?也許通過這個方法集合的該組織可以使我更加容易地回答一些我的問題在經過思考和測試了一些可選方案之後我得到了如清單所示的集合類型的層次結構
圖在ALL_ARGUMENTS集合映射中的四層嵌套
下面是對清單內容的描述像這樣的情況最好是使用自底向上或者是從層次的最外層到最內部的集合的研究方法在第行中我聲明了類型為programs_t的集合這個單獨的集合將包含ALL_ARGUMENTS視圖中的全部信息正像我的第一次嘗試中那樣但是該信息的組織卻完全不同在第行和第行中我聲明了集合類型programs_t這個類型的集合中的每一行包含有關一個給定程序名的全部overloadings的自變量的所有相關信息請注意索引是對象的名字在第行和第行中我聲明了集合類型overloadings_t這個類型的集合中的每一行包含有關一個程序的一個單一overloading的自變量的所有相關信息現在我再次使用一個整數索引因為在這種情況下關鍵字是ALL_ARGUMENTS視圖中的OVERLOAD字段的值在第行和第行中我聲明了集合類型arguments_t這個類型的集合中的每一行包含一個特定overloading的一個單一參數或自變量的所有相關信息我還是使用一個整數索引因為在該情況下關鍵字是ALL_ARGUMENTS的POSITION字段的值(即參數列表中的位置)在第行和第行中我聲明了集合類型breakouts_t這個類型的集合中的每一行包含一個自變量的一個單一元素的所有相關信息這可能是一行也可能是多行數據如果例如這個問題中的自變量是一個有個域的記錄那麼這個集合至少有行我借助一個整數索引因為在這個例子中關鍵字是ALL_ARGUMENTS視圖中的LEVEL字段的值(在參數列表中表示實際的自變量)
是否令人有些困惑?首先不要只盯著ALL_ARGUMENTS視圖中數據的復雜性我只想給你一個在我的代碼中需要操作的變量的感受接下來我們看一下圖中的圖表注意在ALL_ARGUMENTS視圖中嵌套的層次是怎樣簡單地以這些不同的層次來表達的
有了g_programs集合之後讓我們再次查看如清單所示的Codecheck包中的load_arguments過程
清單中的load_arguments過程和清單中的版本有什麼不同?整體地看非常小唯一不同的語句是在清單的第行到第行下面是在清單中的較早的簡單賦值語句
arguments (
NVL (argumentsLAST ) + )
:= rec;
在清單中它變成了
g_programs
(recobject_name)
(recoverload)
(recposition)
(recdata_level) := rec;
這當然很復雜但它會為我處理那可怕的復雜性例如通過使用這個單一的賦值語句我實際上把全部個集合中的所有行放到該層次結構中當我完成這一工作後只花了很少的代碼就滿足了我的檢索數據的需要例如獲得TOTAL_SALES函數的第個overloading的RETURN子句的數據類型
g_programs (TOTAL_SALES) locate
() second overloading
() RETURN clause has position
() Toplevel argument
data_type Value in the
data_type field
在這種情況下使用這個語法比編寫和調試掃描一個平面(flat)(Oraclei數據庫之前)集合所需要的邏輯來得到這樣的信息代碼要容易得多
當然我並不期望你能立即完全領會這些復雜的集合結構的潛在能力我只希望這個段落的一些例子可以起到拋磚引玉的作用
這麼多的選擇!
只要適當地使用集合將幫助我們編寫出更高效和更易懂的代碼將多層次的編程和用字符串建立索引可以幫助我們減少復雜性和減少建模和操作來自復雜數據庫設計的信息所需的編碼量
From:http://tw.wingwit.com/Article/program/Oracle/201311/18063.html