MSSQl分佈式查詢

MSSQlServer所謂的分佈式查詢(Distributed Query)是可以訪問存放在同一部計算機或不一樣計算機上的SQL Server或不一樣種類的數據源, 從概念上來講分佈式查詢與普通查詢區別 它須要鏈接多個MSSQL服務器也就是具備多了數據源.實如今服務器跨域或跨服務器訪問. 而這些查詢是否被使用徹底看使用的須要. sql

本篇將演示利用SQlExpress連接遠程SQlServer來獲取數據方式來詳細說明分佈式查詢須要注意細節.先看一下系統架構數據查詢基本處理:數據庫

固然若是採用了分佈式查詢 咱們系統採起數據DataBase也就可能在多個遠程[Remote Server]上訪問時: 編程

如上截取系統架構中關於數據與緩存流向中涉及的分佈式查詢業務, 當咱們從客戶端Client發起請求數據時. 首先檢查MemCache Server緩存服務器是否有咱們想要數據. 若是沒有我須要查詢數據庫.  而此時數據要求查詢多個遠程服務器上多個數據庫中表, 這時利用分佈式查詢.得到數據 而後更新咱們在緩存服務器MemCache Server上數據保持數據更新同步, 同時向客戶端Client直接返回數據.那如何來執行這一系列動做中最爲關鍵分佈式查詢? 跨域

<1>分佈式查詢方式

咱們知道Microsoft微軟公用的數據訪問的API是OLE_DB, 而對數據庫MSSQlServer 2005的分佈式查詢支持也是OLE_DB方式.SQL Server 用戶可使用分佈式查詢訪問如下內容:緩存

A:存儲在多個 SQL Server 實例中的分佈式數據安全

B:存儲在各類可使用 OLE DB 訪問接口訪問的關係和非關係數據源中的異類數據服務器

OLE DB 訪問接口將在稱爲行集的表格格式對象中公開數據。SQL Server 容許在 Transact-SQL 語句中像引用 SQL Server 表同樣引用 OLE DB 訪問接口中的行集,[其實不用關心這個行集概念 它的功能相似SQl中臨時表 不過它容積更大 能容納類型更多 更豐富]數據結構

SQL Server 實例的客戶機與 OLE DB 訪問接口之間的鏈接 以下圖:架構

在MSSQL2005中則支持兩種方式來進行分佈式查詢:分佈式

<A>使用添加連接服務器方式(Add Link Server)

<B>使用特定名稱及特定數據源來直接指定(Add Host Names) 

其實這兩種方式在實際運用中是有區別的:

方式A:Add Link Server方式創建服務器之間關聯.建立一個連接的服務器,使其容許對分佈式的、針對 OLE DB 數據源的異類查詢進行訪問. 通常適用於持久的數據操做 對於數據量偏大 服務器之間交付時間長特色.

方式B: Add Host Name 利用域來惟一識別數據庫以及數據庫表對象. 來實現跨服務器訪問. 這種方式通常比較簡單 主要適用於對數據需求臨時性查詢是使用偏多. 不適合作大批量數據提取. 有性能瓶頸.

<2>分佈式查詢實現

在進行實現分佈式查詢以前.本次測試Demo對應的SQL版本:

肯定SQLServer版本後以下會演示兩種方式來實現分佈式查詢,並對Distributed Query中詳細細節進行說明.

<2.1>連接服務器查詢

連接服務器配置使 SQL Server 能夠對遠程服務器上的 OLE DB 數據源執行命令。連接服務器具備如下優勢:

  1. 訪問遠程服務器。
  2. 可以對企業內的異類數據源發出分佈式查詢、更新、命令和事務。
  3. 可以以類似的方式肯定不一樣的數據源

下圖顯示了連接服務器配置的基礎:

 

如今利用連接服務器方式實現數據訪問遠程服務器數據庫CustomerDB中Users表數據先本地添加LinkServer:

  
  
  
  
  1. -- 創建鏈接服務器  第一步創建鏈接  IP方式來控制     
  2. EXEC sp_addlinkedserver   '192.168.10.104' , 'SQL Server'      
  3. -- 查看連接服務器信息  [測試鏈接成功]    
  4. select name , product, provider, data_source, query_timeout, lazy_schema_validation, is_remote_login_enabled, is_rpc_out_enabled      
  5. from sys.servers     
  6. where is_linked= 1 

如上市創建鏈接服務器最簡單方式.創建連接服務器過程其實調用了系統存儲過程Sp_addlinkedserver. 第一個參數爲Name 其實用來惟一標識連接服務器. 固然能夠其餘任何有意義字符串來定義,但我我的建議使用遠程服務器的IP來標識.第二個參數是要添加爲連接服務器的 OLE DB 數據源的產品名稱. 默認爲Null,若是指定」SQlServer「則無需指定其餘參數.

若是你的本地裝有多個數據庫實例. 第一個種方式就不適用.這是就須要用SQl2005架構來惟一標識:

  
  
  
  
  1. -- 含架構名  查詢數據兩種模式     
  2. select top 10 * from [192.168.10.104]. wl . 架構名 . 表名      
  3. -- 架構名 [採用默認架構名 ]     
  4. select top 10 * from [192.168.10.104]. CustomerDB . dbo. Users 

對於Sql2005架構這個概念不少人比較陌生:

架構是造成單個命名空間的數據庫實體的集合。命名空間是一個集合,其中每一個元素的名稱都是惟一的。 例如,爲了不名稱衝突,同一架構中不能有兩個同名的表。兩個表只有在位於不一樣的架構中時才能夠同名 例如本次Demo 在CustomerDB後對應DBO既是默認的架構名.

建立後.若是須要修改鏈接服務器屬性能夠經過sp_serveroption系統Proc來設置:

  
  
  
  
  1. -- 配置連接服務器屬性 sp_serveroption爲遠程服務器和連接服務器設置服務器選項     
  2. -- 語法  sp_serveroption [@server =] 'server',[@optname =] 'option_name',[@optvalue =] 'option_value'     
  3. exec sp_serveroption '192.168.10.104','name','192.168.10.104'   
  4. -- 查看鏈接服務器     
  5. select * from sys.servers 

創建後我就能夠直接來查詢遠程服務器上數據:

  
  
  
  
  1. -- 查詢遠程服務器數據     
  2. select * from [192.168.10.104].CustomerDB.dbo.Users   --[成功]    
  3. -- sp_droplinkedsrvlogin 刪除連接服務器登陸名映射 [刪除登陸映射]     
  4. -- 若是爲 NULL,那麼將會刪除由 sp_addlinkedserver 建立的默認映射 [第二個參數]    
  5. exec sp_droplinkedsrvlogin '192.168.10.104' ,NULL     
  6. -- 刪除連接服務器屬性 [刪除服務器]    
  7. exec sp_dropserver 'mytest' --[刪除成功 同時也刪除了Sys_Server信息]    
  8. -- 查看服務器詳細信息   
  9. EXEC sp_helpserver 
查詢結果:

測試查詢成功.遠程數據成功獲取.

當測試完成後咱們不須要這個鏈接服務器是便可利用SP_DroplinkServer刪除掉. 對應參數爲建立時Name惟一標識. 經過Sp_helpserver來查看鏈接服務器詳細信息.

注意如上建立鏈接服務器時設置srvproduct參數即OLED數據源名稱時咱們採用了SQlServer方式.

下面說明這種方式特色.:

這種方式是最爲簡單直接的一種創建連接服務器方式. 可是存在前提的. 測試發現:

在全部數據庫的遠程鏈接 dbo 的方式必須創建在 SA 密碼相同的基礎上 ,不然容易產生沒法鏈接的狀況 Sa用戶登陸失敗. 你也就明白這個SQlServer參數其實就是在本地數據拷貝服務器角色SysAdmin下用戶SA.來對服務器進行登陸. 若是你的本地Sa密碼與遠程服務器上密碼不一致 則沒法正常鏈接.

通過測試還發現一種狀況:

利用Windows7訪問XP(Sp2)系統時始終提示沒法解析或拒絕鏈接SQlServer2005.這個問題我整了很久後來纔到官方連接參數中發現.:若是你的XP系統沒有打上SP4的補丁包 這個問題會始終出現. 須要特別注意.

<2.2>直接指定數據源分佈式查詢

其實相對第一種方式, 直接指定方式在SQlServer架構中 其實跳過本地與遠程服務器創建映射關係的這一步. 經過連接關係創建 其實就是創建一種內部映射關係. 若是沒有映射關係則 大部分設置須要手動控制.

直接指定數據源方式 須要開啓分佈式查詢的基本權限 來進行查詢:

  
  
  
  
  1. -- 若是想使用分佈式查詢,必須先開通分佈式查詢 [外圍配置 這點是全部查詢操做前提]     
  2. -- sp_configure--顯示或更改當前服務器的全局配置設置     
  3. -- reconfigure 指定若是配置設置不須要服務器中止並從新啓動,則更新當前運行的值     
  4. -- SQL2005默認是沒有開啓’Ad Hoc Distributed Queries’ 組件      
  5. -- 啓用權限     
  6. exec sp_configure 'show advanced options',1  -- 顯示高級配置     
  7. reconfigure -- 更新值    
  8. exec sp_configure 'Ad Hoc Distributed Queries',1 -- 啓用分佈式查詢    
  9. reconfigure    
  10. go    
  11. -- 關閉分佈式查詢    
  12. exec sp_configure 'Ad Hoc Distributed Queries',0       
  13. reconfigure    
  14. exec sp_configure 'show advanced options',0    
  15. reconfigure    
  16. go      
  17. -- 開啓權限後 另一種查詢方式    
  18. -- 查詢格式    
  19. SELECT * FROM OPENDATASOURCE(    
  20. 'SQLOLEDB',    
  21. 'Data Source=遠程ip;User ID=sa;Password=密碼'    
  22. ).庫名.dbo.表名    
  23. WHERE 條件    
  24. -- 須要開啓權限     
  25. -- 開啓權限 提示[遠程的SqlServer不容許遠程鏈接]    
  26. select * from OPENDATASOURCE('SQLOLEDB','Data Source=192.168.10.67; User ID=sa; Password=chenkai').wl.dbo.Users 

開啓權限後. 須要裏利用ReConfig命令來確認.對目前分佈式查詢權限的修改. 若是在使用完分佈式查詢後注意關閉.最後查詢結果:

測試成功.

有些人說使用數據庫角色SysAdmin角色下的Sa用戶進行遠程數據傳輸和驗證. 不安全. 其實在使用過程當中應該不難看出. 在從遠程服務器拉取數據庫過程當中. 本地數據庫須要對權限,建立鏈接服務器都須要最大用戶權限來操做. 而服務器呢, 只須要能鏈接上 同時對指定數據CustomerDB具備讀寫的權限便可. 固然你更多遠程操做能夠把用戶賦予CustomerDB的OWner角色.

這時咱們如何用非SA用戶來來鏈接遠程用戶?

咱們如今遠程服務器上對鏈接建立一個用戶名爲Test的用戶 服務器角色設置Public便可:

在用戶角色設置中須要對指定訪問數據CustomerDB具備讀寫權限: 

在遠程服務器建立TEst用戶時使用SQlServer身份驗證方式登陸 這時設置密碼爲RemoteDB.在使用非Sa用戶進行遠程:

  
  
  
  
  1. -- 執行前先刪除已經存在數據     
  2. Exec sp_droplinkedsrvlogin [192.168.10.76],Null     
  3. Exec sp_dropserver 'demodb'    
  4. -- 建立服務器鏈接     
  5. EXEC  sp_addlinkedserver     
  6. @server='demodb',-- 被訪問的服務器別名      
  7. @srvproduct='',     
  8. @provider='SQLOLEDB',    
  9. @datasrc='192.168.10.76'   -- 要訪問的服務器    
  10. EXEC sp_addlinkedsrvlogin     
  11. 'demodb'-- 被訪問的服務器別名    
  12. 'false',     
  13. NULL,    
  14. 'Test'-- 賬號   
  15. 'RemoteDB' -- 密碼 

如上咱們首先清除已經可能建立服務器數據記錄. 而後建立服務器鏈接.sp_addlinkedSrvlogin系統存儲過程用來建立連接服務器上遠程登陸之間的映射 . 即咱們能夠詳細設置本地與遠程服務器詳細的映射信息. 例如設置咱們特定用戶訪問的用戶名和密碼.

查詢數據:

  
  
  
  
  1. -- 查詢指定用戶Test數據     
  2. select * from [demodb].CustomerDB.dbo.Users -- [如上測試成功] 

查詢結果:

指定用戶Test對CustomerDB訪問數據方式測試成功.

 

<3>問題排查與更多查詢方式

 

當咱們在實際編程中進行訪問遠程數據時 由於不一樣操做環境會引起各類各樣的異常,以下我會提出一種常見的異常方式解決辦法和關於遠程數據操做更多查詢方式.

<3.1>沒法創建遠程鏈接

其實這個問題在作分佈式查詢時極其常見. 而引發這個問題的因素過多. 咱們一時沒法判斷真正引起這個異常地方. 只能經過逐個排查方式來進行設置:

例如咱們在創建關聯關係後 進行查詢時會遇到:

提示是: 在進行遠程鏈接時超時, 引發這個問題緣由多是遠程服務器積極拒絕訪問!

首先要在Sql Server Configuation Manager中保證你服務已經運行 且是開機自動運行.

再次檢查SQl2005外圍配置DataBaseEngine容許遠程鏈接:

設置完成後.咱們還須要設置Sql Server Analysis Services分析服務也支持遠程數據查詢:

在遠程服務器上若是啓用了防火牆則可能對目前SQl Server方位實例進行攔截. 因此在服務器端啓用防火牆狀況下要爲SQl DAtaBase建立例外.防止客戶端請求被攔截.

<3.2>進程被其餘用戶佔用

當咱們在遠程分佈式查詢中有建立動做或是相似建立一個新的數據庫. 有時會提示 「該數據庫沒法操做 已經別其餘進程佔用」異常. 致使咱們沒法訪問數據庫. 或是執行咱們要作的建立操做.

遇到這種狀況咱們能夠利用SA權限查詢到Master數據庫對應數據庫被佔用的進程 並殺掉Kill Process.查詢:

  
  
  
  
  1. -- [sysprocesses 表中保存關於運行在 Microsoft® SQL Server™ 上的進程的信息。     
  2. -- 這些進程能夠是客戶端進程或系統進程。sysprocesses 只存儲在 master 數據庫中]     
  3. use Master    
  4. go      
  5. SELECT * FROM sysprocesses ,sysdatabases WHERE sysprocesses.dbid=sysdatabases.dbid AND sysdatabases.Name='CustomerDB'      
  6. select * from sysprocesses    
  7. select * from sysdatabases     
  8. -- 殺死佔用進程    
  9. kill 5 

當咱們對進程佔用清除時有可能訪問數據庫被系統進程佔用. 則這時用Sa沒法殺死.這時提示: 

 

「Only use Process can be Kill 」在SQl2005 只有只有用戶進程才能Kill掉.

<3.3>更多的查詢操做

每每咱們在實際操做中須要對數據讀寫有更多要求. 例如從遠程鏈接多個服務器進行數據讀取或是把本地數據提交到服務器上. 爲了提升效率和性能採用分佈式事務來進行批量操做等等. 以下簡單介紹在分佈式查詢中多中數據操做:

把遠程數據導入本地:

  
  
  
  
  1. -- 導入數據操做     
  2. select top(3) * into TestDB.dbo.CopyDb from  [192.168.10.76].wl.dbo.Users 

導入時使用Into方式 自動在本地建立CopyDB表徹底複製遠程服務器上Users表的數據結構.可是要注意在進行後 的CopyDB將不包含原表的主鍵和索引約束. 雖然能快構建 可是主鍵和索引設置都會丟失.

本地數據導入遠程:

   
   
   
   
  1. -- 把本地表導入遠程表 [openWset方式]  
  2.  insert openrowset( 'SQLOLEDB ''sql服務器名 ''用戶名 ''密碼 ',數據庫名.dbo.表名)  select *from 本地表   
  3. -- 把本地表導入遠程表 [open Query方式]  
  4.  insert openquery(ITSV, 'SELECT * FROM 數據庫.dbo.表名 ')  

更新本地表數據:

   
   
   
   
  1. -- 把本地表導入遠程表 [opendataSource方式]    
  2. insert opendatasource( 'SQLOLEDB ''Data Source=ip/ServerName;User ID=登錄名;Password=密碼 ').數據庫.dbo.表名       
  3. -- 更新本地表 [openowset方式]    
  4. update b  set b.列A=a.列A  from openrowset( 'SQLOLEDB ''sql服務器名 ''用戶名 ''密碼 ',數據庫名.dbo.表名)     
  5. as a inner join 本地表 b  on a.column1=b.column1  

固然還有更多方式來操做分佈式查詢操做.各位均可以嘗試.

 

<4>尾 語

 

如上是我最近在項目中處理關於分佈式查詢涉及到方方面面. 從系統架構到分部是查詢具體操做細節.基本都是一些很是基礎運用.固然也參考很多資料.以及動手來驗證整個過程出現問題緣由所在. 篇幅有限 寫的有些倉促. 不免有紕漏地方 還望各位指正.

相關文章
相關標籤/搜索