SQL Server數據庫文件與文件組總結

 

文件和文件組概念html

 

關於文件與文件組,簡單歸納以下,詳情請參考官方文檔數據庫文件和文件組Database Files and Filegroups或更多相關資料:sql

 

數據文件概念:數據庫

 

每一個SQL Server數據庫至少包含兩個做系統文件:一個數據文件(data file)和一個日誌文件(log file)。數據文件包含數據和對象,例如表、索引、存儲過程和視圖....。日誌文件包含恢復數據庫所需的全部事務的相關數據。其實在SQL Server中,數據文件分爲三類,分別爲:app

 

主數據文件性能

 

        主數據文件包含數據庫的啓動信息,並指向數據庫中的其餘文件。 用戶數據和對象可存儲在此文件中,也能夠存儲在輔助數據文件中。每一個數據庫有一個主要數據文件。 優化

        主要數據文件的建議文件擴展名是 .mdf。ui

 

輔助數據文件spa

 

        輔助數據文件是可選的,由用戶定義並存儲用戶數據。 經過將每一個文件放在不一樣的磁盤驅動器上,輔助數據文件可用於將數據分散到多個磁盤上。 3d

        另外,若是數據庫超過了單個 Windows 文件的最大大小,可使用次要數據文件,這樣數據庫就能繼續增加。日誌

        輔助數據文件的建議文件擴展名是 .ndf。

 

    事務日誌文件

        事務日誌文件保存用於恢復數據庫的日誌信息。 每一個數據庫必須至少有一個日誌文件。 事務日誌的建議文件擴展名是 .ldf。

 

 

 

    注意:雖然文件的擴展名是能夠修改的,但強烈建議不要去改擴展名。

 

 

文件組概念:

 

文件組(File Group),簡單來講,就是數據文件的組合。爲了便於分配和管理,能夠將數據文件集合起來,放到文件組中。每一個數據庫有一個主要文件組(Primary File Group),這個是默認的。 此文件組包含主要數據文件和未放入其餘文件組的全部次要文件。 能夠建立用戶定義的文件組,用於將數據文件集合起來,以便於管理、數據分配和放置。整體來講,文件組是一個邏輯概念,相似於Oracle數據庫的表空間,文件組與文件的關係就相似於ORACLE中表空間與文件的概念。

 

文件組分類:

 

        主文件組(Primary)

        內存優化數據文件組(Memory Optimized Data)

        Filestream 文件組(Filestream)

        用戶自定義文件組(User-defined)

 

注意事項:PRIMARY 文件組是默認文件組,除非使用 ALTER DATABASE 語句進行了修改。另外,即便指定其它文件組爲默認文件組。但系統對象和表仍然分配給 PRIMARY 文件組,而不是新的默認文件組。

   

 

 

文件組的優缺點

 

 文件組是邏輯概念,一個文件組對應一個或多個文件。建立表的時候指定文件組便可(默認,指定PRIMARY文件組),這樣能夠隔離用戶對文件的依賴,耦合性就要低不少。另外,使用多個文件組和文件不只僅是爲了分散IO和提升性能,還有高可用性方面的緣由。有關一個數據庫應該包含幾個文件或文件組[下面部份內容來自SQL Server中數據庫文件的存放方式,文件和文件組]

 

  數據庫中使用多個文件或文件組在高可用性方面的好處包括:

·         某文件的IO損壞,數據庫還能夠保證部分在線。

·         將索引和表分開存放,假如索引文件不在線,數據依然能夠被訪問。

·         歷史數據和熱數據分開,歷史歸檔數據損壞,不影響熱數據。

·         分開數據文件使得在災難恢復時僅僅恢復部分數據從而縮短了宕機時間

·         數據庫分爲多個文件使得能夠經過增長文件或移動文件的方式解決空間不足的問題

 

 

 從用戶的角度來講,建立對象時須要指定存儲文件組的只有三種數據對象:表,索引和大對象(LOB)

  

  使用文件組能夠隔離用戶對文件的依賴,使得用戶僅僅針對文件組來創建表和索引,而不用關心實際磁盤中的文件的狀況。當文件移動或修改時,因爲用戶創建的表和索引是創建在文件組上的,並不依賴具體文件,所以SQL Server能夠放心的管理文件。

 

  另外,使用文件組的方式來管理文件,可使得同一文件組內的文件分佈在不一樣的硬盤中,可以大大提供IO性能。

 

  SQL Server根據每一個文件設置的初始大小和增量值自動分配新加入的空間,假設在同一文件A設置的大小爲文件B的兩倍,新增一個數據佔用3頁,則按比例將2頁分配到文件A中,1頁分配到文件B

 

 

 

新增文件組

 

以下所示,建立兩個文件組,DB_Data_Groups用來存放數據(彙集索引),DB_Index_Groups用來存放索引(非彙集索引)

 

 

--建立文件組DB_Index_Groups
USE [master]
GO
ALTER DATABASE [YourSQLDb] ADD FILEGROUP [DB_Index_Groups]
GO
 
--建立文件組DB_Data_Groups
USE [master]
GO
ALTER DATABASE [YourSQLDb] ADD FILEGROUP [DB_Data_Groups]
GO
 
 
--向文件組新增文件
USE [master];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_IND_01', FILENAME = N'D:\SQL_DATA\YourSQLDb_IND_01.ndf' , SIZE = 16GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Index_Groups];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_IND_02', FILENAME = N'E:\SQL_DATA\YourSQLDb_IND_02.ndf' , SIZE = 16GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Index_Groups];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_IND_03', FILENAME = N'F:\SQL_DATA\YourSQLDb_IND_03.ndf' , SIZE = 16GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Index_Groups];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_IND_04', FILENAME = N'G:\SQL_DATA\YourSQLDb_IND_04.ndf' , SIZE = 16GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Index_Groups];
GO
 
USE [master];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_DATA_01', FILENAME = N'D:\SQL_DATA\YourSQLDb_DATA_01.ndf' , SIZE = 26GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Data_Groups];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_DATA_02', FILENAME = N'E:\SQL_DATA\YourSQLDb_DATA_02.ndf' , SIZE = 26GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Data_Groups];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_DATA_03', FILENAME = N'F:\SQL_DATA\YourSQLDb_DATA_03.ndf' , SIZE = 26GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Data_Groups];
GO
ALTER DATABASE [YourSQLDb] ADD FILE ( NAME = N'YourSQLDb_DATA_04', FILENAME = N'G:\SQL_DATA\YourSQLDb_DATA_04.ndf' , SIZE = 26GB , FILEGROWTH = 256MB ) TO FILEGROUP [DB_Data_Groups];
GO
 
 

 

 

 

 

 

文件組間移動數據

 

如何在SQL Server的文件組直接移動數據呢?關於這個問題呢,有時候也算簡單,可是若是你沒有踩過坑,不是一個老司機的話,建議你仍是看一看下面內容。對於在文件組移動數據文件,分下面幾種狀況:

 

非分區表

 

1: 彙集索引表

   

    1.1 表沒有LOB對象

       

        方法:重建彙集索引和非彙集索引能夠移動文件組。

 

    1.2 表擁有LOB對象

           

        方法:重建表到新文件組,將數據導入。由於重建彙集索引,不會將LOB對象移動到對應表空間。

   

2: 堆表

   

    2.1 表沒有LOB對象

 

        方法1:新建一個彙集索引,轉移文件組後,刪除彙集索引。

        方法2:重建表到新文件組,導入數據。

       

    2.1 表有LOB對象

 

        方法:重建表到新文件組,導入數據。

 

案例演示:咱們要將數據庫AdventureWorks2014中的表BusinessEntityAddress 從文件組Primary移動到文件組[DB_Data_Groups],在移動以前,咱們先檢查一下表BusinessEntityAddress的相關狀況,以下所示,這個表屬於上述狀況的1.1。

 

 

DECLARE @file_group_name  NVARCHAR(32);
 
SET @file_group_name ='PRIMARY'
 
SELECT ds.name                         AS DataSpaceName 
      ,au.type_desc                    AS AllocationDesc 
      ,au.total_pages*1.0 / 128        AS [TotalSize(MB)] 
      ,au.used_pages*1.0  / 128        AS [UsedSize(MB)] 
      ,au.data_pages*1.0  / 128        AS [DataSize(MB)] 
      ,sch.name                        AS SchemaName     
      ,obj.name                        AS ObjectName 
      ,obj.type_desc                   AS ObjectType   
      ,idx.type_desc                   AS IndexType 
      ,idx.name                        AS IndexName 
      INTO #tmp_tables
FROM sys.data_spaces AS ds 
     INNER JOIN sys.allocation_units AS au 
         ON ds.data_space_id = au.data_space_id 
     INNER JOIN sys.partitions AS pa 
         ON (AU.type IN (1, 3)  
             AND au.container_id = pa.hobt_id) 
            OR 
            (au.type = 2 
             AND au.container_id = pa.partition_id) 
     INNER JOIN sys.objects AS obj
         ON pa.object_id = obj.object_id 
     INNER JOIN sys.schemas AS sch 
         ON obj.schema_id = sch.schema_id 
     LEFT JOIN sys.indexes AS idx 
         ON pa.object_id = idx.object_id 
            AND pa.index_id = idx.index_id 
WHERE DS.name=@file_group_name
ORDER BY AU.total_pages DESC
 
 
 
SELECT  *
FROM    #tmp_tables
WHERE   ObjectType = 'USER_TABLE' AND ObjectName='Person'
ORDER BY  [TotalSize(MB)]  DESC;
 
 
SELECT  COUNT(DISTINCT ObjectName)
FROM    #tmp_tables
WHERE   ObjectType != 'SYSTEM_TABLE';
DROP TABLE #tmp_tables;

 

 

clip_image001_thumb

 

對於這種狀況,咱們用下面腳本生成重建索引的腳本(爲何要用腳本生成呢,實際狀況中,可能有不少或大量的表須要移動表空間,此時腳本的效率就凸現出來了。)

 

--從新建立彙集索引,移動數據到文件組DB_Data_Groups
SELECT ' CREATE '
    CASE WHEN I.is_unique = 1 THEN ' UNIQUE ' ELSE '' END  +   
    I.type_desc COLLATE DATABASE_DEFAULT +' INDEX ' +    
    QUOTENAME(I.name)  + ' ON '  +   
    Schema_name(T.Schema_id)+'.'+ QUOTENAME(T.name) + ' ( '
    KeyColumns + ' )  '
    ISNULL(' INCLUDE ('+IncludedColumns+' ) ','') +  
    ISNULL(' WHERE  '+I.Filter_definition,'') + ' WITH ( '
    CASE WHEN I.is_padded = 1 THEN ' PAD_INDEX = ON ' ELSE ' PAD_INDEX = OFF ' END + ','  +  
    'FILLFACTOR = '+CONVERT(CHAR(5),CASE WHEN I.Fill_factor = 0 THEN 100 ELSE I.Fill_factor END) + ','  +  
    -- default value  
    'SORT_IN_TEMPDB = OFF '  + ','  +  
    CASE WHEN I.ignore_dup_key = 1 THEN ' IGNORE_DUP_KEY = ON ' ELSE ' IGNORE_DUP_KEY = OFF ' END + ','  +  
    CASE WHEN ST.no_recompute = 0 THEN ' STATISTICS_NORECOMPUTE = OFF ' ELSE ' STATISTICS_NORECOMPUTE = ON ' END + ','  +  
    -- default value   
    ' DROP_EXISTING = ON '  + ','  +  
    -- default value   
    ' ONLINE = OFF '  + ','  +  
   CASE WHEN I.allow_row_locks = 1 THEN ' ALLOW_ROW_LOCKS = ON ' ELSE ' ALLOW_ROW_LOCKS = OFF ' END + ','  +  
   CASE WHEN I.allow_page_locks = 1 THEN ' ALLOW_PAGE_LOCKS = ON ' ELSE ' ALLOW_PAGE_LOCKS = OFF ' END  + ' ) ON [DB_Data_Groups]; '  [CreateIndexScript]  
   --,I.is_unique
FROM sys.indexes I    
 JOIN sys.tables T ON T.Object_id = I.Object_id         
 JOIN (SELECT * FROM (   
    SELECT IC2.object_id , IC2.index_id ,   
        STUFF((SELECT ' , ' + C.name + CASE WHEN MAX(CONVERT(INT,IC1.is_descending_key)) = 1 THEN ' DESC ' ELSE ' ASC ' END 
    FROM sys.index_columns IC1   
    JOIN Sys.columns C    
       ON C.object_id = IC1.object_id    
       AND C.column_id = IC1.column_id    
       AND IC1.is_included_column = 0   
    WHERE IC1.object_id = IC2.object_id    
       AND IC1.index_id = IC2.index_id    
    GROUP BY IC1.object_id,C.name,index_id   
    ORDER BY MAX(IC1.key_ordinal)   
       FOR XML PATH('')), 1, 2, '') KeyColumns    
    FROM sys.index_columns IC2    
    GROUP BY IC2.object_id ,IC2.index_id) tmp3 )tmp4    
  ON I.object_id = tmp4.object_id AND I.Index_id = tmp4.index_id   
 JOIN sys.stats ST ON ST.object_id = I.object_id AND ST.stats_id = I.index_id    
 JOIN sys.data_spaces DS ON I.data_space_id=DS.data_space_id    
 JOIN sys.filegroups FG ON I.data_space_id=FG.data_space_id    
 LEFT JOIN (SELECT * FROM (    
    SELECT IC2.object_id , IC2.index_id ,    
        STUFF((SELECT ' , ' + C.name  
    FROM sys.index_columns IC1    
    JOIN Sys.columns C     
       ON C.object_id = IC1.object_id     
       AND C.column_id = IC1.column_id     
       AND IC1.is_included_column = 1    
    WHERE IC1.object_id = IC2.object_id     
       AND IC1.index_id = IC2.index_id     
    GROUP BY IC1.object_id,C.name,index_id    
       FOR XML PATH('')), 1, 2, '') IncludedColumns     
   FROM sys.index_columns IC2     
   GROUP BY IC2.object_id ,IC2.index_id) tmp1    
   WHERE IncludedColumns IS NOT NULL ) tmp2     
ON tmp2.object_id = I.object_id AND tmp2.index_id = I.index_id    
WHERE  I.type=1 AND i.data_space_id=1 
AND t.name ='BusinessEntityAddress'
AND FG.name !='DB_Data_Groups'

 

 

此時上面腳本會生成下面腳本

 

 

CREATE  UNIQUE CLUSTERED INDEX [PK_BusinessEntityAddress_BusinessEntityID_AddressID_AddressTypeID] 
ON Person.[BusinessEntityAddress] (  BusinessEntityID ASC  , AddressID ASC  , AddressTypeID ASC  )   
WITH (  PAD_INDEX = OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF ,
    DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [DB_Data_Groups]; 

 

 

下面腳本生成對應表的非彙集索引,將其轉移到表空間[DB_Index_Groups]

 

WITH NoClustTable AS
(
SELECT DISTINCT
        SCHEMA_NAME(so.schema_id) AS 'SchemaName' ,
        OBJECT_NAME(so.object_id) AS 'TableName' ,
        so.object_id AS 'object_id' ,
        CASE OBJECTPROPERTY(MAX(so.object_id), 'TableHasClustIndex')
          WHEN 0 THEN COUNT(si.index_id) - 1
          ELSE COUNT(si.index_id)
        END AS 'IndexCount' 
FROM    sys.objects so ( NOLOCK )
        JOIN sys.indexes si ( NOLOCK ) ON so.object_id = si.object_id
                                          AND so.type IN ( N'U', N'V' )
        JOIN sysindexes dmv ( NOLOCK ) ON so.object_id = dmv.id
                                          AND si.index_id = dmv.indid
        FULL OUTER JOIN ( SELECT    object_id ,
                                    COUNT(1) AS ColumnCount
                          FROM      sys.columns (NOLOCK)
                          GROUP BY  object_id
                        ) d ON d.object_id = so.object_id
WHERE   so.is_ms_shipped = 0
        AND so.object_id NOT IN (
        SELECT  major_id
        FROM    sys.extended_properties (NOLOCK)
        WHERE   name = N'microsoft_database_tools_support' )
        AND INDEXPROPERTY(so.object_id, si.name, 'IsStatistics') = 0
GROUP BY so.schema_id ,
        so.object_id
HAVING  ( OBJECTPROPERTY(MAX(so.object_id), 'TableHasClustIndex') = 0
          AND COUNT(si.index_id) - 1 > 0
        )
)
 
SELECT ' CREATE '
    CASE WHEN I.is_unique = 1 THEN ' UNIQUE ' ELSE '' END  +   
    I.type_desc COLLATE DATABASE_DEFAULT +' INDEX ' +    
    QUOTENAME(I.name)  + ' ON '  +   
    Schema_name(T.Schema_id)+'.'+ QUOTENAME(T.name) + ' ( '
    KeyColumns + ' )  '
    ISNULL(' INCLUDE ('+IncludedColumns+' ) ','') +  
    ISNULL(' WHERE  '+I.Filter_definition,'') + ' WITH ( '
    CASE WHEN I.is_padded = 1 THEN ' PAD_INDEX = ON ' ELSE ' PAD_INDEX = OFF ' END + ','  +  
    'FILLFACTOR = '+CONVERT(CHAR(5),CASE WHEN I.Fill_factor = 0 THEN 100 ELSE I.Fill_factor END) + ','  +  
    -- default value  
    'SORT_IN_TEMPDB = OFF '  + ','  +  
    CASE WHEN I.ignore_dup_key = 1 THEN ' IGNORE_DUP_KEY = ON ' ELSE ' IGNORE_DUP_KEY = OFF ' END + ','  +  
    CASE WHEN ST.no_recompute = 0 THEN ' STATISTICS_NORECOMPUTE = OFF ' ELSE ' STATISTICS_NORECOMPUTE = ON ' END + ','  +  
    -- default value   
    ' DROP_EXISTING = ON '  + ','  +  
    -- default value   
    ' ONLINE = OFF '  + ','  +  
   CASE WHEN I.allow_row_locks = 1 THEN ' ALLOW_ROW_LOCKS = ON ' ELSE ' ALLOW_ROW_LOCKS = OFF ' END + ','  +  
   CASE WHEN I.allow_page_locks = 1 THEN ' ALLOW_PAGE_LOCKS = ON ' ELSE ' ALLOW_PAGE_LOCKS = OFF ' END  + ' ) ON [DB_Index_Groups]; '  [CreateIndexScript]  
   --,I.is_unique
FROM sys.indexes I    
 JOIN sys.tables T ON T.Object_id = I.Object_id     
 --JOIN sys.sysindexes SI ON I.Object_id = SI.id AND I.index_id = SI.indid    
 JOIN (SELECT * FROM (   
    SELECT IC2.object_id , IC2.index_id ,   
        STUFF((SELECT ' , ' + C.name + CASE WHEN MAX(CONVERT(INT,IC1.is_descending_key)) = 1 THEN ' DESC ' ELSE ' ASC ' END 
    FROM sys.index_columns IC1   
    JOIN Sys.columns C    
       ON C.object_id = IC1.object_id    
       AND C.column_id = IC1.column_id    
       AND IC1.is_included_column = 0   
    WHERE IC1.object_id = IC2.object_id    
       AND IC1.index_id = IC2.index_id    
    GROUP BY IC1.object_id,C.name,index_id   
    ORDER BY MAX(IC1.key_ordinal)   
       FOR XML PATH('')), 1, 2, '') KeyColumns    
    FROM sys.index_columns IC2    
    GROUP BY IC2.object_id ,IC2.index_id) tmp3 )tmp4    
  ON I.object_id = tmp4.object_id AND I.Index_id = tmp4.index_id   
 JOIN sys.stats ST ON ST.object_id = I.object_id AND ST.stats_id = I.index_id    
 JOIN sys.data_spaces DS ON I.data_space_id=DS.data_space_id    
 JOIN sys.filegroups FG ON I.data_space_id=FG.data_space_id    
 LEFT JOIN (SELECT * FROM (    
    SELECT IC2.object_id , IC2.index_id ,    
        STUFF((SELECT ' , ' + C.name  
    FROM sys.index_columns IC1    
    JOIN Sys.columns C     
       ON C.object_id = IC1.object_id     
       AND C.column_id = IC1.column_id     
       AND IC1.is_included_column = 1    
    WHERE IC1.object_id = IC2.object_id     
       AND IC1.index_id = IC2.index_id     
    GROUP BY IC1.object_id,C.name,index_id    
       FOR XML PATH('')), 1, 2, '') IncludedColumns     
   FROM sys.index_columns IC2     
   GROUP BY IC2.object_id ,IC2.index_id) tmp1    
   WHERE IncludedColumns IS NOT NULL ) tmp2     
ON tmp2.object_id = I.object_id AND tmp2.index_id = I.index_id    
WHERE   T.object_id NOT IN (
        SELECT  major_id
        FROM    sys.extended_properties (NOLOCK)
        WHERE   name = N'microsoft_database_tools_support' )
        AND I.type = 2 AND T.object_id NOT IN (SELECT object_id  FROM NoClustTable)
        AND i.data_space_id =1
        AND T.name='BusinessEntityAddress'

 

 

 

CREATE UNIQUE NONCLUSTERED INDEX [AK_BusinessEntityAddress_rowguid] ON Person.[BusinessEntityAddress] (  rowguid ASC  )   WITH (  PAD_INDEX = OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [DB_Index_Groups]; 
CREATE NONCLUSTERED INDEX [IX_BusinessEntityAddress_AddressID] ON Person.[BusinessEntityAddress] (  AddressID ASC  )   WITH (  PAD_INDEX = OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [DB_Index_Groups]; 
CREATE NONCLUSTERED INDEX [IX_BusinessEntityAddress_AddressTypeID] ON Person.[BusinessEntityAddress] (  AddressTypeID ASC  )   WITH (  PAD_INDEX = OFF ,FILLFACTOR = 100  ,SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , STATISTICS_NORECOMPUTE = OFF , DROP_EXISTING = ON , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON  ) ON [DB_Index_Groups]; 
 

 

 

對於彙集索引表,若是擁有LOB對象,那麼上述方法不徹底可行,咱們以Person.Person爲例,這個表有LOB對象。執行上面操做後,你會發現LOB_DATA 仍是位於PRIMARY文件組。

 

 

clip_image002_thumb

 

 

 

這個是由於經過重建索引的方式是沒法移動LOB對象,以下所示,生成該表的建立腳本,你會發現TEXTIMAGE_ON位於[PRIMARY]文件組,  這種情形,只能經過重建表,導入數據的方式。

 

clip_image003_thumb

 

 

我的在實際操做中,總結了一下簡單步驟:

 

 

1:使用Generate And Publish Scripts 生成含有LOB對象的表的腳本(具體細節有不少須要注意的地方),修改對應的文件組(例如將PRIMARY 改成[DB_Data_Groups] 或[DB_Index_Groups]

 

 

2確認表單獨受權給了那些用戶或角色(若是是默認角色,能夠忽略),新建這些表必須考慮權限問題,不然重建這些表就會出現權限問題。

 

 

--查看某個對象被授予了那些用戶或角色

SELECT o.name as ObjectName,u.name as objname,

CASE o.type

     WHEN 'AF'  THEN 'Aggregate Function(CLR)'

     WHEN 'C'   THEN 'Check Constraint'

     WHEN 'D'   THEN 'Default Constraint'

     WHEN 'F'   THEN 'Foreign Key Constraint'

     WHEN 'FN'  THEN 'Scalar Function'

     WHEN 'FS'  THEN 'Assembly (CLR) Scalar-Function'

     WHEN 'FT'  THEN 'Assembly (CLR) Table-Valued Function'

     WHEN 'IT'  THEN 'Internal Table'

     WHEN 'K'   THEN 'Primary Key or Unique Constraint'

     WHEN 'U'   THEN 'User Table'

     WHEN 'P'   THEN 'Stored Procedure'

     WHEN 'PC'  THEN 'Assembly (CLR) Stored Procedure'

     WHEN 'S'   THEN 'System Table'

     WHEN 'SN'  THEN 'Synonym'

     WHEN 'V'   THEN 'View'

     WHEN 'X'   THEN 'Extended Store Procedure'

     WHEN 'TF'  THEN 'Table Function'

     ELSE 'OTHER'

END AS TYPE,

CASE WHEN  p.ACTION = 26  AND p.PROTECTTYPE = 205 THEN '' ELSE '' END AS 'REFERENCES',

CASE WHEN  p.ACTION = 193 AND p.PROTECTTYPE = 205 THEN '' ELSE '' END AS 'SELECT',

CASE WHEN  p.ACTION = 195 AND p.PROTECTTYPE = 205 THEN '' ELSE '' END AS 'DELETE',

CASE WHEN  p.ACTION = 196 AND p.PROTECTTYPE = 205 THEN '' ELSE '' END AS 'INSERT',

CASE WHEN  p.ACTION = 197 AND p.PROTECTTYPE = 205 THEN '' ELSE '' END AS 'UPDATE',

CASE WHEN  p.ACTION = 224 AND p.PROTECTTYPE = 205 THEN '' ELSE '' END AS 'EXECUTE',

CASE p.PROTECTTYPE

    WHEN 204 THEN 'GRANT_W_GRANT '

    WHEN 205 THEN 'GRANT'

    WHEN 206 THEN 'DENY'

    ELSE 'OTHER'

END AS PROTECTTYPE

FROM sysprotects p

 INNER JOIN sysobjects o on p.id = o.id

 INNER JOIN sysusers u on p.uid = u.uid

WHERE o.name='Person.Person'  --具體表名

 

 

3:咱們須要將原表重命名(包括約束, 以下所示,使用下面腳本生成對應的腳本,執行後修改表名或約束名稱),而後執行步驟1裏面生成的腳本,建立新表()

 

 

--USE [AdventureWorks2014]
--GO
 
DECLARE @ori_tab_name NVARCHAR(64);
DECLARE @old_tab_name NVARCHAR(64);
 
SET @ori_tab_name = 'Person.Person';
SET @old_tab_name = RTRIM(@ori_tab_name) + '_old';
 
 
 
 
 
SELECT  'sp_rename ''' + SCHEMA_NAME(schema_id) +'.' + name + ''' ,'''
        + name + '_old'';' + CHAR(10) + 'GO'
FROM    sys.key_constraints
WHERE   parent_object_id = OBJECT_ID(@ori_tab_name);
 
 
SELECT  'sp_rename ''' + SCHEMA_NAME(schema_id) +'.' + name + ''', ''' 
        + name + '_old'';' + CHAR(10) + 'GO'
FROM    sys.default_constraints
WHERE   parent_object_id = OBJECT_ID(@ori_tab_name);
 
 
SELECT 'sp_rename ''' +  SCHEMA_NAME(schema_id) +'.' + name + ''', ''' 
        + name + '_old'';' + CHAR(10) + 'GO'
FROM sys.foreign_keys
WHERE parent_object_id =OBJECT_ID(@ori_tab_name);
 
 
SELECT 'sp_rename '''  + SCHEMA_NAME(schema_id) + '.' + name +''', ''' 
        + name + '_old'';'  + CHAR(10) + 'GO'
FROM sys.check_constraints
WHERE parent_object_id =OBJECT_ID(@ori_tab_name);
 
 
SELECT  'sp_rename ''' +SCHEMA_NAME(schema_id) + '.' +  name + ''', ''' + name + '_old'';'
FROM    sys.tables
WHERE   object_id = OBJECT_ID(@ori_tab_name);

 

 

 

注意:有外鍵約束指向這個表的,還須要額外調整。

 

 

 

INSERT  INTO Person.Person
        ( BusinessEntityID ,
          PersonType ,
          NameStyle ,
          Title ,
          FirstName ,
          MiddleName ,
          LastName ,
          Suffix ,
          EmailPromotion ,
          AdditionalContactInfo ,
          Demographics ,
          rowguid ,
          ModifiedDate
        )
        SELECT  BusinessEntityID ,
                PersonType ,
                NameStyle ,
                Title ,
                FirstName ,
                MiddleName ,
                LastName ,
                Suffix ,
                EmailPromotion ,
                AdditionalContactInfo ,
                Demographics ,
                rowguid ,
                ModifiedDate
        FROM    Person.Person_old;
 
sp_spaceused 'Person.Person';
GO
sp_spaceused 'Person.Person_old';
GO
 
TRUNCATE TABLE Person.Person_old;
GO
DROP TABLE Person.Person_old;
GO

 

 

若是遇到有自增字段,還必須考慮插入自增字段相關值。 總的來講,這樣轉移文件組是一個至關麻煩的事情。對於堆表,這裏也沒啥好介紹的。沒法是細節問題須要注意。轉移文件組倒沒有什麼技術含量。還有一個因素就是這樣的操做會影響業務。

 

 

 

SET IDENTITY_INSERT [dbo].[YourTableName] ON;

GO

INSERT INTO [dbo].[YourTableName](............)

SELECT .............

GO

SET IDENTITY_INSERT [dbo].[YourTableName] OFF;

GO

 

 

 

 

 

分區表   

 

對於分區表而言,也能夠經過從新建立彙集索引和非彙集索引來移動數據。另外,就是從新建立該表,轉移數據。這個大同小異。固然,分區表還有切換分區(Switch Partition)這個機制來轉移數據。

 

 

 

 

刪除文件和文件組

 

刪除文件前,必須確保文件爲空,不然就會報The file 'xxxx' cannot be removed because it is not empty.",因此,首先必須轉移文件當中的對象,而後收縮文件,最後刪除文件。

 

DBCC SHRINKFILE (FileName, EMPTYFILE);

 

USE [AdventureWorks2014]

GO

ALTER DATABASE [AdventureWorks2014]  REMOVE FILE [AdventureWorks2014_DATA_01]

GO

 

 

正常狀況下,刪除文件組對應的文件後,就能夠刪除文件組。

 

ALTER DATABASE [AdventureWorks2014] REMOVE FILEGROUP [DB_Data_Groups]

GO

 

可是若是存在分區表,你可能沒法刪除文件組。由於還有幾個東西依賴文件組,一是分區方案,二是使用該分區方案的分區表。

     

因此要刪除分區方案才能刪除文件組。但要刪除分區方案以前要先更改依賴它的分區表,使其不依賴它。 這個主要是更改分區表的分區列,使其不使用分區方案,若是實在不會更改,在表裏數據已經備份的前提下,能夠直接刪除表來解決。  而後再刪除分區表方案,最後就能夠直接刪除文件組了。

 

 

1、修改分區表,使其不依賴分區方案。

 

2、刪除分區方案(依賴要刪除的文件組)。

 

DROP PARTITION SCHEME [PART_FUNC_SCHEME_NAME]

 

3、直接刪除文件組。

 

ALTER DATABASE [DataBaseName] REMOVE FILEGROUP [xxxx]

 

 

參考資料:

 

https://www.sqlskills.com/blogs/paul/files-and-filegroups-survey-results/

https://docs.microsoft.com/zh-cn/sql/relational-databases/databases/database-files-and-filegroups?view=sql-server-2017

http://www.cnblogs.com/CareySon/archive/2011/12/26/2301597.html

相關文章
相關標籤/搜索