為什麼 dbcc 的收縮數據庫和收縮文件不起作用?
好,我知道了。縮小數據庫是錯誤的。你討厭它。但讓我解釋一下。
我有一個 1TB P1 Azure SQL 數據庫正在生產中,有大約 50 個表,其中大約 5 個是 JSON 容器。這是最初的設計,我很快意識到它的局限性,所以現在我正在將這些 JSON 的儲存解除安裝到更合適的 Azure 儲存帳戶。
這個過程需要時間(JSON 用於不同的業務流程,我一次遷移一個),所以我目前正在刪除成功遷移後的行範圍。不過,我不能截斷或刪除整個表。
在遷移了許多業務流程之後,我現在只剩下 868.64 GB 的分配空間和 390.82 GB 的已用空間。當然,我想將儲存大小降低到 400GB 層以降低成本,但是當我嘗試從 Azure 門戶執行此操作時,我收到以下錯誤消息:
數據庫的儲存大小不能小於目前分配的大小。為了減小數據庫大小,數據庫首先需要通過執行來回收未使用的空間
DBCC SHRINKDATABASE (<db_name>)
。請注意,此操作可能會在執行時影響性能,並且可能需要幾個小時才能完成。好吧,夠公平的。所以我繼續執行命令(當然,使用正確的數據庫名稱),幾個小時並成功執行後,情況完全一樣。沒有空間回收。
在此之後,我進行了以下嘗試:
- 也許我必須強制重組+截斷,所以我執行
dbcc shrinkdatabase(<db_name>, notruncate)
後跟dbcc shrinkdatabase(<db_name>, truncateonly)
:沒有結果。- 也許我必須縮小單個文件,所以我執行
dbcc shrinkfile(<file_name>)
: 還是一樣。- 也許我必須將文件縮小到一個特定的值,所以我再次執行了 `dbcc shrinkfile(<file_name>, <free_space_on_file_in_mb>): ,沒有運氣。
這個查詢
with [BaseData] as ( select [DF].[type_desc] as [Type], [DF].[name] as [FileName], [DF].[size] / 131072.0 as [TotalSpaceInGB], [UP].[size] / 131072.0 as [UsedSpaceInGB], ([DF].[size] - [UP].[size]) / 131072.0 as [FreeSpaceInGB], [DF].[max_size] as [MaxSize] from [sys].[database_files] as [DF] cross apply ( select fileproperty([DF].[name], 'spaceused') as [size] ) as [UP] ) select [BD].[Type] as [Type], [BD].[FileName] as [FileName], format([BD].[TotalSpaceInGB], N'N2') as [TotalSpaceInGB], format([BD].[UsedSpaceInGB], N'N2') as [UsedSpaceInGB], format([BD].[FreeSpaceInGB], N'N2') as [FreeSpaceInGB], case [BD].[MaxSize] when 0 then N'Disabled' when -1 then N'Unrestricted' else format(([BD].[MaxSize] / 131072.0), N'N2') end as [MaxSizeInGB] from [BaseData] as [BD] order by [BD].[Type] asc, [BD].[FileName];
總是返回相同的結果:
另外,這個查詢:
with [BaseData] as ( select [TB].[object_id] as [ObjectId], max([PT].[rows]) as [RowCount], count(distinct [IX].[index_id]) as [IndexCount], sum([PS].[used_page_count]) / 131072.0 as [UsedSpaceInGB], sum([PS].[reserved_page_count]) / 131072.0 as [ReservedSpaceInGB] from [sys].[schemas] as [SC] inner join [sys].[tables] as [TB] on [SC].[schema_id] = [TB].[schema_id] inner join [sys].[indexes] as [IX] on [TB].[object_id] = [IX].[object_id] inner join [sys].[partitions] as [PT] on [TB].[object_id] = [PT].[object_id] and [IX].[index_id] = [PT].[index_id] left join [sys].[dm_db_index_usage_stats] as [IS] on [TB].[object_id] = [IS].[object_id] and [IX].[index_id] = [IS].[index_id] left join [sys].[dm_db_partition_stats] as [PS] on [PT].[partition_id] = [PS].[partition_id] and [IX].[index_id] = [PS].[index_id] and [TB].[object_id] = [PS].[object_id] group by [TB].[object_id] ) select top 5 [BD].[ObjectId] as [ObjectId], [BD].[RowCount] as [RowCount], [BD].[IndexCount] as [IndexCount], format([BD].[UsedSpaceInGB], N'N2') as [UsedSpaceInGB], format([BD].[ReservedSpaceInGB], N'N2') as [ReservedSpaceInGB] from [BaseData] as [BD] order by [BD].[ReservedSpaceInGB] desc;
清楚地表明表格並沒有佔用過多的空間:
我還做了以下考慮:
- 我遇到過這篇文章,它解釋了使用文件組的技巧,但據我所知,在 Azure SQL 數據庫上管理這些是不可能的。
- 這個問題可能與我刪除了很多 LOB 的事實有關。我找到了
dbcc forceghostcleanup (<db_id>, 'visit_all_pages')
命令,但我猶豫要不要嘗試。- 為了試驗 dbcc 的命令,我從備份中創建了數據庫的複製。我認為這排除了與從加速數據庫恢復的版本儲存中保留行版本的活動事務相關的任何可能的問題。
- 理想情況下,我想盡可能避免(作為最後手段)複製數據並刪除原始表或類似的事情的過程。
數據庫中的大多數表都是行儲存聚集索引,除了 6.63GB 的表,它是列儲存聚集索引,還有 7 個堆都在 40MB 標記以下,無論是分配的還是使用的。所有被刪除的表都屬於第一類,並且它們沒有任何非聚集索引。
我剛試過’DBCC UPDATEUSAGE
, but it doesn't seem to change anything;
sp_spaceused`返回相同的值。你有什麼見解嗎?
我已經通過在
ALTER INDEX ALL ON ... REBUILD
我所有的表上執行然後執行來解決了這個問題DBCC SHRINKDATABASE
。我已經在我的部落格上的一篇文章中詳細介紹了所有故障排除,請點擊此處。
請嘗試
ALTER INDEX ... REORGANIZE WITH (LOB_COMPACTION = ON)
,然後再縮小。順便說一句,Azure SQL DB 的收縮文件文章最近已更新,其中一些可能是相關的,即同時收縮多個文件並逐步收縮。