文章出處

SQLSERVER將數據移到另一個文件組之后清空文件組并刪除文件組

之前寫過一篇文章:SQLSERVER將一個文件組的數據移動到另一個文件組


每個物理文件(數據文件)對應一個文件組的情況(一對一)

如果我把數據移到另一個文件組了,不想要這個已經清空的文件組了,怎麼做?

腳本跟之前那篇文章差不多

 1 USE master
 2 GO
 3 
 4 
 5 IF EXISTS(SELECT * FROM sys.[databases] WHERE [database_id]=DB_ID('Test'))
 6 DROP DATABASE [Test]
 7 
 8 --1.創建數據庫
 9 CREATE DATABASE [Test]
10 GO
11 
12 USE [Test]
13 GO
14 
15 
16 --2.創建文件組
17 ALTER DATABASE [Test]
18 ADD FILEGROUP [FG_Test_Id_01]
19 
20 ALTER DATABASE [Test]
21 ADD FILEGROUP [FG_Test_Id_02]
22 
23 
24 
25 --3.創建文件
26 ALTER DATABASE [Test]
27 ADD FILE
28 (NAME = N'FG_TestUnique_Id_01_data',FILENAME = N'E:\FG_TestUnique_Id_01_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB )
29 TO FILEGROUP [FG_Test_Id_01];
30 
31 ALTER DATABASE [Test]
32 ADD FILE
33 (NAME = N'FG_TestUnique_Id_02_data',FILENAME = N'E:\FG_TestUnique_Id_02_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB )
34 TO FILEGROUP [FG_Test_Id_02];
35 
36 
37 --4.創建表,這個表的數據存放在[FG_Test_Id_01] 文件組上
38 CREATE TABLE aa(id INT ,cname NVARCHAR(4000)) ON [FG_Test_Id_01] 
39 GO
40 
41 
42 --5.插入數據
43 INSERT INTO [dbo].[aa]
44 SELECT 1,REPLICATE('s',3000)
45 GO 500
46 
47 
48 --6.查詢數據
49 SELECT * FROM [dbo].[aa]
50 
51 
52 --7.創建聚集索引在[FG_Test_Id_02]文件組上
53 CREATE CLUSTERED INDEX PK_ID ON [dbo].[aa]([id]) WITH(ONLINE=ON) ON [FG_Test_Id_02]
54 GO
55 
56 
57 --8.我們查看一下文件組的邏輯文件名
58 EXEC [sys].[sp_helpdb] @dbname = TEST -- sysname
59 
65 
66 --9.移除FG_Test_Id_01文件組
67 ALTER DATABASE TEST
68 REMOVE FILE FG_TestUnique_Id_01_data

當你移動數據到文件組[FG_Test_Id_02]上時,這時候文件組[FG_Test_Id_01]里面已經沒有數據了
使用下面的腳本查看

 1 --數據庫文件、大小和已經使用空間
 2 USE [Test]  --要查看的當前數據庫的使用空間,自動增長大小,數據庫文件位置
 3 GO
 4 set nocount on
 5 create table #Data(
 6       FileID int NOT NULL,
 7       [FileGroupId] int NOT NULL,
 8       TotalExtents int NOT NULL,
 9       UsedExtents int NOT NULL,
10       [FileName] sysname NOT NULL,
11       [FilePath] nvarchar(MAX) NOT NULL,
12       [FileGroup] varchar(MAX) NULL)
13 
14 create table #Results(
15       db sysname NULL ,
16       FileType varchar(4) NOT NULL,
17       [FileGroup] sysname not null,
18       [FileName] sysname NOT NULL,
19       TotalMB numeric(18,2) NOT NULL,
20       UsedMB numeric(18,2) NOT NULL,
21       PctUsed numeric(18,2) NULL,
22       FilePath nvarchar(MAX) NULL,
23       FileID int null)
24 
25 create table #Log(
26       db sysname NOT NULL,
27       LogSize numeric(18,5) NOT NULL,
28       LogUsed numeric(18,5) NOT NULL,
29       Status int NOT NULL,
30       [FilePath] nvarchar(MAX) NULL)
31 
32 INSERT #Data (FileID, [FileGroupId], TotalExtents, UsedExtents, [FileName], [FilePath])
33 EXEC ('DBCC showfilestats WITH NO_INFOMSGS')
34 
35 update #Data
36 set #Data.FileGroup = sysfilegroups.groupname
37 from #Data, sysfilegroups
38 where #Data.FileGroupId = sysfilegroups.groupid
39 
40 INSERT INTO #Results (db, [FileGroup], FileType, [FileName], TotalMB, UsedMB, PctUsed, FilePath, FileID)
41 SELECT DB_NAME() db,
42             [FileGroup],
43             'Data' FileType,
44             [FileName],
45             TotalExtents * 64./1024. TotalMB,
46             UsedExtents *64./1024 UsedMB,
47             UsedExtents*100. /TotalExtents  UsedPct,
48             [FilePath],
49             FileID
50 FROM #Data
51 order BY --1,2
52 DB_NAME(), [FileGroup]
53 
54 insert #Log (db,LogSize,LogUsed,Status)
55 exec('dbcc sqlperf(logspace) WITH NO_INFOMSGS ')
56 
57 insert #Results(db, [FileGroup], FileType, [FileName],  TotalMB,UsedMB, PctUsed, FilePath, FileID)
58 select DB_NAME() db,
59             'Log' [FileGroup],
60             'Log' FileType,
61             s.[name] [FileName],
62             s.Size/128. as LogSize ,
63             FILEPROPERTY(s.name,'spaceused')/8.00 /16.00 As LogUsedSpace,
64             ((FILEPROPERTY(s.name,'spaceused')/8.00 /16.00)*100)/(s.Size/128.) UsedPct,
65             s.FileName FilePath,
66             s.FileID FileID
67       from #Log l , master.dbo.sysaltfiles f , dbo.sysfiles s
68       where f.dbid = DB_ID()
69       and (s.status & 0x40) <> 0
70       and s.FileID = f.FileID
71       and l.db = DB_NAME()
72 
73 SELECT r.db AS "Database",
74 r.FileType AS "File type",
75 CASE
76      WHEN r.FileGroup = 'Log' Then 'N/A'
77      ELSE r.FileGroup
78 END "File group",
79 r.FileName AS "Logical file name",
80 r.TotalMB AS "Total size (MB)",
81 r.UsedMB AS "Used (MB)",
82 r.PctUsed AS "Used (%)",
83 r.FilePath AS "File name",
84 r.FileID AS "File ID",
85 CASE WHEN s.maxsize = -1 THEN null
86     ELSE CONVERT(decimal(18,2), s.maxsize /128.)
87 END "Max. size (MB)",
88 CONVERT(decimal(18,2), s.growth /128.) "Autogrowth increment (MB)"
89 FROM #Results r
90 INNER JOIN dbo.sysfiles s
91 ON r.FileID = s.FileID
92 ORDER BY 1,2,3,4,5
93 
94 DROP TABLE #Data
95 DROP TABLE #Results
96 DROP TABLE #Log
View Code

 

使用下面的SQL語句移除文件組[FG_Test_Id_01]就可以了

 
5 --9.移除FG_Test_Id_01文件組
6 ALTER DATABASE TEST
7 REMOVE FILE FG_TestUnique_Id_01_data

此時就只剩下主文件組和[FG_Test_Id_02]文件組了

注意:如果不使用聚集索引來移動文件組[FG_Test_Id_01]上的數據到文件組[FG_Test_Id_02]

1 --4.創建表,這個表的數據存放在[FG_Test_Id_01] 文件組上
2 CREATE TABLE aa(id INT ,cname NVARCHAR(4000)) ON [FG_Test_Id_01] 
3 GO

直接使用下面SQL語句來收縮文件會報錯

1 -收縮一下FG_Test_Id_01文件組文件
2 DBCC SHRINKFILE(FG_TestUnique_Id_01_data,EMPTYFILE)

報錯內容

1 DBCC SHRINKFILE: 無法移動堆頁 3:5152 消息 2555,級別 16,狀態 1,第 13 無法將文件 "FG_TestUnique_Id_01_data" 的所有內容移到其他位置,以完成清空文件操作。
4 語句已終止。
5 DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。
6 消息 1105,級別 17,狀態 2,第 17 無法為數據庫 'Test' 中的對象 'dbo.aa' 分配空間,因為 'FG_Test_Id_01' 文件組已滿。請刪除不需要的文件、刪除文件組中的對象、將其他文件添加到文件組或為文件組中的現有文件啟用自動增長,以便增加可用磁盤空間。

因為文件組[FG_Test_Id_01]里還有數據,不能清空


兩個物理文件(數據文件)對應一個文件組的情況(一對多)

上面的情況是每個物理文件(數據文件)對應一個文件組的情況

下面這種情況是兩個物理文件(數據文件)對于一個文件組的情況

一對一的情況使用聚集索引里移動數據,而一對一的情況使用DBCC SHRINKFILE

創建數據庫

test1和test2這兩個數據文件歸屬于主文件組primary,而數據文件test1最大大小為6MB初始大小為5MB

test2數據文件最大大小沒有限制

使用下面腳本添加數據到主文件組

 1 --1.創建表,這個表的數據存放在主文件組上
 2 CREATE TABLE aa(id INT ,cname NVARCHAR(4000)) 
 3 GO
 4 
 5 
 6 --2.插入數據
 7 INSERT INTO [dbo].[aa]
 8 SELECT 1,REPLICATE('s',3000)
 9 GO 600
10 
11 
12 --3.查詢數據
13 SELECT * FROM [dbo].[aa]
14 
15 
16 
17 
18 --4.我們查看一下文件組的邏輯文件名
19 EXEC [sys].[sp_helpdb] @dbname = TEST1
20  -- sysname
21 SELECT  DB_NAME(database_id) AS DatabaseName ,
22         Name AS Logical_Name ,
23         Physical_Name ,
24         ( size * 8 ) / 1024 SizeMB
25 FROM    sys.master_files
26 WHERE   DB_NAME(database_id) = 'Test1'

因為第一個數據文件的最大大小限制,所以有一部分數據插入到了test2.ndf

 

 

現在修改test1數據文件的最大大小限制為20MB

相關SQL

1 ALTER DATABASE [Test1] MODIFY FILE(name='Test1',SIZE=5MB, filegrowth=1MB, MAXSIZE=20MB)
View Code

 

執行下面的SQL語句

1 --5.收縮文件
2 DBCC SHRINKFILE(test2,EMPTYFILE)
3 
4 
5 --6.移除test2數據文件test2.ndf
6 ALTER DATABASE TEST1
7 REMOVE FILE test2


在執行第五條語句的時候,執行下面腳本

 1 --數據庫文件、大小和已經使用空間
 2 USE [Test1]  --要查看的當前數據庫的使用空間,自動增長大小,數據庫文件位置
 3 GO
 4 set nocount on
 5 create table #Data(
 6       FileID int NOT NULL,
 7       [FileGroupId] int NOT NULL,
 8       TotalExtents int NOT NULL,
 9       UsedExtents int NOT NULL,
10       [FileName] sysname NOT NULL,
11       [FilePath] nvarchar(MAX) NOT NULL,
12       [FileGroup] varchar(MAX) NULL)
13 
14 create table #Results(
15       db sysname NULL ,
16       FileType varchar(4) NOT NULL,
17       [FileGroup] sysname not null,
18       [FileName] sysname NOT NULL,
19       TotalMB numeric(18,2) NOT NULL,
20       UsedMB numeric(18,2) NOT NULL,
21       PctUsed numeric(18,2) NULL,
22       FilePath nvarchar(MAX) NULL,
23       FileID int null)
24 
25 create table #Log(
26       db sysname NOT NULL,
27       LogSize numeric(18,5) NOT NULL,
28       LogUsed numeric(18,5) NOT NULL,
29       Status int NOT NULL,
30       [FilePath] nvarchar(MAX) NULL)
31 
32 INSERT #Data (FileID, [FileGroupId], TotalExtents, UsedExtents, [FileName], [FilePath])
33 EXEC ('DBCC showfilestats WITH NO_INFOMSGS')
34 
35 update #Data
36 set #Data.FileGroup = sysfilegroups.groupname
37 from #Data, sysfilegroups
38 where #Data.FileGroupId = sysfilegroups.groupid
39 
40 INSERT INTO #Results (db, [FileGroup], FileType, [FileName], TotalMB, UsedMB, PctUsed, FilePath, FileID)
41 SELECT DB_NAME() db,
42             [FileGroup],
43             'Data' FileType,
44             [FileName],
45             TotalExtents * 64./1024. TotalMB,
46             UsedExtents *64./1024 UsedMB,
47             UsedExtents*100. /TotalExtents  UsedPct,
48             [FilePath],
49             FileID
50 FROM #Data
51 order BY --1,2
52 DB_NAME(), [FileGroup]
53 
54 insert #Log (db,LogSize,LogUsed,Status)
55 exec('dbcc sqlperf(logspace) WITH NO_INFOMSGS ')
56 
57 insert #Results(db, [FileGroup], FileType, [FileName],  TotalMB,UsedMB, PctUsed, FilePath, FileID)
58 select DB_NAME() db,
59             'Log' [FileGroup],
60             'Log' FileType,
61             s.[name] [FileName],
62             s.Size/128. as LogSize ,
63             FILEPROPERTY(s.name,'spaceused')/8.00 /16.00 As LogUsedSpace,
64             ((FILEPROPERTY(s.name,'spaceused')/8.00 /16.00)*100)/(s.Size/128.) UsedPct,
65             s.FileName FilePath,
66             s.FileID FileID
67       from #Log l , master.dbo.sysaltfiles f , dbo.sysfiles s
68       where f.dbid = DB_ID()
69       and (s.status & 0x40) <> 0
70       and s.FileID = f.FileID
71       and l.db = DB_NAME()
72 
73 SELECT r.db AS "Database",
74 r.FileType AS "File type",
75 CASE
76      WHEN r.FileGroup = 'Log' Then 'N/A'
77      ELSE r.FileGroup
78 END "File group",
79 r.FileName AS "Logical file name",
80 r.TotalMB AS "Total size (MB)",
81 r.UsedMB AS "Used (MB)",
82 r.PctUsed AS "Used (%)",
83 r.FilePath AS "File name",
84 r.FileID AS "File ID",
85 CASE WHEN s.maxsize = -1 THEN null
86     ELSE CONVERT(decimal(18,2), s.maxsize /128.)
87 END "Max. size (MB)",
88 CONVERT(decimal(18,2), s.growth /128.) "Autogrowth increment (MB)"
89 FROM #Results r
90 INNER JOIN dbo.sysfiles s
91 ON r.FileID = s.FileID
92 ORDER BY 1,2,3,4,5
93 
94 DROP TABLE #Data
95 DROP TABLE #Results
96 DROP TABLE #Log
View Code

你會發現

數據都移動到了test1.mdf里去了

執行第六條SQL語句,刪除test2.ndf文件

數據沒有丟失

這里關鍵在于EMPTYFILE參數 :DBCC SHRINKFILE(test2,EMPTYFILE)


總結

這里要根據是一對多還是一對一來選擇移動數據的方法

如果是一對多:使用DBCC SHRINKFILE(要移動數據的數據文件,EMPTYFILE)

如果是一對一:創建聚集索引

 

參考文章:     [SQL]透過 DBCC SHRINKFILE([要清空的File], EMPTYFILE) 來將資料移到另一個資料檔之中

大家可以做一下實驗

對于同一個文件組里的多個數據文件(不一定是主文件組),

比如有有個文件組叫[FG_Test_01],里面有兩個數據文件test3.ndf和test4.ndf

test3.ndf和test4.ndf都有數據

如果我運行DBCC SHRINKFILE(test4,EMPTYFILE),test4.ndf里的數據是否會移動到test3.ndf還是會移動到test1.mdf???

這個實驗留給大家o(∩_∩)o

2014-1-14補充:

這個實驗的測試腳本和結果

 1 USE master
 2 GO
 3 
 4 --DROP DATABASE [Test]
 5 
 6 
 7 IF EXISTS(SELECT * FROM sys.[databases] WHERE [database_id]=DB_ID('Test'))
 8 DROP DATABASE [Test]
 9 
10 --1.創建數據庫
11 CREATE DATABASE [Test]
12 GO
13 
14 USE [Test]
15 GO
16 
17 
18 --2.創建文件組
19 ALTER DATABASE [Test]
20 ADD FILEGROUP [FG_Test_Id_01]
21 
22 
23 
24 
25 
26 --3.創建文件
27 ALTER DATABASE [Test]
28 ADD FILE
29 (NAME = N'FG_TestUnique_Id_01_data',FILENAME = N'E:\FG_TestUnique_Id_01_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB )
30 TO FILEGROUP [FG_Test_Id_01];
31 
32 ALTER DATABASE [Test]
33 ADD FILE
34 (NAME = N'FG_TestUnique_Id_02_data',FILENAME = N'E:\FG_TestUnique_Id_02_data.ndf',SIZE = 1MB, FILEGROWTH = 1MB )
35 TO FILEGROUP [FG_Test_Id_01];
36 
37 
38 
39 
40 
41 --4.創建表,這個表的數據存放在[FG_Test_Id_02] 文件組上
42 CREATE TABLE aa(id INT ,cname NVARCHAR(4000)) ON [FG_Test_Id_01] 
43 GO
44 
45 
46 --5.插入數據
47 INSERT INTO [dbo].[aa]
48 SELECT 1,REPLICATE('s',3000)
49 GO 1000
50 
51 
52 --6.查詢數據
53 SELECT * FROM [dbo].[aa]
54 
55 
56 
57 
58 --7.我們查看一下文件組的邏輯文件名
59 EXEC [sys].[sp_helpdb] @dbname = TEST -- sysname
60 
61 
62 
63 --8.收縮文件
64 DBCC SHRINKFILE(FG_TestUnique_Id_02_data,EMPTYFILE)
65 
66 
67 --9.移除FG_TestUnique_Id_03_data數據文件FG_TestUnique_Id_03_data.ndf
68 ALTER DATABASE TEST
69 REMOVE FILE FG_TestUnique_Id_02_data
70 
71 
72 
73 --10.查詢數據
74 SELECT * FROM [dbo].[aa]
75 SELECT COUNT(*) FROM [dbo].[aa]
View Code

 

 

數據沒有丟失

答案:

FG_TestUnique_Id_02_data.ndf里的數據會移動到FG_TestUnique_Id_01_data.ndf,不會移動到Test.mdf

因為DBCC SHRINKFILE只能在同一文件組內移動數據,而mdf只能屬于主文件組primary

 

如有不對的地方,歡迎大家拍磚o(∩_∩)o


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()