好,我知道了。缩小数据库是错误的。你讨厌它。但让我解释一下。
我有一个 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];
总是返回相同的结果:
类型 | 文件名 | 总空间InGB | 已用空间InGB | 自由空间InGB | 最大尺寸 |
---|---|---|---|---|---|
文件流 | XTP | 2.03 | 无效的 | 无效的 | 不受限制 |
日志 | 日志 | 1.63 | 0.60 | 1.03 | 250.00 |
行 | 数据_0 | 509.47 | 231.58 | 277.89 | 512.00 |
行 | dfa_data_3 | 359.17 | 159.27 | 199.91 | 512.00 |
另外,这个查询:
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;
清楚地表明表格并没有占用过多的空间:
对象标识 | 行数 | 索引计数 | 已用空间InGB | ReservedSpaceInGB |
---|---|---|---|---|
108579475 | 2892280 | 1 | 254.34 | 254.37 |
1952114095 | 834306760 | 1 | 79.73 | 79.74 |
418204640 | 20233590 | 1 | 23.52 | 23.53 |
1599396817 | 6346104 | 1 | 6.63 | 6.74 |
1939590048 | 596471 | 1 | 4.75 | 4.75 |
我还做了以下考虑:
- 我遇到过这篇文章,它解释了使用文件组的技巧,但据我所知,在 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 的收缩文档文章最近已更新,其中一些可能是相关的,即同时收缩多个文件并逐步收缩。