分布式數據庫的優勢是將IO分散在不同的Physical Disk上,每次查詢都由多台Server的CPU,I/O共同負載,通過各節點並行處理數據來提高性能,劣勢是消耗大量的網絡帶寬資源,管理難度大。在SQL Server 2012 版本中,創建水平切分的分布式數據庫,必須分兩步來實現:划分子集和對子集進行並集操作。
划分子集是將原始表水平切分成若干個較小的成員表,每一個成員表都是全集的一個划分(各子集的並集是全集,其交集是空集)。每個成員表包含與原始表相同數量的列,並且每一列具有與原始表中的相應列同樣的特性(如數據類型、大小、排序規則),成員表的schema和原始表相同,只是存儲的數據不同。水平切分原始表,也叫做數據庫水平分片,sharding。在查詢時,利用分區視圖來實現水平分片對用戶透明,分區視圖對分布在不同服務器中的分區數據進行並集操作,使數據看起來來自一個表。
分布在不同場地的SQL Server通過Linked Server相互通信,通過MSDTC來保證查詢的事務特性。Linked Server定義從某一數據庫服務器到另一數據庫服務器的單向通信路徑,而MSDTC能夠保證一個事務在不同的Server上實現ACID屬性。例如,在一個事務中存在 Server1上的 Insert 操作和 Server2上 Update 操作 ,如果事務回滾,那么MSDTC保證Server1 和 Server2的操作都要回滾;如果事務提交,MSDTC保證Server1 和 Server2的操作都要Commit。
設計目的:將table dbo.Person 的數據水平分片,分布到兩天SQL Server上,Column [PersonType] 共有6個值,分別是:('IN','EM','SP'),('SC','VC','GC');
CREATE TABLE [dbo].[Person] ( [PersonID] [int] NOT NULL, [PersonType] [nchar](2) NOT NULL, [FirstName] [sysname] NOT NULL, [MiddleName] [sysname] NOT NULL, [LastName] [sysname] NOT NULL )
step1,打開Win10 MSDTC(Microsoft Distributed Transaction Coordinator)
參考《Win10 打開MSDTC》,不再贅述。
step2,分別在兩台Server上創建數據庫和表,數據庫分別是DBtest1 和 DBTest2,將DBTest1作為Master DB,將DBTest2作為Slave DB。
--default instance CREATE TABLE [dbo].[Person]( [PersonID] [int] NOT NULL, [PersonType] [nchar](2) NOT NULL, [FirstName] sysname, [MiddleName] sysname , [LastName] sysname, constraint chk__Person_PersonType check([PersonType] in ('IN','EM','SP')) ); --named instance CREATE TABLE [dbo].[Person]( [PersonID] [int] NOT NULL, [PersonType] [nchar](2) NOT NULL, [FirstName] sysname, [MiddleName] sysname , [LastName] sysname, constraint chk__Person_PersonType check([PersonType] in ('SC','VC','GC')) );
Step3,在Master DB中,添加Linked Server
--add linked server exec sys.sp_addlinkedserver @server= N'db1'
,@srvproduct= N'' ,@provider= N'SQLNCLI' ,@datasrc= N'LJHPC\NamedInstance1' ,@location= null ,@provstr= null ,@catalog= N'dbtest2' --check select * from sys.servers where is_linked=1 --drop linked server --EXEC sys.sp_dropserver @server=N'db1', @droplogins='droplogins' --add login exec sp_addlinkedsrvlogin @rmtsrvname = 'db1' ,@useself=false ,@locallogin=null ,@rmtuser ='sa' ,@rmtpassword='sa'
step4,創建分布式水平分區視圖
create view dbo.view_Person as select [PersonID] ,[PersonType] ,[FirstName] ,[MiddleName] ,[LastName] from [dbo].[Person] with(nolock) where [PersonType] in('IN','EM','SP') union all select [PersonID] ,[PersonType] ,[FirstName] ,[MiddleName] ,[LastName] from db1.[DBTest2].[dbo].[Person] with(nolock) where [PersonType] in('SC','VC','GC') with check OPTION;
Step5,查詢分布式數據,查看執行計划
SELECT * from dbo.view_Person p where p.PersonType in ('em','sc')
Step6,優化
分布式事務使用的資源遠大於內部事務,通常使用OPENQUERY等相關行集函數,避免過度依賴分布式事務。
1,使用OpenQuery,避免DTC的干預
create view dbo.view_Person as select [PersonID] ,[PersonType] ,[FirstName] ,[MiddleName] ,[LastName] from [dbo].[Person] with(nolock) where [PersonType] in('IN','EM','SP') union all select [PersonID] ,[PersonType] ,[FirstName] ,[MiddleName] ,[LastName] from OPENQUERY ( db1 , N'select [PersonID] ,[PersonType] ,[FirstName] ,[MiddleName] ,[LastName] from db1.[DBTest2].[dbo].[Person] with(nolock) where [PersonType] in(''SC'',''VC'',''GC'')' ) as p with check OPTION;
2,在Local Server上更新分片數據
update db1.DBTEST2.dbo.person set FirstName=N'Harm' where PersonId=102; --修改成 exec db1.DBTEST2.sys.sp_executesql N'update dbo.person set FirstName=N''Harm'' where PersonId=102;'
Appendix
--SQL Server 阻止了對組件 'Ad Hoc Distributed Queries' exec sp_configure 'show advanced options',1 reconfigure exec sp_configure 'Ad Hoc Distributed Queries',1 reconfigure --使用完成后,關閉Ad Hoc Distributed Queries: exec sp_configure 'Ad Hoc Distributed Queries',0 reconfigure exec sp_configure 'show advanced options',0 reconfigure
參考doc: