Microsoft SQL Server 查詢處理器的內部機制與結構
2024-08-31 00:53:19
供稿:網友
摘要:本文介紹了在客戶機上處理 Microsoft sql server(WINDOWS平臺上強大的數據庫平臺) 查詢的方式,各種客戶機與 sql server(WINDOWS平臺上強大的數據庫平臺) 的交互方式,以及 sql server(WINDOWS平臺上強大的數據庫平臺) 在處理客戶機程序的請求時需要完成的工作。
簡介
Microsoft(R) sql server(WINDOWS平臺上強大的數據庫平臺)(TM) 內部機制和結構是一個非常大的主題,因此本文僅限于程序開發人員感興趣的問題,集中研究其他源中沒有徹底討論的問題。在討論 sql server(WINDOWS平臺上強大的數據庫平臺) 的結構時,我們主要觀察客戶機的處理過程,研究不同的客戶機程序與 sql server(WINDOWS平臺上強大的數據庫平臺) 的交互方式,以及 sql server(WINDOWS平臺上強大的數據庫平臺) 如何處理客戶機的請求。還有一些討論 sql server(WINDOWS平臺上強大的數據庫平臺) 其他方面的信息源,特別是 Microsoft PRess 出版的 Inside sql server(WINDOWS平臺上強大的數據庫平臺) 7.0,作者是 Ron Soukup 和 Kalen Delaney,這本書非常詳細地討論了 sql server(WINDOWS平臺上強大的數據庫平臺) 存儲引擎的內部機制和處理方法,不過對查詢處理器的討論不夠深入。本文正填補了這個空白。
我們期望本文有助于讀者編寫出更好的應用程序。通過本文,讀者會在提高程序性能方面得到新的啟發,產生新的理解。
sql server(WINDOWS平臺上強大的數據庫平臺) 是一種客戶機/服務器系統
多年來,sql server(WINDOWS平臺上強大的數據庫平臺) 一直被認為是一種客戶機/服務器系統。事實上,Sybase DataServer(以此為基礎開發了原始的 sql server(WINDOWS平臺上強大的數據庫平臺))正是第一個作為客戶機/服務器系統開發的商用關系數據庫系統。那這又說明了什么呢?這不只意味著 sql server(WINDOWS平臺上強大的數據庫平臺) 是一個雙層系統。從傳統上看,雙層系統意味著客戶機應用程序運行在一臺機器上,向另一臺計算機上的服務器發送請求。而對于 sql server(WINDOWS平臺上強大的數據庫平臺),客戶機/服務器意味著 sql server(WINDOWS平臺上強大的數據庫平臺) 的組成部分,即客戶機 API 部分,駐留在處理結構中的遠端,與服務器組件本身是分開的。
在典型的雙層模型中,客戶機程序部分駐留在臺式機上,具有大量客戶機應用程序邏輯和業務邏輯,并且會直接向數據庫系統發出請求。然后,客戶機得到服務器響應這些請求所返回的數據。
三層系統也采用了同樣的模型。多年以來,sql server(WINDOWS平臺上強大的數據庫平臺) 一直用在事務處理監視系統中,例如 BEA 的 Tuxedo 以及 Compaq 的 ACMSxp,這些系統早在二、三十年前就采用了典型的三層模型。三層模型在今天基于 Web 的應用系統中占據了支配地位,這類系統以 Microsoft 的 MTS 以及新的 COM+ 1.0 為代表。從 sql server(WINDOWS平臺上強大的數據庫平臺) 的角度看,三層解決方案中的客戶機程序是放在中間層的。中間層直接與數據庫交互。實際的桌面,或瘦客戶機(Thin Client),使用其他機制并通常直接與中間層交互,而不是直接與數據庫系統交互。圖 1 描述了這種結構。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖一)" width="354" height="298" />
圖 1. 三層系統模型
從結構的角度看,sql server(WINDOWS平臺上強大的數據庫平臺) 關系服務器組件本身并不真正關心客戶機程序運行的位置。事實上,就 sql server(WINDOWS平臺上強大的數據庫平臺) 而言,即使在運行 sql server(WINDOWS平臺上強大的數據庫平臺) 的同一臺機器上運行應用程序,仍然還是客戶機/服務器模型。
服務器運行一個單獨的多線程進程,為來自客戶機的請求提供服務,不管客戶機的位置在哪里??蛻魴C程序代碼本身是單獨的運行在客戶機應用程序內部的 DLL,與 sql server(WINDOWS平臺上強大的數據庫平臺) 的實際接口是在客戶機和服務器之間對話的“表格數據流”(Tabular Data Stream, TDS) 協議。
一個常見的問題是“什么是 sql server(WINDOWS平臺上強大的數據庫平臺) 的本機接口呢?”很長時間以來,很多開發人員一直都不愿意使用 ODBC 這樣的接口,因為他們認為由 Sybase 開發的客戶機 API,也就是 DB-Library,是 sql server(WINDOWS平臺上強大的數據庫平臺) 的本機接口。實際上,sql server(WINDOWS平臺上強大的數據庫平臺) 關系服務器本身并沒有本機 API,它的接口就是在客戶機和服務器之間的通信流協議 TDS。TDS 把客戶機發送給服務器的 SQL 語句封裝起來,也把服務器返回給客戶機的處理結果封裝起來。任何直接處理 TDS 的 API 都是 sql server(WINDOWS平臺上強大的數據庫平臺) 的本機接口。
讓我們來看一下客戶機的組件,如圖 2 所示??蛻魴C結構中的某些部分就不在這里討論了,因為它們不屬于 sql server(WINDOWS平臺上強大的數據庫平臺) 的范疇。但如果您在編寫應用程序的話,就必須了解這些部分。大家知道得最多的應該是各種對象模型,如果您正在編寫 asp 或 Microsoft Visual Basic(R) 應用程序,就需要通過 ADO 與數據庫系統交互,而不是直接調用底層的 API,例如 ODBC 或 OLE-DB。ADO 映射到 OLE-DB,而 RDO 映射到 ODBC。因此,作為這種最常用的編程模型的對象模型,并不是 sql server(WINDOWS平臺上強大的數據庫平臺) 客戶機結構中的嚴格意義上的組件。此外,還有另外一些組件可以插接到 sql server(WINDOWS平臺上強大的數據庫平臺) 基礎結構上面的這一層。OLE-DB 的“會話池服務提供程序 (session Pooling Service Provider)”就是這種組件的一個例子。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖二)" width="333" height="330" />
圖 2. 客戶機結構
客戶機接口
sql server(WINDOWS平臺上強大的數據庫平臺) 有兩個接口可以認為是 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 的本機接口,即 OLE-DB 和 ODBC。DB-Library 接口也是本機的,它與 TDS 通信,但是 DB-Library 使用的是 TDS 較老的版本,需要在服務器上進行一些轉換?,F有的 DB-Library 應用程序仍然可以繼續與 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 協同使用,但是很多新的功能和性能提高等好處只能通過 ODBC 和 OLE DB 才能利用。更新 DB-Library 使其支持 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 的新能力,將會導致與現有應用程序的很多不兼容性,因此需要修改應用程序。ODBC 在五年之前就替代了 DB-Library,是新的 sql server(WINDOWS平臺上強大的數據庫平臺) 應用程序更理想的 API,因此引入不兼容的 DB-Library 新版本并不明智。
從圖 2 可以看到,所有這些客戶機 API 都有三個部分。最上面的部分實現 API 的細節,例如行集和游標應該是什么樣等等。TDS 格式化程序負責處理實際請求,例如 SQL 語句,并將其封裝成 TDS 消息包,發送給 sql server(WINDOWS平臺上強大的數據庫平臺),獲得返回的結果,然后再把結果反饋到接口實現。
還有一些供所有提供程序使用的公共庫代碼。例如,BCP 設備就是 ODBC 和 OLE-DB 都可以調用的庫。DTC 也是這樣。第三個例子是 ODBC 規范的 SQL 語法,即帶有參數標記的 CALL 語法,這些對于所有提供程序都是通用的。
除了我們在前面已經提到的局限性,即 DB-Library 仍然只能使用 sql server(WINDOWS平臺上強大的數據庫平臺) 6.5 版,TDS 協議對于所有 API 都是相同的。ODBC 和 OLE-DB 在與 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 通信時使用 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 版,但也能夠與 6.5 或 6.0 服務器通信。另一個是 Net-Library,這是一個抽象層,客戶機和服務器都在此層上同網絡抽象接口通信,不必為 ipX 還是 TCP/IP 困擾。在這里我們將不討論 Net-Library 的工作細節;只要知道它們的工作基本上是將來自的網絡通信底層的細節隱藏起來不讓軟件的其他部分看到就可以了。
從客戶機的角度看服務器
前面已經提到過,客戶機與 sql server(WINDOWS平臺上強大的數據庫平臺) 通信的主要方法就是通過使用 TDS 消息。TDS 是一種簡單協議。當 sql server(WINDOWS平臺上強大的數據庫平臺) 接收到一條消息時,可以認為是發生了一個事件。首先,客戶機在一個連接上發送登錄消息(或事件),并得到返回的成功或失敗的響應。當您希望發送 SQL 語句時,客戶機可以把 SQL 語言消息打包發送給 sql server(WINDOWS平臺上強大的數據庫平臺)。另外,當您希望調用存儲過程、系統過程或虛擬系統存儲過程(我們后面還要詳細討論)時,客戶機可以發送 RPC 消息,這種消息相當于 sql server(WINDOWS平臺上強大的數據庫平臺) 上的一個 RPC 事件。對于上面的后兩種情況,服務器會以數據令牌流的形式送回結果。Microsoft 沒有把實際的 TDS 消息寫入文檔中,因為這被認為是 sql server(WINDOWS平臺上強大的數據庫平臺) 組件之間的私用契約。
目錄存儲過程是另一類關鍵的客戶機/服務器的交互部分。這些存儲過程首先在 ODBC 的 sql server(WINDOWS平臺上強大的數據庫平臺) 6.0 中出現, 包括諸如 sp_tables 和 sp_columns 等存儲過程。ODBC 和 OLE-DB API 定義了描述有關數據庫對象的元數據的標準方法,這些標準需要適用于所有類型的 RDBMS 服務器,而不必調整為 sql server(WINDOWS平臺上強大的數據庫平臺) 自己的系統表。不是客戶機向服務器發送對系統表的多個查詢,并在客戶機端建立標準的元數據視圖,而是創建一組存儲在服務器上的系統存儲過程,并對 API 返回適當格式的信息。這種方法使得通過一次通信就可以完成很多重要的元數據請求。
為 ODBC 編寫的過程已經寫入文檔,通常適合需要從系統表中獲取信息但其他機制沒有提供這種方法的情況。這使得 Transact-SQL 過程和 DB-Library 應用程序可以訪問元數據,而不需要編寫對 sql server(WINDOWS平臺上強大的數據庫平臺) 系統表的復雜查詢,并且使應用程序不受今后 Microsoft 修改系統表的影響。
OLE DB 定義了一組架構行集,它們類似于 ODBC 的元數據,但又和它不同。它創建了一組新的目錄存儲過程,以更有效地為這些架構行集植入數據。但是,這組新的存儲過程沒有寫入文檔,因為這些存儲過程重復了早先提供的功能。通過現有的若干種方法都可以得到元數據,因此 sql server(WINDOWS平臺上強大的數據庫平臺) 開發組決定不顯露這些并沒有為編程模型增加新內容的對象。
客戶機與服務器的交互還有第三個方面。它最初出現在 sql server(WINDOWS平臺上強大的數據庫平臺) 6.0 中,但是沒有得到普遍使用。這就是虛擬系統存儲過程的概念;在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中起很重要的作用。當第一次為 sql server(WINDOWS平臺上強大的數據庫平臺) 6.0 開發服務器端游標時,開發人員就需要選擇采取什么方法管理客戶機/服務器的交互。游標并不特別適合現有的 TDS 消息,因為這些消息允許逐行返回數據,不需要客戶機指定額外的 SQL 語句。開發人員本來可以向 TDS 協議添加更多的消息,但是需要修改太多的其他組件。sql server(WINDOWS平臺上強大的數據庫平臺) 6.0 中的 TDS 版本還需要向 Sybase 版本靠攏,以便確保兩者的可互操作性,于是開發人員選擇了另外的處理機制。他們開發了外表看起來像是系統存儲過程的新功能(服務器端游標),實際上是指向 sql server(WINDOWS平臺上強大的數據庫平臺) 代碼的入口存儲過程。它們被客戶機應用程序使用標準的 RPC TDS 消息來調用。它們被稱為虛擬系統存儲過程,因為在客戶機上,它們像其他存儲過程那樣被調用,和其他存儲過程不同的是,它們并不是由簡單的 SQL 語句組成。大多數虛擬系統存儲過程都是私用的,并且沒有寫入文檔。對于游標過程,所有 API 都顯露其自有的一組游標 API 模型和它們自己的游標操作函數,因此沒有必要為存儲過程本身編寫文檔。即使是在 Transact-SQL 語言中,也有顯露游標的語法,可以使用 DECLARE、OPEN、FETCH 等,所以完全沒有必要為虛擬系統存儲過程編寫文檔,例如 sp_cursor,因為這些過程只在內部使用。
ODBC 和 OLE DB 中出現了帶參數的查詢和準備/執行模型的概念。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 以前的版本中,這些概念是由客戶機 API 中的代碼實現的。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,Microsoft 為這些概念添加了對“關系服務器”的支持,并且通過新的虛擬系統存儲過程顯露了這種支持。本文后面還要介紹這些功能,以及服務器如何支持這些功能。通過 sp_executesql 過程對帶參數的查詢的支持,被認為對直接 Transact-SQL 和 DB-Library 的使用特別有用,所以將其寫入了文檔。準備/執行的過程,被 ODBC 驅動程序和 OLE DB 提供程序專用。
服務器結構
sql server(WINDOWS平臺上強大的數據庫平臺),或更確切一點地說,是“sql server(WINDOWS平臺上強大的數據庫平臺) 關系服務器”,經常被說成是由兩個主要部分組成,即關系引擎和存儲引擎。正如前面提到過的那樣,已經有很多文獻介紹存儲引擎的細節了,所以本文主要介紹關系引擎的功能。圖 3 給出了 sql server(WINDOWS平臺上強大的數據庫平臺) 關系引擎部分的主要組件。所給出的組件可以分為三組子系統。左邊的組件編譯查詢,包括查詢優化器。查詢優化器是所有關系數據庫引擎中的最神秘的部分之一,從性能的角度看也是最重要的部分。查詢優化器負責提取 SQL 語句中的非過程請求部分,并將其翻譯成一組磁盤 I/O、過濾以及其他能夠高效地滿足該請求的過程邏輯。圖中右側是執行基礎結構。這里實際上只有很少的功能。當編譯組件的工作完成之后,所產生的結果只需用很少幾個服務即可直接執行。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖三)" width="386" height="322" />
圖 3. 服務器結構
圖的中間是稱為 SQL Manager 的部分。SQL Manager 控制著 sql server(WINDOWS平臺上強大的數據庫平臺) 內部的所有數據的流動。SQL Manager 控制著 RPC 消息,在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,絕大多數來自客戶機的功能調用都是通過 RPC 消息進行的。上一節中介紹的虛擬系統存儲過程邏輯上也是 SQL Manager 的一部分。通常,作為 TDS SQL 語言消息的 SQL 語句直接在編譯一端執行,與早期版本相比,sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 較少使用這種方法,但還算是比較常見的。執行結果由稱為 ODS 的執行引擎中的組件格式化為 TDS 執行結果消息。
絕大多數輸出都來自圖中的執行端,而且輸出結果也真正出自表達式服務?!氨磉_式服務”庫是進行數據轉換、謂詞評估(過濾)以及算法計算的組件。它還利用了 ODS 層,把輸出結果格式化為 TDS 消息。
還有幾個組件,我們只是在這里簡單地提一下,這些組件在關系引擎內部提供附加服務。這些組件中的一個是目錄服務組件,用于數據定義語句,例如 CREATE TABLE、CREATE VIEW 等。目錄服務組件主要放在關系引擎中,但是實際上大約有三分之一的目錄服務組件是在存儲引擎中運行的,所以可以看作是共享組件。
關系引擎中的另一種組件是“用戶模式調度程序 (UMS)”,這是 sql server(WINDOWS平臺上強大的數據庫平臺) 自己內部的纖程和線程規劃器。把任務分配給纖程或線程是一種非常復雜的內部機制,取決于對服務器如何配置,以及在 SMP 系統中允許 sql server(WINDOWS平臺上強大的數據庫平臺) 進行處理器之間的適當的負載平衡。UMS 還可以避免 sql server(WINDOWS平臺上強大的數據庫平臺) 由于同時運行太多的線程而導致性能過低。最后,還有大家熟悉的系統過程,邏輯上它們也屬于關系引擎的一部分。這些組件肯定不是服務器代碼,因為可以很容易地使用 sp_helptext 檢查定義這些過程的 Transact-SQL 代碼。但是,系統過程被作為服務器的一部分來對待,因為系統過程的用途是顯露重要的服務器能力,像系統表一樣,以供應用程序在更高的層次上和更適當的層次上使用。如果應用程序開發人員將較高層次的系統過程 — 更容易使用 — 作為一種接口,即使隨著版本的更新,原始層次上的系統表發生變化時,應用程序仍然可以繼續使用。
下面我們將討論當客戶機應用程序與 sql server(WINDOWS平臺上強大的數據庫平臺) 交互時客戶機的動作。以下是一個 ODBC 調用的例子:
SQLExecDirect(hstmt, "SELECT * FROM parts where partid = 7", SQL_NTS)
?。∣LE-DB 也有一個與這個調用幾乎直接等價的調用,此處不再討論這個調用,因為這個調用實際上與 ODBC 調用相同。)該 ODBC 調用取一個 SQL 語句,然后將其發送給 sql server(WINDOWS平臺上強大的數據庫平臺) 來執行。
在這個具體的查詢語句中,我們從零件表中提取具有特定零件標識號的所有行。這是特定 SQL 的一個典型例子。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 以前的版本中,特定的 SQL 與存儲過程的一個顯著差別是,查詢優化器所生成的計劃從不緩存。查詢語句要被讀入、編譯、執行,然后再拋棄計劃。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,正如稍后還要討論的,實際上提供了可以緩存特定查詢語句的計劃的機制。
在這條語句被送往 sql server(WINDOWS平臺上強大的數據庫平臺) 之前,還必須要問幾個問題。所有客戶機程序都要提供某種游標說明,所以客戶機程序在內部必須詢問的一個問題是,程序員請求的是什么樣的結果集或什么樣的游標。最快的類型是在文檔中被稱為默認結果集的游標。這種游標由于歷史上的原因被稱為消防站游標,有時甚至根本不把它作為游標看待。當 SQL 請求被送到服務器之后,服務器開始把結果返回給客戶機,這個返回結果的過程持續進行,直到把全部數據集發送完畢為止。這就像一個將數據抽給客戶機的大型消防站。
一旦客戶機程序確定了這是默認結果集,則下一步就是確定是否有參數標記。使用這個 ODBC SQLExecDirect(以及 OLE-DB 中等價的調用)調用的選項之一是,不是在 WHERE 從句中給出像 7 這樣的具體值,而是可以用一個問號來傳遞參數標記,如下所示:
SQLExecDirect(hstmt, "SELECT * FROM parts where partid = ?", SQL_NTS)
請注意,您必須分別提供實際的參數值。
客戶機需要知道 SQL 語句中是否有參數標記,或者它是否為真正特定的非參數化 SQL。這將影響到客戶機將用這個語句在內部做什么,并確定將什么作為消息真正發送給 sql server(WINDOWS平臺上強大的數據庫平臺)。在沒有問號時,很明顯,客戶機只想將這個請求作為 SQL Language TDS 消息發送,然后客戶機將位于流水的末端,并將結果返回。然后客戶機能將結果返回給基于應用程序參數的應用程序。客戶機的內部處理選擇會模糊一點,這取決于您通過 ODBC 或 OLE DB API 請求什么。例如,應用程序不直接請求默認結果集。相反,在 ODBC 中,如果請求一個只讀的、只向前的且每次只給出一行的游標,那么對于客戶機內部運行來說,這就是在定義流水游標(默認結果集)。
下面我們將討論當客戶機應用程序與 sql server(WINDOWS平臺上強大的數據庫平臺) 交互時客戶機的動作。以下是一個 ODBC 調用的例子:
SQLExecDirect(hstmt, "SELECT * FROM parts where partid = 7", SQL_NTS)
(OLE-DB 也有一個與這個調用幾乎直接等價的調用,此處不再討論這個調用,因為這個調用實際上與 ODBC 調用相同。)該 ODBC 調用取一個 SQL 語句,然后將其發送給 sql server(WINDOWS平臺上強大的數據庫平臺) 來執行。
在這個具體的查詢語句中,我們從零件表中提取具有特定零件標識號的所有行。這是特定 SQL 的一個典型例子。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 以前的版本中,特定的 SQL 與存儲過程的一個顯著差別是,查詢優化器所生成的計劃從不緩存。查詢語句要被讀入、編譯、執行,然后再拋棄計劃。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,正如稍后還要討論的,實際上提供了可以緩存特定查詢語句的計劃的機制。
在這條語句被送往 sql server(WINDOWS平臺上強大的數據庫平臺) 之前,還必須要問幾個問題。所有客戶機程序都要提供某種游標說明,所以客戶機程序在內部必須詢問的一個問題是,程序員請求的是什么樣的結果集或什么樣的游標。最快的類型是在文檔中被稱為默認結果集的游標。這種游標由于歷史上的原因被稱為消防站游標,有時甚至根本不把它作為游標看待。當 SQL 請求被送到服務器之后,服務器開始把結果返回給客戶機,這個返回結果的過程持續進行,直到把全部數據集發送完畢為止。這就像一個將數據抽給客戶機的大型消防站。
一旦客戶機程序確定了這是默認結果集,則下一步就是確定是否有參數標記。使用這個 ODBC SQLExecDirect(以及 OLE-DB 中等價的調用)調用的選項之一是,不是在 WHERE 從句中給出像 7 這樣的具體值,而是可以用一個問號來傳遞參數標記,如下所示:
SQLExecDirect(hstmt, "SELECT * FROM parts where partid = ?", SQL_NTS)
請注意,您必須分別提供實際的參數值。
客戶機需要知道 SQL 語句中是否有參數標記,或者它是否為真正特定的非參數化 SQL。這將影響到客戶機將用這個語句在內部做什么,并確定將什么作為消息真正發送給 sql server(WINDOWS平臺上強大的數據庫平臺)。在沒有問號時,很明顯,客戶機只想將這個請求作為 SQL Language TDS 消息發送,然后客戶機將位于流水的末端,并將結果返回。然后客戶機能將結果返回給基于應用程序參數的應用程序??蛻魴C的內部處理選擇會模糊一點,這取決于您通過 ODBC 或 OLE DB API 請求什么。例如,應用程序不直接請求默認結果集。相反,在 ODBC 中,如果請求一個只讀的、只向前的且每次只給出一行的游標,那么對于客戶機內部運行來說,這就是在定義流水游標(默認結果集)。
SQLExecDirect 模型流程如圖 4 所示。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖四)" width="444" height="312" />
·OWASP要素增強Web應用程序安全(2)
·“惡搞”盜用你無線網絡的鄰居
·如何入侵jsp(SUN企業級應用的首選)網站
·黑客知識:如何隱藏 php文件后門的技
·jsp(SUN企業級應用的首選)+javabean學習(二)
·Java入門視頻教程-第61講
·OWASP 10要素增強Web應用程序安全(1
·什么是asp木馬
·如何在Windows Server 2003中安裝Java
·Web 2.0網站安全堪憂 Javascript恐引
圖 4. 客戶機/服務器交互
準備/執行模型
除了執行直接模型(在 ODBC 中用 SQLExecDirect 調用)外,在 ODBC 和 OLE-DB 中,還有一種執行模型,稱為準備/執行模型。定義要執行的 SQL,是作為一個獨立于實際執行 SQL 的步驟來完成的。以下是 ODBC 中的一個例子:
SQLPrepare(hstmt, "SELECT * FROM parts where partid = ?", SQL_NTS)
SQLExecute(hstmt)
在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 版本之前,準備/執行從來都不是 sql server(WINDOWS平臺上強大的數據庫平臺) 的本機模式。如今在 7.0 版本中,有兩個提供本機接口的虛擬系統存儲過程。對于準備調用,我們要再次研究游標的類型,然后調用 sp_prepare 或 sp_cursorprepare。這些過程會完成 SQL 或存儲過程的編譯,但不會實際執行計劃。相反,虛擬系統存儲過程只是返回該計劃的句柄?,F在,應用程序可以反復地執行 SQL 了,例如傳入不同的參數值,而不需要重新編譯。
在 sql server(WINDOWS平臺上強大的數據庫平臺) 6.5 中,由于沒有本機接口,需要模擬準備和執行兩個階段。可以通過下面的兩種方法做到這一點。在第一種方法中,不會真正出現準備階段。只有執行部分返回元數據(有一些選項可以做到這一點),所以 sql server(WINDOWS平臺上強大的數據庫平臺) 可以把結果的格式描述返回給應用程序。在第二種方法中,sql server(WINDOWS平臺上強大的數據庫平臺) 實際上創建一個特定存儲過程,這個過程是單個用戶私用的,不能共享計劃。這第二種方法可能會占滿 tempdb 數據庫的空間,因此大多數應用程序開發人員都通過 ODBC 配置對話框中的復選框,關閉此選項,以使用第二種方法。
在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,準備/執行方法是 sql server(WINDOWS平臺上強大的數據庫平臺) 的本機功能。準備好 SQL 語句之后,才會執行它。至于默認的結果集,應用程序只需要調用 sp_execute,提供準備操作生成的句柄,語句就會被執行。對于游標,與其他游標處理過程看起來很相似,事實上,它也具有相同的特性,包括如果游標是快速只前向型,還可以使用 autofetch 和 toclose。
準備/執行操作的流程如圖 5 所示。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖五)" width="446" height="312" />
圖 5. 準備/執行模型
調用存儲過程
存儲過程一般是從 ODBC 和 OLE-DB,通過發送 SQL 語句給使用 ODBC 標準 CALL 語法調用過程的 sql server(WINDOWS平臺上強大的數據庫平臺) 來調用。其應類似于以下語句:
·OWASP要素增強Web應用程序安全(2)
·“惡搞”盜用你無線網絡的鄰居
·如何入侵jsp(SUN企業級應用的首選)網站
·黑客知識:如何隱藏 PHP文件后門的技
·jsp(SUN企業級應用的首選)+javabean學習(二)
·Java入門視頻教程-第61講
·OWASP 10要素增強Web應用程序安全(1
·什么是asp木馬
·如何在Windows Server 2003中安裝Java
·Web 2.0網站安全堪憂 JavaScript恐引
SQLExecDirect(hstm, "{call addorder(?)}", SQL_NTS)
對于默認結果集,這是一個簡單的流,因為這正是 RPC 消息原本要處理的對象??蛻魴C向服務器發送 RPC 消息,并獲取來自存儲過程的處理結果。如果是游標,則情況稍微復雜一些,客戶機需要調用 Sp_cursoropen,就像其他游標一樣。Sp_cursoropen 含有內部邏輯,檢測該存儲過程是否只包含一條 SELECT 語句。如果是,則對該 SELECT 語句打開一個游標。如果該存儲過程中不是一條 SELECT 語句,則客戶機會得到一個指示,說明“我們為您打開結果集,但是我們將以流水的方式返回數據流,您可以把這個數據流提供給用戶”。
存儲過程執行流程如圖 6 所示。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖六)" width="446" height="317" />
圖 6. 調用存儲過程
SQL Manager
前面已經提到過的 SQL Manager 驅動很多服務器處理過程,它實際上是服務器的心臟。SQL Manager 處理所有調用存儲過程的請求,管理過程緩存,擁有虛擬系統存儲過程,在稍后要介紹的特定查詢的自動參數化過程中也要涉及。如果您有與本文類似的描述 SQL 6.5 或更老版本的文章,則不會讀到有關 SQL 管理器的討論,然而,您會讀到一些完成 SQL 管理器工作的一些不同的組件。但是在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,這些組件被統一為 SQL 管理器,通過系統驅動查詢語句的處理。
在一般情況下,當要求 SQL 管理器為您做某些工作時,通過 RPC 消息調用 SQL 管理器。但是,當通過 SQL 消息發送 SQL 語句并進入引擎編譯時,也會用到 SQL 管理器。當存儲過程或批處理程序包含 EXEC 語句時,也會調用 SQL 管理器,因為 EXEC 實際上就是調用 SQL 管理器。如果該 SQL 語句傳送了下面就要討論的一個自動參數化模板,則需要調用 SQL 管理器對該查詢進行參數化處理。當特定查詢語句需要裝入緩存時,也要調用 SQL 管理器。
編譯與執行
現在討論在 sql server(WINDOWS平臺上強大的數據庫平臺) 中編譯和執行的一般流程。需要注意的是編譯和執行在 sql server(WINDOWS平臺上強大的數據庫平臺) 內部是兩個不同的階段。sql server(WINDOWS平臺上強大的數據庫平臺) 編譯查詢語句和執行該語句之間的間隔時間可能非常短,只有幾個毫秒,也可能是幾秒鐘、幾分鐘、幾小時甚至幾天。在編譯過程中(這個過程包括優化),我們必須區分什么樣的知識可以用于編譯。并不是所有對編譯有用的知識對執行也起作用。您必須把編譯和執行理解為兩個不同的活動,即使您發送并立即執行的是特定 SQL 查詢語句。
當 sql server(WINDOWS平臺上強大的數據庫平臺) 可以開始處理查詢語句時,SQL Manager 要在緩存內進行查找,如果沒有找到該語句,則必須編譯該語句。編譯處理要完成以下幾件工作。首先,要進行分析和正常化。分析就是剖析該 SQL 語句,將其轉換成更適合計算機處理的數據結構。分析還要驗證語法的正確性。
分析不進行表名和列名合法性等檢查,這些工作在正?;A段完成。正?;饕墙馕?SQL 語句中引用的對象,轉換成實際的數據庫對象,檢查請求的語義是否有意義。例如,試圖執行一個表,這在語義上就是錯誤的。
下一步是編譯 Transact-SQL 代碼。Transact-SQL 和 SQL 本身都讓人有點兒困惑,Microsoft 的開發人員也像別人一樣經常互換兩個詞。但是,這兩者之間還是有重要差別的。SQL 包括所有 DML 語句:INSERT、UPDATE、DELETE 和 SELECT。sql server(WINDOWS平臺上強大的數據庫平臺) 還有一種包括這些 DML 語句的語言,稱為 Transact-SQL,也就是 TSQL。TSQL 提供過程結構:IF 語句、WHILE 語句、局部變量聲明等。服務器內部對 SQL 和 TSQL 的處理方法完全不同。TSQL 的過程邏輯要由知道如何進行過程化處理的引擎來編譯。
SQL 語句本身由典型的查詢優化器來處理。優化器必須把基于集合的 SQL 語句的非過程化的請求,翻譯成可以被高效執行并返回所需結果的過程。除非特別說明,我們在以下討論編譯時,均指 TSQL 的編譯和 SQL 語句的優化。
上面已經提到,編譯和執行是兩個不同的查詢處理階段,因此,優化器完成的工作之一是基于相當穩定的狀態進行優化。您可以注意到,sql server(WINDOWS平臺上強大的數據庫平臺) 可能會根據語句所滿足的條件重新編譯,所以狀態并不是永遠穩定的,但也不是處于不停的變化之中。如果優化器使用的信息變化太劇烈、太經常 — 并發處理器的數量和鎖的數量不穩定 — 則必須不斷重新進行編譯,而一般來說編譯是比較耗時的。例如,SQL 語句的運行時間為百分之一秒,而編譯可能需要占用半秒。最理想的情況是,sql server(WINDOWS平臺上強大的數據庫平臺) 能夠只編譯語句一次,而執行成千上萬次,不必每次執行該語句時都重新編譯它。
編譯階段的最終產品是查詢計劃,放在過程緩存中。便宜的特定 SQL 計劃并不放在緩存中,不過這只是個小問題。我們不希望緩存被不太可能重復執行的內容占滿,一般來說,特定 SQL 語句的計劃是最不可能反復使用的了。如果語句編譯已經很便宜(小于百分之一秒),則沒有必要再把計劃放入緩存,用不太可能重新使用的計劃占用緩存。
把計劃放入緩存之后,SQL Manager 按照執行要求邏輯進行檢查,確定是否有更改的內容,是否需要重新編譯。即使編譯到執行之間時間間隔只有幾毫秒,也可能有人會執行一條數據定義語句 (DDL),為關鍵的表加了索引。這種可能性不大,但是確實存在,因此 sql server(WINDOWS平臺上強大的數據庫平臺) 必須考慮這一點。有幾種情況 sql server(WINDOWS平臺上強大的數據庫平臺) 必須重新編譯存儲規劃。元數據的修改,例如增加或刪除索引,是重新編譯的最主要的原因。服務器必須確信所使用的計劃反映了索引的當前狀態。
重新編譯的另一種原因是統計情況發生變化。sql server(WINDOWS平臺上強大的數據庫平臺) 還維護不少數據使用頻率的統計信息。如果數據使用頻率分布情況變化很大,則可能需要另一個查詢計劃以便更有效地執行。sql server(WINDOWS平臺上強大的數據庫平臺) 跟蹤表數據插入和刪除的統計數據,如果數據修改的數量超過根據表的容量變化的某一閾值,則需要根據新的分布數據重新編譯計劃。
圖 7 給出了編譯和執行過程的流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖七)" width="477" height="374" />
·OWASP要素增強Web應用程序安全(2)
·“惡搞”盜用你無線網絡的鄰居
·如何入侵jsp(SUN企業級應用的首選)網站
·黑客知識:如何隱藏 PHP文件后門的技
·jsp(SUN企業級應用的首選)+javabean學習(二)
·Java入門視頻教程-第61講
·OWASP 10要素增強Web應用程序安全(1
·什么是asp木馬
·如何在Windows Server 2003中安裝Java
·Web 2.0網站安全堪憂 JavaScript恐引
圖 7. 編譯與執行
注意,實際參數的改變并不會導致重新編譯,環境的改變,例如可用內存的增加或所需數據的增加,也不會導致重新編譯。
執行是比較簡單的,如果需要執行的查詢很簡單,如“插入一行”,或從帶有唯一索引的表中查詢數據,則執行處理會非常簡單。但是,很多查詢都要求大量的內存以提高運行效率,或至少從所增加的內存得到好處。在 sql server(WINDOWS平臺上強大的數據庫平臺) 6.5 中,每個查詢能夠使用的內存限制在 0.5MB 或 1MB 以下。有一個控制查詢內存使用的參數,稱為排序頁。顧名思義,它主要是限制可能占用大量內存的排序操作。不管要處理的排序有多大,在 sql server(WINDOWS平臺上強大的數據庫平臺) 6.5 中,內存的使用不能超過 1MB。即使您使用的機器上配置了 2GB 內存,需要對數百萬行數據排序,也不能突破限制。顯然,復雜的查詢不能高效執行,因此 sql server(WINDOWS平臺上強大的數據庫平臺) 開發人員增加了 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 的能力,使得單個查詢可以使用大量的內存。
另一個問題隨之而來。一旦您開始允許查詢使用大量內存,就必須確定如何把內存分配給可能需要內存的很多查詢。sql server(WINDOWS平臺上強大的數據庫平臺) 按照以下方法解決這個問題。當查詢計劃優化之后,優化器要確定有關給該查詢使用的內存的兩部分信息。第一,該查詢有效執行所需要的最小內存,該參數與查詢計劃一起存放。優化器還要確定該查詢可以獲益的最大的內存量。例如,如果要排序的整個表只有 100MB,分配 2GB 內存就沒什么幫助了。您需要的只是 100MB,這個最大有用內存參數隨查詢計劃一起存放。
當 sql server(WINDOWS平臺上強大的數據庫平臺) 開始執行計劃時,該計劃被傳遞給一個所謂內存授權調度程序的例程中。這個授權調度程序要完成幾項有趣的工作。首先,如果授權調度程序要處理的查詢在計劃中沒有排序或雜湊操作,則 sql server(WINDOWS平臺上強大的數據庫平臺) 知道該查詢不會需要很多內存。在這種情況下,不需要內存授權調度程序進行判斷。該計劃會立即執行,因此典型的事務處理請求會完全旁路這種判斷機制。內存授權調度程序還設有多個隊列處理不同容量的請求。內存調度程序優先處理較小的請求。例如,如果有一個查詢要求“提取前 10 個”,并且只需要對 20 行排序,則雖然需要經過內存授權調度程序,但是要釋放該查詢并且很快調度。服務器需要并行或并發執行許多這種查詢。
如果有很大的查詢,您希望一次只運行幾個查詢,讓它們占有所需的更多內存。sql server(WINDOWS平臺上強大的數據庫平臺) 確定一個由 4 X(系統中的 CPU 個數)得到的數。如果可能,sql server(WINDOWS平臺上強大的數據庫平臺) 會同時運行那個數量的查詢,為它們分配高效運行所需要的最小內存。如果還剩有內存,則一部分查詢會允許占用最大高效內存。
sql server(WINDOWS平臺上強大的數據庫平臺) 試圖既為查詢分配盡可能多的內存,又讓盡可能多的查詢同時運行在系統中。
能夠使用最大高效內存對某些操作很重要,例如夜間運行的批處理過程。您可能會生成很大的報表,或重新建立索引。這些查詢可能使用大量內存,這種機制可以動態調整對內存的需求。因此,如果如果在隊列中等待處理的查詢不多,則內存授權調度程序會經常分配給查詢最大需要的內存。如果白天的機器負載很重,則就不能同時運行太多的查詢。這些查詢會得到有效運行所需最小的內存,讓內存為更多的查詢共享。
一旦調度程序說現在可以為請求分配內存,則計劃即被“打開”,開始實際運行。計劃會一直運行直到完成。如果查詢使用了默認結果集模型,則計劃會一直運行到檢索到所有結果為止,然后把結果返回給客戶機。如果使用的是游標模型,則處理過程略有不同。每個客戶機請求只提取一塊數據,并不是所有數據。當每個結果塊返回給客戶機之后,sql server(WINDOWS平臺上強大的數據庫平臺) 必須等待客戶機的下一個請求。在等待時,整個計劃就會睡眠。這意味著要釋放一些鎖,要釋放一些資源,并保留一些斷點信息。這些斷點信息使得 sql server(WINDOWS平臺上強大的數據庫平臺) 能夠返回到睡眠之前的狀態,使得執行可以繼續。
過程緩存
我們在前面已經多次提到 sql server(WINDOWS平臺上強大的數據庫平臺) 的過程緩存。需要注意的是,sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 的過程緩存與以前的版本有很大不同。在早期的版本中,有兩個有效配置值用于控制過程緩存的容量:一個是定義 sql server(WINDOWS平臺上強大的數據庫平臺) 總可用內存的固定容量,另一個是供存儲查詢計劃使用的內存百分比(扣除滿足固定需要的內存)。在老版本中,特定 SQL 語句從不存入緩存,只有存儲過程計劃才存入其中。在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中,內存的總容量是動態的,用于查詢計劃的空間也是經常變化的。
在處理查詢時,sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 首先會問的是:這個查詢既是特定的又是易于編譯的嗎?如果是,sql server(WINDOWS平臺上強大的數據庫平臺) 就根本不會將其寫入緩存中。將來重新編譯這些計劃比把復雜的計劃或數據頁推出內存更合算。如果查詢不是特定的或不易于編譯,則 sql server(WINDOWS平臺上強大的數據庫平臺) 會從緩存區中分配一些緩存內存存儲該計劃,因為該緩存區是 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 用來滿足 99% 內存需求的唯一來源。在少數特殊情況下,sql server(WINDOWS平臺上強大的數據庫平臺) 會直接從操作系統中分配大塊內存,但是這種情況極為罕見。sql server(WINDOWS平臺上強大的數據庫平臺) 的管理是集中式的。
寫入緩存的除計劃外,還有反映通過編譯該查詢實際創建該計劃的成本的成本因子。如果這是一個特定計劃,則 sql server(WINDOWS平臺上強大的數據庫平臺) 將它的成本設置為 0,表示可以立即將它撤出過程緩存。對于特定 SQL,雖然有可能被重復使用,但可能性很小,如果系統內存緊張,總是愿意首先撤出特定語句的計劃。
這樣,特定查詢的計劃是最適合清出緩存的對象。如果查詢不是特定的,則 sql server(WINDOWS平臺上強大的數據庫平臺) 會把該成本設置為實際編譯查詢的成本。這些成本是以磁盤 I/O 為單位的。如果從磁盤中讀出一個數據頁,則有一個 I/O 成本。在編譯計劃時,信息從磁盤中讀出,包括統計數據和查詢本身的文本。SQL 要進行附加的處理,而且這處理工作被正?;癁?I/O 成本?,F在,建立過程的成本可用執行 I/O 的成本表示。該成本非常恰當反映了,與打算用磁盤緩存的數據量相比,管理實際打算分配給存儲過程和任何種類查詢計劃的緩存量的能力。該成本被計算出來之后,該計劃就會被寫入緩存。
圖 8 顯示計算計劃成本并將其寫入緩存的流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖八)" width="214" height="315" />
圖 8. 將計劃寫入緩存
如果另一個查詢可以重新使用該計劃,則 sql server(WINDOWS平臺上強大的數據庫平臺) 要再次判定計劃的類型。如果是一個特定計劃,sql server(WINDOWS平臺上強大的數據庫平臺) 會把成本加 1。這樣,如果特定計劃確實要被重新使用,則它會在緩存中稍作停留,停留時間越長,成本就增加越多。如果該計劃經常被重新使用,則成本會一次增加一個單位地不斷增長,直到增長到其實際編譯成本。該成本和設置的成本一樣高。不過該計劃經常被重復使用;如果同一用戶或其他用戶不斷重新提交完全一樣的 SQL 文本,該計劃就會留在緩存中。
如果查詢不是特定的,也就是說是一個存儲過程、帶參數的查詢或自動參數化的查詢,則每次該計劃被重新使用時,成本都會設置回原來的值。只要計劃被重新使用,就會留在緩存中。即使有一段時間沒有被使用,取決于最初的編譯代價的高低,計劃停留在緩存中的時間也有長短。
圖 9 顯示從緩存中檢索計劃并調整成本的流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖九)" width="217" height="218" />
圖 9. 從緩存中檢索計劃
遲緩寫入器(Lazywriter) 是使計劃過時的機制,負責在必要的時候從緩存中刪除計劃。遲緩寫入器實際上是存儲引擎的一部分,但是因為遲緩寫入器對于查詢處理機制是如此重要,我們還是在這里進行討論。遲緩寫入器管理查詢計劃內存使用的機制與管理頁面的機制一樣,因為 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 計劃存儲在普通緩沖存儲器中。遲緩寫入器要檢查系統中所有的緩沖器標題。如果系統的內存不緊張,檢查的次數就很少;如果開始緊張,則遲緩寫入器就會經常運行。當遲緩寫入器運行時,它要檢查緩沖區標題,并檢查緩存區中該頁面的當前成本。如果成本為 0,則意味著自從上次遲緩寫入器檢查以來,該頁面沒有被使用過,于是遲緩寫入器就會釋放該頁面,以便為系統增加可用內存,用于頁面 I/O 或其他計劃。此外,如果該緩沖區包含過程計劃,則遲緩寫入器會調用 SQL 管理器,以完成一些清理工作。最后,該緩沖區會被放到可用內存表中供重新使用。
如果與緩沖區關聯的成本大于 0,則遲緩寫入器會把成本減 1,并繼續檢查其他緩沖區。這成本實際上反映的,某計劃若是沒被使用,它在緩存中還能存在多少個遲緩寫入器的檢查周期。這種算法,除了如果對象是存儲過程則調用 SQL Manager 這一步之外,對緩存中的計劃和緩存的數據或索引沒有什么區別。遲緩寫入器并不知道對象是否存儲過程,這種算法很好地平衡了磁盤 I/O 對緩存的使用和存儲過程計劃對緩存的使用。
您會發現,如果計劃的編譯成本很高,那么即使很長一段時間都沒有被重新使用,也仍然會停留在緩存中,這是因為其初始成本太高了。經常被重新使用的計劃也會長期停留在緩存中,這是因為每當它被重新使用時其成本已被重新設置,遲緩寫入器不會看到它的成本降為 0。
圖 10 顯示遲緩寫入器處理緩存的流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖十)" width="338" height="198" />
圖 10. 遲緩寫入器處理緩存的流程
處理客戶機的 SQL
下面再看看提交 SQL 語句之后的處理過程。首先,我們將研究客戶機向 sql server(WINDOWS平臺上強大的數據庫平臺) 發送 RPC 事件。因為 sql server(WINDOWS平臺上強大的數據庫平臺) 收到了 RPC 事件,所以它會知道該事件是某種參數化的 SQL;它是準備/執行模型,或者是 EXECUTESQL。sql server(WINDOWS平臺上強大的數據庫平臺) 需要構建一個緩存鍵,以標識這個具體的 sql server(WINDOWS平臺上強大的數據庫平臺) 文本。如果 sql server(WINDOWS平臺上強大的數據庫平臺) 處理的是實際的存儲過程,則不需要建立它自己的鍵;直接使用該過程的名稱即可。對于通過 RPC 調用發來的簡單 SQL 文本,則通過雜湊該 SQL 文本來建立緩存鍵。此外,該鍵還要反映一定的狀態信息,如某些 ANSI 設置。使所有 ANSI 設置為 ON 的連接和另一個使所有 ANSI 設置為 OFF 的連接,即使它們來自相同的查詢,也不能使用相同的計劃。處理過程是不同的。例如,如果一個連接把 concat_null_yields_null 設置為 ON,另一個把 concat_null_yields_null 設置為 OFF 的連接,即使它們執行的是完全相同的 SQL 文本,但所產生的結果則完全不同。這樣,sql server(WINDOWS平臺上強大的數據庫平臺) 可能需要在緩存中保存計劃的多個版本,每個版本對應于一個不同的 ANSI 設置組合。啟用的選項設置是鍵的一部分,而鍵字是使用這種緩存處理機制檢查對象的核心,因此 sql server(WINDOWS平臺上強大的數據庫平臺) 建立這種鍵并用來檢查緩存。如果在緩存中沒有發現該計劃,則 sql server(WINDOWS平臺上強大的數據庫平臺) 會按照前面介紹的方式編譯該計劃,并把該計劃與鍵一起存入緩存中。
sql server(WINDOWS平臺上強大的數據庫平臺) 還需要確定該命令是否是準備操作,這意味著該計劃應該只編譯但不執行。如果是準備操作,則 sql server(WINDOWS平臺上強大的數據庫平臺) 會給客戶機返回一個句柄,供客戶機在以后檢索并執行該計劃。如果不是一個準備操作,則 sql server(WINDOWS平臺上強大的數據庫平臺) 提取并執行該計劃,就像最初從緩存中找到該計劃一樣。
準備/執行模型為緩存管理增加了復雜因素。預備給出了今后能夠執行該計劃的句柄。應用程序可以在幾小時或幾天之內保持該句柄是激活的,以定期執行計劃。即使需要在緩存中為更多的活動計劃或數據頁面騰出空間,也不能使該句柄無效。
sql server(WINDOWS平臺上強大的數據庫平臺) 實際所做的就是將計劃放入緩存,此外還從預備操作中將 SQL 保存到更加緊湊的空間。如果空間緊張,則可按前述的方式釋放計劃所占用的空間,但仍有 SQL 的副本準備著。如果客戶機要執行預備的 SQL,但在緩存中沒有找到計劃,則 sql server(WINDOWS平臺上強大的數據庫平臺) 能夠檢索到該文本并編譯它,再將它放回緩存中。這樣,緩存中的 16 千字節 (KB) 或更多的頁面用來保存可重用的計劃,而長期占用的空間或許是存儲在其他處的 SQL 代碼的 100 或 200 字節。
處理來自客戶機的語句時的另一種情況是,查詢是作為 SQL 語言事件出現的。除了一點以外,此流程并無太大的差異。在這種情況下,sql server(WINDOWS平臺上強大的數據庫平臺) 試圖使用稱為自動參數化的技術。SQL 文本與自動參數化模板相匹配。自動參數化是個棘手的問題,因此,過去一直能夠利用共享的 SQL 的其他數據庫管理產品, 一般并沒有提供這一選項。隨之而來的問題是,如果 sql server(WINDOWS平臺上強大的數據庫平臺) 自動地參數化每個查詢,那么對于隨后提交的某些特定值而言,這些查詢中的某些(或絕大多數)將獲得非常糟糕的計劃。在程序員將參數標記放在代碼之中的場合下,其假定是程序員知道所期望的值的范圍,并愿意接受 sql server(WINDOWS平臺上強大的數據庫平臺) 提供的計劃。但當程序員實際補充一個特定的值,并且 sql server(WINDOWS平臺上強大的數據庫平臺) 決定將該值當做一個可變的參數來對待時,所產生的任何適合于某個值的計劃可能不適合于后續的值。利用存儲過程,通過在過程中放入 WITH RECOMPILE 選項,程序員可以強制產生新的計劃。利用自動參數化,程序員無法指出必須為每一個新值開發新的計劃。
當 sql server(WINDOWS平臺上強大的數據庫平臺) 處理自動參數化時,它是非常保守的。被安全地自動參數化的查詢有一個模板,并且只有匹配模板的查詢才能應用自動參數化。例如,假設有這樣一個查詢,其中包含帶有等于操作符、但沒有連接的 WHERE 子句,WHERE 子句中的列帶有唯一的索引。sql server(WINDOWS平臺上強大的數據庫平臺) 知道絕對不會返回一行以上,而且計劃將總是使用那個唯一的索引。sql server(WINDOWS平臺上強大的數據庫平臺) 絕對不會考慮掃描,實際值絕對不會以任何方式改變計劃。對于自動參數化而言,這種查詢是安全的。
如果查詢匹配自動參數化模板,則 sql server(WINDOWS平臺上強大的數據庫平臺) 自動用參數標記(例如 @p1、@p2)代替文字,并且這就是我們發送到服務器的內容,正如它是 sp_executesql 調用一樣。如果 sql server(WINDOWS平臺上強大的數據庫平臺) 認為該查詢對自動參數化并不安全,則客戶機將向 sql server(WINDOWS平臺上強大的數據庫平臺) 發送文字的 SQL 文本,以此作為特定的 SQL。
準備/執行模型為緩存管理增加了復雜因素。預備給出了今后能夠執行該計劃的句柄。應用程序可以在幾小時或幾天之內保持該句柄是激活的,以定期執行計劃。即使需要在緩存中為更多的活動計劃或數據頁面騰出空間,也不能使該句柄無效。
sql server(WINDOWS平臺上強大的數據庫平臺) 實際所做的就是將計劃放入緩存,此外還從預備操作中將 SQL 保存到更加緊湊的空間。如果空間緊張,則可按前述的方式釋放計劃所占用的空間,但仍有 SQL 的副本準備著。如果客戶機要執行預備的 SQL,但在緩存中沒有找到計劃,則 sql server(WINDOWS平臺上強大的數據庫平臺) 能夠檢索到該文本并編譯它,再將它放回緩存中。這樣,緩存中的 16 千字節 (KB) 或更多的頁面用來保存可重用的計劃,而長期占用的空間或許是存儲在其他處的 SQL 代碼的 100 或 200 字節。
處理來自客戶機的語句時的另一種情況是,查詢是作為 SQL 語言事件出現的。除了一點以外,此流程并無太大的差異。在這種情況下,sql server(WINDOWS平臺上強大的數據庫平臺) 試圖使用稱為自動參數化的技術。SQL 文本與自動參數化模板相匹配。自動參數化是個棘手的問題,因此,過去一直能夠利用共享的 SQL 的其他數據庫管理產品, 一般并沒有提供這一選項。隨之而來的問題是,如果 sql server(WINDOWS平臺上強大的數據庫平臺) 自動地參數化每個查詢,那么對于隨后提交的某些特定值而言,這些查詢中的某些(或絕大多數)將獲得非常糟糕的計劃。在程序員將參數標記放在代碼之中的場合下,其假定是程序員知道所期望的值的范圍,并愿意接受 sql server(WINDOWS平臺上強大的數據庫平臺) 提供的計劃。但當程序員實際補充一個特定的值,并且 sql server(WINDOWS平臺上強大的數據庫平臺) 決定將該值當做一個可變的參數來對待時,所產生的任何適合于某個值的計劃可能不適合于后續的值。利用存儲過程,通過在過程中放入 WITH RECOMPILE 選項,程序員可以強制產生新的計劃。利用自動參數化,程序員無法指出必須為每一個新值開發新的計劃。
當 sql server(WINDOWS平臺上強大的數據庫平臺) 處理自動參數化時,它是非常保守的。被安全地自動參數化的查詢有一個模板,并且只有匹配模板的查詢才能應用自動參數化。例如,假設有這樣一個查詢,其中包含帶有等于操作符、但沒有連接的 WHERE 子句,WHERE 子句中的列帶有唯一的索引。sql server(WINDOWS平臺上強大的數據庫平臺) 知道絕對不會返回一行以上,而且計劃將總是使用那個唯一的索引。sql server(WINDOWS平臺上強大的數據庫平臺) 絕對不會考慮掃描,實際值絕對不會以任何方式改變計劃。對于自動參數化而言,這種查詢是安全的。
如果查詢匹配自動參數化模板,則 sql server(WINDOWS平臺上強大的數據庫平臺) 自動用參數標記(例如 @p1、@p2)代替文字,并且這就是我們發送到服務器的內容,正如它是 sp_executesql 調用一樣。如果 sql server(WINDOWS平臺上強大的數據庫平臺) 認為該查詢對自動參數化并不安全,則客戶機將向 sql server(WINDOWS平臺上強大的數據庫平臺) 發送文字的 SQL 文本,以此作為特定的 SQL。
圖 11 顯示客戶機向 sql server(WINDOWS平臺上強大的數據庫平臺) 發送請求時的處理流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖十一)" width="531" height="358" />
·OWASP要素增強Web應用程序安全(2)
·“惡搞”盜用你無線網絡的鄰居
·如何入侵jsp(SUN企業級應用的首選)網站
·黑客知識:如何隱藏 PHP文件后門的技
·jsp(SUN企業級應用的首選)+javabean學習(二)
·Java入門視頻教程-第61講
·OWASP 10要素增強Web應用程序安全(1
·什么是asp木馬
·如何在Windows Server 2003中安裝Java
·Web 2.0網站安全堪憂 JavaScript恐引
圖 11. 處理客戶機的 SQL
編譯
現在讓我們更詳細地討論一下編譯和優化。在編譯過程中,sql server(WINDOWS平臺上強大的數據庫平臺) 分析語句,并創建所謂的次序樹,即語句的內部表述。這是 sql server(WINDOWS平臺上強大的數據庫平臺) 6.5 實際保留在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 中的幾個數據結構之一。該次序樹是正?;?。正常化程序的主要功能是執行綁定。綁定包括檢驗表和列的存在,以及裝載有關表和列的元數據。有關必需的(隱含的)轉換信息也附加在次序樹上,例如,如果查詢試圖向數字值添加整數 10,則 sql server(WINDOWS平臺上強大的數據庫平臺) 將向該樹插入隱含的轉換。正?;€用視圖的定義代替對該視圖的引用。最后,正常化執行一些基于語法的優化。如果該語句是傳統的 SQL 語句,則 sql server(WINDOWS平臺上強大的數據庫平臺) 從關于該查詢的次序樹中提取信息,并創建稱為查詢圖表的特殊結構,設置查詢圖表是為了使優化器工作非常有效。然后優化該查詢圖表,一個計劃就產生了。
圖 12 顯示編譯過程流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖十二)" width="306" height="328" />
圖 12. 編譯
優化
sql server(WINDOWS平臺上強大的數據庫平臺) 優化器其實是由獨立的段組成的。第一段是一個非基于成本的優化器,稱為瑣細計劃優化?,嵓氂媱潈灮耐暾拍钍?,當 SQL 語句確實只有一個可變計劃時,基于成本的優化太昂貴了。最好的例子是,帶 VALUES 子句的 INSERT 語句組成的查詢。它只可能有一個計劃。另一個例子是,所有的列都在唯一的封面索引(且沒有其他列的索引)中的 SELECT 語句。這兩例中,sql server(WINDOWS平臺上強大的數據庫平臺) 只要簡單地生成一個計劃,用不著在多個計劃選一個更好的方案。瑣細計劃優化器可找到真正顯而易見的計劃,而且通常非常便宜。所以,最簡單的查詢在處理的前期就趨于被清除,優化器不花很多時間來搜索一個好計劃。這是好事,因為隨著 sql server(WINDOWS平臺上強大的數據庫平臺) 將雜湊連接、合并連接和索引相交增加到其處理技術列表上,sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 版上的潛在計劃數呈天文數字增長。
如果瑣細計劃優化器不能找到一個計劃,sql server(WINDOWS平臺上強大的數據庫平臺) 便進入優化的下一部分,稱為簡化。簡化是查詢本身的語法變換,尋找可交換的特性和可重新排列的運算。sql server(WINDOWS平臺上強大的數據庫平臺) 可進行常數合并,以及無需考慮成本或分析索引是什么但能得出更有效查詢的其他運算。sql server(WINDOWS平臺上強大的數據庫平臺) 然后上載關于索引和列的統計信息,并輸入優化的最后的主要部分,即基于成本的優化器。
基于成本的優化有三個階段。第一個基于成本的階段,稱為交易處理階段,查找簡單請求的計劃,即典型的交易處理系統。這些請求一般比由瑣細計劃優化器處理的那些請求要復雜些,并要求比較眾多計劃查找出成本最低的計劃。
當交易處理階段完成時,sql server(WINDOWS平臺上強大的數據庫平臺) 便將找到的成本最低的計劃與內部閾值進行比較。閾值用于決定是否要求進一步的優化。如果計劃成本比閾值低,那么,進行附加優化比只執行已找到的計劃成本要高。所以,sql server(WINDOWS平臺上強大的數據庫平臺) 不做進一步優化,并使用交易處理階段找到的計劃。
如果交易處理階段找到的計劃,仍比該階段的閾值貴,sql server(WINDOWS平臺上強大的數據庫平臺) 便進入第二個階段。這個階段有時稱為 QuickPlan 階段。QuickPlan 階段擴大搜索范圍來尋找一個好計劃,包括選擇好的、適度復雜的查詢。QuickPlan 檢查可能的計劃范圍,完成之后,將最佳計劃的成本與第二個閾值進行比較。因為在交易處理階段,如果發現了一個成本比閾值低的計劃,優化便終止,并使用那個計劃。一般來說,sql server(WINDOWS平臺上強大的數據庫平臺) 6.5 版中已有的查詢的計劃,在 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 版中也應當是最佳的,這個計劃將要么被瑣細計劃優化器找到,要么被基于成本的優化的頭兩個階段中的一個發現。這些規則被有意地組織起來以達到這個目的。這個計劃將很可能由使用單一的索引和使用嵌套循環聯合組成。
優化的最后階段,稱為完全優化,旨在對復雜和非常復雜的查詢產生一個好計劃。對復雜的查詢來說,QuickPlan 產生的計劃,經常被認為比繼續搜索一個更好的計劃要昂貴得多,而完全優化將被執行。在完全優化中,實際上有兩個適用的獨立選擇。如果 QuickPlan 階段產生的最佳成本比“并行成本閾值”的配置值要高,并且如果服務器是一個多處理器機器,那么優化器的最后階段將涉及查找一個能在多個處理器上并行運行的計劃。如果 QuickPlan 階段的最佳計劃的成本比配置的“并行成本閾值”低,那么,優化器將只考慮串行計劃。完全優化階段能執行各種可能性,而且很耗時,因為在這最后階段必須找到一個計劃。優化器仍可能沒有檢查每個可得到的計劃,因為它將任何潛在的計劃成本與優化中得出此結果的成本進行比較,并且它估算繼續試用不同優化的可能成本。在某些情況下,優化器可能認為,使用現有的計劃比繼續查找更優方案還要便宜,而且支付繼續優化的附加編譯成本將不具備高的成本效率比。在這最后階段處理的各種查詢的計劃一般只使用一次,所以,幾乎沒有這樣的機會:為編譯和優化所付出的額外代價,會在后續執行的計劃重用中一次結清。那些后續執行很可能不會發生。
找到一個計劃后,該計劃便變為優化器的輸出,然后 sql server(WINDOWS平臺上強大的數據庫平臺) 在執行該計劃之前,遍歷前面已討論過的全部緩存機制。您應該意識到,如果完全優化階段產生了該查詢的并行計劃,并不一定意味著該計劃將在多個處理器上執行。如果機器很忙,而且不支持在多個 CPU 上運行單一的查詢,該計劃則使用單一的處理器。
圖 13 顯示了優化器的處理流程。
(WINDOWS平臺上強大的數據庫平臺) 查詢處理器的內部機制與結構(圖十三)" width="499" height="371" />
·OWASP要素增強Web應用程序安全(2)
·“惡搞”盜用你無線網絡的鄰居
·如何入侵jsp(SUN企業級應用的首選)網站
·黑客知識:如何隱藏 PHP文件后門的技
·jsp(SUN企業級應用的首選)+javabean學習(二)
·Java入門視頻教程-第61講
·OWASP 10要素增強Web應用程序安全(1
·什么是asp木馬
·如何在Windows Server 2003中安裝Java
·Web 2.0網站安全堪憂 JavaScript恐引
圖 13. 優化
執行
查詢處理的最后一步是執行。除了這一小段外,我們不會再討論執行的詳細過程。執行引擎采用優化器生成的計劃,并執行之。處理實際執行以外,執行引擎還為要運行的處理器調度線程,并提供線程間的通信。
摘要
如前所述,sql server(WINDOWS平臺上強大的數據庫平臺) 的內部機制與結構是一個非常大的主題,遠遠超過了我們能在本文中提供的內容。我們重在直接介紹 sql server(WINDOWS平臺上強大的數據庫平臺) 與客戶機的交互方式,以及 sql server(WINDOWS平臺上強大的數據庫平臺) 關系引擎如何處理來自客戶機的請求。我們希望,在了解 sql server(WINDOWS平臺上強大的數據庫平臺) 如何處理查詢,以及如何和何時編譯或重新編譯它們之后,您就能利用 sql server(WINDOWS平臺上強大的數據庫平臺) 7.0 的功能和技巧編寫出更好的應用程序。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/ynigeng/archive/2009/12/30/5105611.aspx