一、背景
在線上系統中,如果我們發現存放數據庫文件的磁盤空間不夠,我們應該怎么辦呢?新買一個硬盤掛載上去可以嘛?(linux下可以直接掛載硬盤進行擴容),但是我們的SQL Server是運行在Windows下的,有什么辦法可以解決這燃眉之急呢?
有兩種方法可以解決上面的問題:第一種就是把數據庫磁盤轉換為【動態磁盤】,新增新的磁盤就可以解決了;第二種就是我今天要講述的,使用SQL Server在其它磁盤(或者邏輯分區)中添加新的文件,添加完成后,SQL Server馬上就能進新的數據了。
上面兩種方法的區別就是,第二種方法的響應速度會更快,而且也更符合一般的應用場景,因為我們一般對磁盤分區的時候會划分幾個邏輯分區,常常會出現某些邏輯分區剩余的空間會比較大,剛剛好用於放置新的文件。
二、知識准備
在講解如何磁盤擴容之前,我先講講一些關於表分區的一些知識,這對理解磁盤擴容很有幫助。
(Figure1:分區邏輯關系圖)
Figure1分區邏輯關系圖解析:
1) 文件組只是一個邏輯上的存在;
2) 一個文件組下面可以包含多個文件;(文件組FG1包含了文件F1和文件F2)
3) 分區方案包括了一個分區函數和一個或者多個文件組;(分區方案Sch1使用了分區函數Fn和文件組FG1和n個其它文件組)
4) 一個分區方案可以被多張表引用;
5) 兩個分區方案可以使用同一個分區函數;(分區方案Sch1與分區方案Sch2使用了同一個分區函數Fn)
在使用SSMS生成創建表的SQL語句的時候,我們經常看到SQL中包含ON [PRIMARY]的字樣,這就說明我們平時創建的表都是創建在主文件組(在沒有指定分區方案的情況下)的,而默認情況下,主文件組中就只包含一個mdf,所以當數據不斷增長的時候,發現mdf文件也會在不斷的增長(考慮文件自動增長設置的值,不是每次進數據都會增長mdf文件的)。
綜上所述:在出現數據庫磁盤空間不夠的情況下,我們在PRIMARY文件組中添加一個ndf文件,這就相當於我們表分區有類似效果(數據分散),區別就是我們沒有使用分區函數規則哪些數據應該存在哪些文件組中。想要了解更多表分區的實戰可以參考:SQL Server 表分區實戰系列(文章索引)
三、測試過程
(一) 模擬磁盤不夠用的情況:
1) 創建一個數據庫,在創建過程中設置ldf文件的初始大小,盡量占用完磁盤空間,mdf文件的初始大小盡量小,方便測試;
2) 插入一定量的數據占用剩余的磁盤,插到一定量的時候就會發生不夠用而報錯;
3) 接下來我們在主文件組PRIMARY中創建一個位於其它邏輯分區的ndf文件;
4) 繼續插入數據,查看數據的插入情況;
(二) 測試腳本及效果圖:
1) 使用下面的SQL查詢Task數據庫的文件與文件組的信息:
--文件與文件組 SELECT df.[name],df.physical_name,df.[size], df.[growth],f.[name] AS [filegroup],f.[is_default] FROM sys.database_files df LEFT JOIN sys.filegroups f ON df.data_space_id = f.data_space_id
(Figure2:文件與文件組)
2) 使用下面的SQL查詢Task數據庫的文件剩余空間的信息:
--當前數據庫,數據文件占用與剩余空間 SELECT DB_NAME() AS DbName, name AS FileName, size/128.0 AS CurrentSizeMB, size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS INT)/128.0 AS FreeSpaceMB FROM sys.database_files;
(Figure3:文件剩余空間)
3) 查看F盤的使用情況:
(Figure4:磁盤信息)
4) 在Task數據庫中執行下面的SQL語句(笛卡爾值):
--生成測試數據 select top 2000000 identity(int, 1,1) as id, 0 as usered into TempA from syscolumns a,syscolumns b
執行上面的SQL,會產生下面的錯誤信息:
消息1101,級別17,狀態12,第2 行
由於文件組'PRIMARY 中的磁盤空間不足,無法為數據庫'Task' 分配新頁。請刪除文件組中的對象、將其他文件添加到文件組或者為文件組中的現有文件啟用自動增長,以便增加必要的空間。
5) 上面我們已經成功模擬了磁盤無法分配空間的環境,現在我們就來創建一個存儲於PRIMARY主文件的ndf文件:
--創建ndf文件 ALTER DATABASE [Task] ADD FILE (NAME = N'Primary_data',FILENAME = N'E:\DataBase\Primary_data.ndf',SIZE = 20MB, FILEGROWTH = 10MB ) TO FILEGROUP [Primary];
6) 再次執行步驟4的SQL,數據已經可以插入了,現在我們來看看效果:
(Figure5:文件與文件組)
(Figure6:文件剩余空間)
Figure5中可以看到在E盤中已經添加新的文件:Primary_data.ndf,數據已經成功插入,並且Primary_data.ndf文件的可用空間減少了(Figure6),說明我們已經成功進行磁盤擴容了。
有一點需要注意,如果你猜想可能還需要在這個數據庫創建未分區的新表或者索引,那么你需要設置一下文件組的默認值選項。
四、知識點
1. SQL Server的文件類型可以分為mdf、ndf、ldf,我們通常創建數據庫的時候一般只創建了mdf和ldf文件。
2. 主要數據文件包含數據庫的啟動信息,並指向數據庫中的其他文件。用戶數據和對象可存儲在此文件中,也可以存儲在次要數據文件中。每個數據庫有一個主要數據文件。主要數據文件的建議文件擴展名是.mdf。
3. 次要數據文件是可選的,由用戶定義並存儲用戶數據。通過將每個文件放在不同的磁盤驅動器上,次要文件可用於將數據分散到多個磁盤上。另外,如果數據庫超過了單個Windows 文件的最大大小,可以使用次要數據文件,這樣數據庫就能繼續增長。次要數據文件的建議文件擴展名是.ndf。
4. 事務日志文件保存用於恢復數據庫的日志信息。每個數據庫必須至少有一個日志文件。事務日志的建議文件擴展名是.ldf。
5. 每個數據庫有一個主要文件組。此文件組包含主要數據文件和未放入其他文件組的所有次要文件。可以創建用戶定義的文件組,用於將數據文件集合起來,以便於管理、數據分配和放置。
6. 如果在數據庫中創建對象時沒有指定對象所屬的文件組,對象將被分配給默認文件組。不管何時,只能將一個文件組指定為默認文件組。默認文件組中的文件必須足夠大,能夠容納未分配給其他文件組的所有新對象。
7. PRIMARY 文件組是默認文件組,除非使用ALTER DATABASE 語句進行了更改。但系統對象和表仍然分配給 PRIMARY 文件組,而不是新的默認文件組。
8. 針對Figure1中描述的:分區方案Sch1(1個分區函數、1個或多個文件組),下面是對這個說法的驗證SQL:
--1.創建分區函數 CREATE PARTITION FUNCTION [Fun_Archive_Id](INT) AS RANGE RIGHT FOR VALUES(200000000) --2.創建分區方案 CREATE PARTITION SCHEME [Sch_Archive_Id] AS PARTITION [Fun_Archive_Id] TO([Primary],[Primary])
9. 針對Figure6中顯示,Task.mdf和Primary_data.ndf都同時出現空間減少的情況?我給了我們什么提示呢?
10. SQL SERVER會根據每個文件設置的初始大小和增長量會自動分配新加入的空間,假設在同一文件組中的文件A設置的大小為文件B的兩倍,新增一個數據占用三頁(Page),則按比例將2頁分配到文件A中,1頁分配到文件B中?
11. 在SQL SERVER 2008之后,還新增了文件流數據文件和全文索引文件?
12. 如果一個表是存在物理上的多個文件中時,則表的數據頁的組織為N(N為具體的幾個文件)個B樹.而不是一個對象為一個B樹?
五、參考文獻