Sql-Server

使用 # 的 SQL Server 臨時表 - 它是否只能通過包含具有相同登錄名的多個連接的查詢訪問?

  • July 18, 2017

假設我們有 2 個完全不同的查詢,它們引用同名的臨時表:

查詢一 ….操作:#tempTableName

查詢兩個 ….操作:#tempTableName

我對此進行了研究,發現“#temp 是一個本地臨時表,因此對其他連接不可見”,但是我不確定連接在 SQL 查詢上下文中的深入含義。SQL 是否認為每個執行的單獨查詢都有一個單獨的“連接”,還是以某種方式共享連接?

具體來說,我的問題是“如果我的場景中的兩個查詢被同一個登錄名訪問,會發生什麼”,例如多個 .NET 應用程序正在使用相同的 .NET 連接字元串並同時訪問數據庫。如果我的場景中的兩個查詢同時執行,他們是否會潛在地訪問同一個臨時表?鎖呢?在對桌子進行操作期間,我是否需要採取任何措施來防止不必要的訪問?

我看過這個答案,https://stackoverflow.com/questions/466947/are-temporary-tables-thread-safe,但是我真的需要像“假裝我是 6 歲”這樣的解釋,這樣我’我非常清楚我假設的場景中發生了什麼,就 SQL 查詢如何利用連接和確定獨占訪問等而言。任何可以給我一個完整命令的資源圖表或指針都會很棒!

本地臨時對象由 Session 分隔。如果您有兩個查詢同時執行,那麼它們顯然是兩個完全獨立的會話,您無需擔心。登錄無關緊要。如果您使用的是連接池,那也沒關係。本地臨時對象(最常見的表,還有儲存過程)是安全的,不會被其他會話看到。

雖然您的程式碼對本地臨時對像有一個單一的通用名稱,但 SQL Server 會為每個會話(如果需要,每個子程序)的每個對象名稱附加一個唯一的字元串,以使它們分開。您可以通過在 SSMS 中執行以下查詢來查看這一點:

CREATE TABLE #T (Col1 INT)

SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%';

您將看到類似於以下名稱的內容(我從名稱中間刪除了大部分下劃線,以防止需要在此處滾動):

#T_______________00000000001F

然後,在不關閉該查詢選項卡的情況下,打開一個新的查詢選項卡並粘貼相同的 2 個查詢並執行它們。您現在應該看到如下內容:

#T_______________00000000001F
#T_______________000000000020

因此,每次您的程式碼引用#T時,SQL Server 都會根據會話將其轉換為正確的名稱。這一切都是自動處理的:-)。

為了說明這一點。我曾在高度事務性(每秒數千個事務)的系統上工作,並且是 SaaS(軟體即服務)Web 應用程序 24 / 7 執行。所有 T-SQL 程式碼都在儲存過程中(意思是:相同的本地臨時表名稱每次執行該程式碼),我們很好地利用了本地臨時表。作為一個網路應用程序,幾乎所有連接的登錄都是相同的,我們肯定使用了連接池。我們從來沒有遇到任何問題表明任何同名本地臨時對象的跨會話訪問。坦率地說,如果真的發生了,我們會感到震驚並利用我們與微軟的支持契約來修復它。

關於本地臨時表要記住的其他幾點:

  1. 雖然它們的名稱是唯一的,但它們的依賴對象卻不是。您不能在臨時表上創建觸發器或外鍵,因此這實際上是關於主鍵、檢查約束和預設約束。這意味著命名主鍵#PK_#T不會使其成為唯一名稱,並在名稱後面附加一個幕後唯一 ID。如果您嘗試這樣做,您將得到“無法創建對象。對像已存在。” 錯誤(好吧,假設多個並發執行相同的程式碼)。因此,如果您需要將這 3 種對像類型中的任何一種用於本地臨時表,請內聯創建依賴對象,以便它/它們將獲得系統生成的名稱,這些名稱將是唯一的並且不會在會話之間發生衝突。

您無需擔心索引名稱,因為它們已經被分開[object_id]。 2. 假設您得到“無法創建對象。對像已存在。” 創建命名的依賴對象時出現錯誤,這帶來了一個關於“每個會話是否完全隔離本地臨時對象”這個問題最常被忽視的好點:如果其他會話可以看到本地臨時表,那麼該CREATE TABLE語句將得到一個錯誤,對吧? 3. 本地臨時表的細微差別(這也是上面 #2 的鬆散反點)是,如果您在EXEC子流程啟動之前創建的子流程(即)中引用本地臨時表,它將能夠查看(甚至修改)該本地臨時表。但是,如果該子程序創建另一個具有相同名稱的臨時表,則將有兩個對象,其末尾附加了單獨的唯一 ID,可通過短名稱訪問。我記得在某處讀到不能保證引用#name在子流程中將始終解析為在子流程中創建的該對象的版本。因此,最好在儲存過程之間有一些本地臨時表名稱的唯一性,這些儲存過程有可能在嵌套的儲存過程呼叫鏈中執行。

引用自:https://dba.stackexchange.com/questions/180069