跨伺服器中繼資料
本頁包含連結伺服器名單、四段式名稱為什麼只能走 OPENQUERY,以及對面不通時的退避。 換資料庫那一半見跨資料庫。
連結伺服器:名字在本機,內容在對面
sys.servers 就在目前這條連線上,所以「這台伺服器掛了哪些連結伺服器」是一次本機 查詢,附掛在第一層快照裡,不對任何一台連結伺服器送出東西。這份名單有兩個用途: FROM 之後列得出伺服器名稱,以及讓 LibMirror. 這一段被認成伺服器而不是結構描述。
名稱不保證是識別字的形狀——連結伺服器可以直接以位址命名([192.0.2.10]), 任何「這看起來像不像名稱」的判斷都不成立,只能照名單比對。
[LibMirror].[LibArchive].[dbo].[Loan] 這種四段式名稱要的東西在對面那台伺服器上。 它換不了連線——那台伺服器不是我們連得上的——所以與跨資料庫剛好相反: 連線原封不動,換的是 SQL 的限定字(SqlCatalogQualifier)。兩者都產出一份 SqlMetadataCatalog,四層載入一行都不知道差別。
只能走 OPENQUERY,不能寫四段式
實測 [srv].[db].sys.objects 回傳的是 sysrscols 這一類內部系統資料表,不是使用者 物件——那不是慢,是答錯。OPENQUERY 讓整句在對方執行,只有結果過線,順帶避開 把遠端目錄檢視整份拉回來本機 JOIN(sys.columns 那條有五個 JOIN)。條件是連結 伺服器的 is_data_access_enabled = 1;is_rpc_out 不需要。
兩件事跟著這個決定走,而且都寫在 SqlCatalogQualifier 一份:
@objectId內嵌成常值。OPENQUERY的內層是字串常值,參數傳不進去。 型別是int,沒有注入面,但格式必須是不變文化。OBJECT_DEFINITION換成sys.sql_modules。 前者是本機函式,加不了限定字, 跨過去會在對方登入的預設資料庫裡找 object_id,於是拿到另一個資料庫裡剛好 同號的那個物件的定義。兩者讀的是同一欄,行為一致。
漏掉任何一條查詢的限定字沒有徵兆:它會在本機執行成功並回傳本機的東西。 因此測試不逐條列舉,而是反射掃過 SqlMetadataQueries 的每一條,確認遠端形式裡 沒有一個沒加限定字的 sys.、也沒有一個殘留的參數名稱。
伺服器本身那一格只問資料庫清單
LibMirror. 要的只有資料庫名稱。物件與結構描述要再往右一格才問得到,在這裡先撈 一份等於對那台伺服器多送兩輪誰也不會看的查詢。這份快照因此只有 Databases—— IsEmpty 必須把它算進來,否則它永遠不「新鮮」,每按一次鍵就重查一次。
對面不通不會變成本機打字卡住
三件事疊起來:命令逾時跨伺服器時比本機短、載入閘是每個目錄一把(卡住的那一輪 只擋住自己)、失敗退避讓同一個目標在一段時間內只撞一次。
還沒有實測結論的是「連結伺服器登入失敗在某些設定下會冒出 SSMS 自己的對話框」。 那不是 DbException,一般降級接不住它。 真的遇上時要在這裡補一條。
SELECT * 展開與 F12 走同一份目錄:查不到就整個不做,不退回只用名稱比對—— 退回去會跳到本機剛好同名的物件,而畫面上看不出跳錯了。