SQL Server在AlwaysOn中使用內存表的“踩坑”記錄
前言
最近因為線上alwayson環(huán)境的一個數據庫上使用內存表。經過大概一個星期監(jiān)控程序發(fā)現了一個非常嚴重問題這個數據庫的日志文件不會截斷,已用空間一直在增加(存在定時的每個小時的日志備份),同時內存表數據庫文件也無法刪除,下面就介紹一下后面我的處理過程,話不多說了,來一起看看詳細的介紹吧。
數據庫:SQL Server2014 Enterprise Edition (64-bit)
刪除文件
使用一個單獨非alwayson環(huán)境的數據庫測試。
一、創(chuàng)建內存表
---創(chuàng)建內存表文件組 ALTER DATABASE [test] ADD FILEGROUP [test_ag] CONTAINS MEMORY_OPTIMIZED_DATA GO ----創(chuàng)建內存表數據庫文件 ALTER DATABASE [test] ADD FILE ( NAME = 'test_memory', FILENAME ='D:\database\memory' ) TO FILEGROUP [test_ag]; GO
二、刪除內存表數據庫文件
USE [test] GO ALTER DATABASE [test] REMOVE FILE [test_memory] GO
備注:此時還未創(chuàng)建表,創(chuàng)建完后數據庫文件執(zhí)行刪除就無法刪除,接下來試試在線文檔的刪除方法方法
三、官方相關的刪除方法
即使已使用“DBCC SHRINKFILE”操作清空 FILESTREAM 容器,但出于各種系統(tǒng)維護原因,數據庫可能仍然需要保留對已刪除文件的引用。 sp_filestream_force_garbage_collection (TRANSACT-SQL)將運行 FILESTREAM 垃圾回收器刪除這些文件時,則可以安全進行這些操作。 除非 FILESTREAM 垃圾回收器已從 FILESTREAM 容器中刪除所有文件,否則 ALTER DATABASEREMOVE FILE 操作將無法刪除 FILESTREAM 容器并返回錯誤。 建議使用以下過程刪除 FILESTREAM 容器。
1.運行DBCC SHRINKFILE (TRANSACT-SQL)帶有 EMPTYFILE 選項以將此容器的活動內容移動到其他容器
USE test; GO -- Create a data file and assume it contains data. ALTER DATABASE test ADD FILE ( NAME = Test1data, FILENAME = 'D:\database\t1data.ndf', SIZE = 5MB ); GO -- Empty the data file. DBCC SHRINKFILE (test_memory, EMPTYFILE); GO
2.確保已在 FULL 或 BULK_LOGGED 恢復模型中執(zhí)行日志備份。
3.確保復制日志讀取器作業(yè)已運行(如果相關)。
通過log_reuse_wait_desc的狀態(tài)可以看到當前數據庫已經無需日志備份,當然我已經執(zhí)行過日志備份。
4.運行sp_filestream_force_garbage_collection (TRANSACT-SQL)強制垃圾回收器刪除不再需要此容器中的任何文件
USE [test] GO EXEC sp_filestream_force_garbage_collection @dbname = N'test' @filename = N' test_memory ';
5.執(zhí)行帶有 REMOVE FILE 選項的 ALTER DATABASE,以刪除此容器。
USE [test] GO ALTER DATABASE [test] REMOVE FILE [test_memory] GO
還是無法刪除?。。?/p>
四、問題分析
一開始是在alwayson的環(huán)境中刪除,提示由于副本的原因無法刪除。后面單獨在一個非alwayson的環(huán)境下的數據庫測試同樣是無法刪除,起初以為是創(chuàng)建了內存表的原因后面測試僅僅創(chuàng)建文件組和文件然后來刪除文件同樣是無法刪除,個人猜測有可能是buffer的緣故;在buffer中一直存在內存表相關的文件存在,通過執(zhí)行DBCC DROPCLEANBUFFERS命令也無法清空buffer中的內存表對象。使盡渾身解數還是無法將它刪除掉,最后只能投降了?。。【€上環(huán)境等不下去;只能使用最不愿使用的生成表結構導出數據的辦法來重建新的數據庫。
生成腳本重建數據庫
創(chuàng)建一個新的數據庫同時保證當前數據庫可用(重命名當前的數據庫,新創(chuàng)建的數據庫使用之前的名稱這樣可以保證應用程序那邊不需要改變),這樣如果出現什么問題也可以及時的切換回來。
步驟如下(在允許停機維護的情況下進行):
1.禁用所有相關作業(yè)
2禁用應用程序登入用戶
同時保證相關進程事務都已完成。
ALTER LOGIN [test] DISABLE GO USE [master] GO ALTER DATABASE [test] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;--將數據庫設置成單用戶并回滾當前連接 USE [test];---保持連接操作,防止其它用戶此時進行連接 GO
3.執(zhí)行checkpoint刷新所有臟頁
CHECKPOINT ---返回當前buffer中每個數據庫所占的buffer大小和buffer中臟頁的大小 WITH CTE1 AS ( SELECT COUNT(*) * 8 / 1024 AS dirty_cached_size_MB , COUNT(*) AS dirty_pages, CASE database_id WHEN 32767 THEN 'ResourceDb' ELSE DB_NAME(database_id) END AS database_name FROM sys.dm_os_buffer_descriptors WHERE is_modified = 1 GROUP BY DB_NAME(database_id),database_id ), CET2 AS ( SELECT COUNT(*) * 8 / 1024 AS cached_size_MB , COUNT(*) AS pages, CASE database_id WHEN 32767 THEN 'ResourceDb' ELSE DB_NAME(database_id) END AS database_name FROM sys.dm_os_buffer_descriptors GROUP BY DB_NAME(database_id),database_id ) SELECT CET2.database_name, CET2.cached_size_MB, --CET2.pages, CTE1.dirty_cached_size_MB --CTE1.dirty_pages FROM CTE1 INNER JOIN CET2 ON CTE1.database_name = CET2.database_name ---將數據庫選項改成多用戶訪問 ALTER DATABASE [test] SET MULTI_USER;
4.生成數據庫腳本
5.重命名舊的數據庫
注意:如果數據庫是在alwayson中,需要先從可用性數據庫中刪除,否則無法重命名數據庫。
/*
1.斷開數據庫所有連接同時禁止新的連接進來
2.比如禁止登入用戶、將實例設為單用戶模式等。
*/
----1.設置數據庫脫機
USE [master]
ALTER DATABASE [test] SET OFFLINE WITH ROLLBACK IMMEDIATE;
----2.手動修改數據庫物理文件名,例如將test.mdf改成test_old.mdf
----3.語句修改
USE [master]
ALTER DATABASE [test]
MODIFY FILE (NAME = test, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test_old.mdf');
GO
ALTER DATABASE [test]
MODIFY FILE (NAME = test_log, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test_old_log.ldf');
GO
---4.設置數據庫在線
USE [master]
ALTER DATABASE [test] SET ONLINE
----5.修改數據庫邏輯文件名
USE [test]
GO
ALTER DATABASE [test] MODIFY FILE (NAME=N'test', NEWNAME=N'test_old')
GO
USE [test]
GO
ALTER DATABASE [test] MODIFY FILE (NAME=N'test_log', NEWNAME=N'test_old_log')
GO
----6.重命名數據庫
USE [master]
EXEC sp_renamedb N'test', N'test_old';
----7.查詢
SELECT *
FROM sys.master_files
WHERE database_id = DB_ID('test_old');
6.創(chuàng)建新的數據庫同時導入腳本到新的數據庫
如果同時導出表結構和數據在ssms工具中執(zhí)行可能會因為腳本過大無法執(zhí)行,可以使用sqlcmd工具執(zhí)行腳本導入,具體方法可以百度一下。當然還有其他方法就是只導出表結構然后通過“導出數據\導入數據”的方法同步數據。
注意:如果使用“導出數據\導入數據”的方法同步數據,注意勾選“啟用標示插入”
7.其它
1.如果存在alwayson記得將新的數據庫加入到可用性數據庫組中。
2.將新的數據庫加入到備份作業(yè)中。
3.對比新舊兩個數據庫的表數量是否相同。
4.配置登入用戶新的數據庫權限。
總結
內存表是2014新引入的功能所以對于新功能的第一個版本使用要比較慎重,特別是在線上環(huán)境。雖然在上線之前做過測試,但是顯然備份這塊的測試往往比較容易被忽略因為沒有線上的這種環(huán)境。好在是這次影響的是一個新上的項目數據量和并發(fā)都很小且允許節(jié)假日停機維護;如果是非常大的系統(tǒng)對于需要導入導出數據肯定是非常頭疼的事情關鍵還得看允許停機的時長。因為自己在生產環(huán)境踩了坑,寫這篇文章希望后面的人可以避免踩坑。
備注:內存表在2014版本的alwayson中無法同步到輔助副本,這就導致了它的作用大打折扣,2016版本可以同步到輔助副本,建議有條件的直接上2016。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對我們的支持。
上一篇:SQL Server 2016 Alwayson新增功能圖文詳解
欄 目:MsSql
下一篇:mybatis collection 多條件查詢的實現方法
本文標題:SQL Server在AlwaysOn中使用內存表的“踩坑”記錄
本文地址:http://www.jygsgssxh.com/a1/MsSql/10427.html
您可能感興趣的文章
- 01-10SQLServer存儲過程實現單條件分頁
- 01-10SQL Server 2012降級至2008R2的方法
- 01-10SQLServer中防止并發(fā)插入重復數據的方法詳解
- 01-10SQL Server數據庫定時自動備份
- 01-10SQL Server性能調優(yōu)之緩存
- 01-10實現SQL Server 原生數據從XML生成JSON數據的實例代碼
- 01-10Sql Server 死鎖的監(jiān)控分析解決思路
- 01-10SqlServer 在事務中獲得自增ID的實例代碼
- 01-10SqlServer快速檢索某個字段在哪些存儲過程中(sql 語句)
- 01-10SQLServer性能優(yōu)化--間接實現函數索引或者Hash索引


閱讀排行
本欄相關
- 01-10SQLServer存儲過程實現單條件分頁
- 01-10SQLServer中防止并發(fā)插入重復數據的方
- 01-10SQL Server 2012降級至2008R2的方法
- 01-10SQL Server性能調優(yōu)之緩存
- 01-10SQL Server數據庫定時自動備份
- 01-10Sql Server 死鎖的監(jiān)控分析解決思路
- 01-10實現SQL Server 原生數據從XML生成JSON數
- 01-10SqlServer快速檢索某個字段在哪些存儲
- 01-10SqlServer 在事務中獲得自增ID的實例代
- 01-10SQLServer性能優(yōu)化--間接實現函數索引或
隨機閱讀
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢)副欄目數量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 01-10C#中split用法實例總結
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-11ajax實現頁面的局部加載


