資料庫設計:儲存過程

woodytu發表於2016-07-05

對於設計和建立資料庫完全是個新手?沒關係,Joe Celko, 世界上讀者數量最多的SQL作者之一,會告訴你這些基礎。和往常一樣,即使是最專業的資料庫老手,也會給他們帶來驚喜。Joe是DMBS雜誌是多年來最受 讀者喜愛的作者。他在美國、英國,北歐,南美及非洲傳授SQL知識。他在ANSI / ISO SQL標準委員會工作了10年,為SQL-89和SQL-92標準做出了傑出貢獻。


 Joe Celko會談下資料庫設計裡儲存過程和它的位置。他所寫的是令人深思的東西,即使是有經驗的資料庫開發人員。

在第一篇,我們因它們是什麼並區分它們命名資料元。在第二篇,我們用SQL裡給我們的資料型別和簡單的行或列約束來模型化資料元。在第三篇,我們把這些行放入表成為實體,關係和輔助資料。在第四篇,我們有了基礎表,把它們連線在一起,增加從索引,並建立了檢視。

這應該會給你萬事俱備,卻是錯誤的感覺。在一個非常簡 單的資料庫裡,這是對的。但在一個真正的資料庫有更多的架構來考慮。在這些架構外的其他東西事:遊標(cursors)、觸發器(triggers)和存 儲過程(stored procedures)。有更多像整理、翻譯,特權和諸如此類的東西。我將只處理這3個東西——遊 標(cursors)、觸發器(triggers)和儲存過程(stored procedures)——我只用通常的方式命名。儘管ANS/ISO標準裡,T-SQL和其他產品可以獲得更高的佔有慾。理由很簡單:這些東西建立在早 期SQL產品使用的現有檔案系統上。這些程式結構是用來彌補在早期產品裡缺少申明式程式碼。這些供應商有鎖在今天“程式碼博物館”不能地址他們客戶群的使用者。

儲存過程名稱(Procedure Headers)

SQL允許儲存過程程式碼模組在架構裡儲存。同時在標準SQL裡有SQL/PSM語言,你會使用像T-SQL的專門語言。這些語言通常是Algol家族的成員;那就是說他它們有IF-THEN-ELSE,WHILE迴圈和有BEGIN-END作用域的程式碼塊。

這些專用語言的大多數從未想用做程式開發。對於T- SQL的首要規則(The rules of thumb)是不寫超過50行的的過程,且不使用PRINT。但事實上,你可以避免所有的程式導向,每個表像檔案和程式碼一樣對待,好像資料庫是個過程化的 檔案系統。如果你喜歡疼痛,大可敲個釘子到你身體,所以不用糾結。

儲存過程的目的更像個檢視。它們授予所有使用者在所有時間會用同樣的方式做同樣的工作。檢視封裝了一個查詢並給它一個名稱,因此建立了一個虛擬表。儲存過程用同樣的方式封裝了UPDATE,INSERT,DELETE和SELECT,但增加了引數。

在儲存過程名稱裡一個引數(parameter )就是個“持有人(place holder)”,引數值(argument )是傳給儲存過程的實際值。T-SQL引數過去只限制於簡單的標量值。現在,它們可以是表值和XML字元。讓我們從簡單的標量引數開始。

編譯器讀取引數值,並檢查資料型別,範圍和確保它是有效的其他事項。編譯器會做比你想象還多的事。看下這個T-SQL:

同事,浮點表示法有點意思。如果你以DECIMAL或FLOAT轉化指數計數法,肯定沒問題:

但現在把字串的指數計數法,嘗試轉化它為DECIMAL或FLOAT,你肯定會出現問題:

如果轉化字元,你要用這樣的指數程式碼:

現在嘗試傳這些測試值作為引數,看看它們的結果:

返回值(2010-01-01, 6230000000.00000)和預期的一樣。

你不能傳表示式作為引數值,但你可以傳本地變數,它是表示式值預先設定的。這就是說這個會報錯:

但這個會成功執行:

你會看到新的SQL程式設計會嘗試傳遞XML或CSV(逗 號分割值(Comma Separated Values))列表字元作為引數值。它們增加了解析器的負擔(XML解析器或任何寫出來用來分割CSV字元的任何程式碼)並讓它們的資料完整性受到危險。 SQL Server可以處理超過2000的引數值,對於現實中的情況已經足夠能應付。

在引數列表裡另一個未使用的功能是預設值。這個語法非常簡單。引數宣告後一個“=”和一個合適的定值。

如果引數值沒有提供,就會使用預設值。

除非你特別分配引數值到引數,它們是從左到右的順序分配。

最後,引數可以用作輸出。這就是說它需要在呼叫的模組裡有個本地變數,這樣的話,返回值才有地方可去。這是展示這個語法的例子:

軟體工程基礎

關於儲存過程標題就講這些;那儲存過程的具體內容呢?嗯,我們現在暫時不講。我們先講下原則讓,然後再看看特定的工具。我們需要一個高度來看如何編寫程式碼——軟體工程(Software Engineering)。

軟體工程的基礎不在SQL裡修改。但現實完全不一樣。我們大多數(從學LISP,APL,FP,Haskell或其它外來語言學起,對這些程式設計師例外)學過從Algol-60進化而來的結構化程式語言。適用於過程化語言的原則同樣適用於SQL儲存過程。

在近1970年,我們發現我們可以在程式裡寫出更好(更快,正確,更易維護的)的程式碼,在程式碼裡有原生程式碼塊規則和程式碼模組,都是一個入口一個出口。我們避免GO TO語句,並使用簡單的一系列控制結構。這是結構化程式設計的進步。

內聚度(Cohesion)

內聚度是一個模組做且只做一件事會很好:那是邏輯上的 內聚性。模組應該高內聚。模組的命名格式應該是“<動作><物件>”,這裡“<物件>”是資料模型裡特定的邏輯單 元,“<動作>”是單一明確的行動。有很多內聚型別。我們從最差到最好對它們排名。

  1. 偶然內聚(coincidental cohesion)是 模組部分任意分組。一個偶然模組無關行為的火車殘骸。它是“Lady GaGa,魷魚和汽車”模組,它們的描述會是複合且複雜的句子。這個在SQL裡的最佳例子是OTLT(查詢表(One True Lookup Table))設計缺陷。這是它裡面有對整個實體架構的查詢表。
  2. 邏輯性內聚(logical cohesion)是模組部分按它們邏輯上做同樣的事進行分組,即使本質上它們是不同的。在SQL裡最常見的例子是在任何表上進行更新、插入或刪除的通用模組——在“Lady GaGa,魷魚和汽車”上。用動態SQL,XML和CLR進行實現。
  3. 時間性內聚(temporal cohesion)是模組部分按它們處理時分組。例如,對於整個系統,進行所有初始化工作的模組。
  4. 過程性內聚(procedural cohesion)是模組部分是因為它們總是緊跟特定操作順序。例如,當一個使用者登入到資料庫,我們會檢查用特權可並記錄登入。不把這些事放在各個模組裡,在上層的控制下,我們寫整合的一塊來完成這一切。
  5. 通訊性內聚(communicational cohension)是模組部分因它們在同樣的資料庫元上操作進行分組。例如在一個儲存過程裡,UPDATE的一系列語句影響同樣列,基於先前模組做的事。
  6. 順序性內聚(sequential cohesion)是模組部分因為從一個部分的輸出是另一個部分的輸入,像流水線一樣。在SQL裡,可以看下臨時表的使用,在磁帶檔案系統裡用來替換。
  7. 功能性內聚(functional cohesion)是模組只做一件定義明確的工作,像一個數學函式。這才是我們模組裡想要的,它是功能性程式語言的基礎。沒有副作用或外部資料。

如果在你的軟體工程課程裡錯過這些,你可以網上找下它們的具體定義

耦合度(Coupling)

耦合度是模組之間的相互獨立性。如果你的模組需要特定的順序執行,它們是強耦合度。如果它們之間可以獨立執行,可以像樂高一樣堆積,它們是鬆散或弱耦合的。耦合有好幾類,從低到高排序是:

  1. 內容耦合(Content coupling)是一個模組的修改依賴於另一個模組的內部操作。控制模組的跳入與調出。在SQL裡,使用者自定義函式(UDF)的使用和CLR是最好的例子。直到執行的時候你才知道會發生什麼。
  2. 公共耦合(Common coupling)是兩個模組共用同樣的全域性資料。這聽起來像SQL裡的表,但它指的是在公共資料上有2個做同樣工作的方法。做同樣的工作很快變成幾乎一樣的工作。
  3. 外部耦合(External coupling)是兩個模組共享一個外部強加的資料格式,通訊協議,或裝置介面。理想的,我們不需要擔心外部環境。這是在資料庫裡,分層架構不做任何形式或包裝。
  4. 控制耦合(Control coupling)是一個模組通過傳遞標記控制執行。直到它的主模組告訴它,你不知道這個模組會做什麼。這也是在SQL程式設計裡,使用BIT標記不好的一個原因。
  5. 標記耦合(Stamp coupling)是模組共享複合資料結構,且只使用它的一部分。在SQL裡可以使用檢視實現。
  6. 資料耦合(Data coupling)是模組共享簡單資料元。想下傳遞引數;這是隻共享的資料元。
  7. 非直接耦合(Message Coupling)是最寬鬆的耦合型別。模組不相互依賴,它們使用公共介面來交換少引數的資訊。這更多是物件導向的方法,但你會在觸發器、異常處理和其他SQL特性裡看到它。

這個在我的《SQL 程式設計風格》書裡關於儲存過程編寫的章節裡會有簡單的介紹。同時,你也可以閱讀下DeMarco, Yourdon, Constantine, Myers或其它軟體工程先驅。這已經不是簡單的SQL程式設計了。在你寫任何語言的程式碼前,這些都是你應該知道的。

好的SQL儲存過程

一般而言,好的儲存過程是高內聚,低耦合,它不使用控制結構的缺陷,除非是必須的。對於過程化開發人員,這個是意外。理由是儘可能多的把“程式設計的元素”放入單純的SQL,這樣優化器可以更好的處理程式碼。

如何實現?下篇會告訴你。

英文連結:

http://www.sqlservercentral.com/articles/Stairway+Series/Procedures+in+Database+design/70891/

下一篇:資料庫設計:儲存過程主體

相關文章