我使用 SQL 服务器数据库。为了减少数据库日志文件,我将数据库的恢复模式设置为简单,然后收缩数据库,但日志文件没有效果。
什么是问题?
我使用 SQL 服务器数据库。为了减少数据库日志文件,我将数据库的恢复模式设置为简单,然后收缩数据库,但日志文件没有效果。
什么是问题?
好,我知道了。缩小数据库是错误的。你讨厌它。但让我解释一下。
我有一个 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>)
: 还是一样。这个查询
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 |
我还做了以下考虑:
dbcc forceghostcleanup (<db_id>, 'visit_all_pages')
命令,但我犹豫要不要尝试。数据库中的大多数表都是行存储聚集索引,除了 6.63GB 的表,它是列存储聚集索引,还有 7 个堆都在 40MB 标记以下,无论是分配的还是使用的。所有被删除的表都属于第一类,并且它们没有任何非聚集索引。
我刚试过'DBCC UPDATEUSAGE , but it doesn't seem to change anything;
sp_spaceused`返回相同的值。
你有什么见解吗?
我在 Azure SQL MI 的数据文件中有一个 600GB 的数据库和 400GB 的可用空间。我打算缩小它并保存存储,但它是用户会话的关键数据库。
有两个计划:
方案 A:一次将数据文件压缩到 210GB。
方案B:每次收缩5GB,逐个执行。
你有什么想法吗?B计划有什么好处?
我从模式中删除了一堆旧数据,包括 BLOB 数据,然后我尝试缩小和压缩所有内容。我设法缩小了所有表(启用行移动,缩小空间紧凑,禁用行移动),除了一个 BLOB 列,它存储在一个单独的段上:
SELECT
segment_name,
SUM(bytes) / 1024 / 1024 / 1024 AS "GB_SIZE"
FROM
dba_segments
WHERE
owner = 'MY_OWNER'
GROUP BY
segment_name
ORDER BY
SUM(bytes) / 1024 / 1024 / 1024 DESC;
有问题的部分:
SEGMENT_NAME GB_SIZE
SYS_LOB0000072887C00005$$ 0,35955810546875
注意:这是一个测试数据库,在产品数据库中,大约是 660 GB。
当我尝试缩小它时,我收到此错误:
ALTER TABLE my_table MODIFY LOB ( my_blob ) ( SHRINK SPACE );
Error starting at line : 1 in command -
alter table my_table modify lob (my_blob) (shrink space)
Error report -
ORA-10635: Invalid segment or tablespace type
10635. 00000 - "Invalid segment or tablespace type"
*Cause: Cannot shrink the segment because it is not in auto segment space
managed tablespace or it is not a data, index or lob segment.
*Action: Check the tablespace and segment type and reissue the statement
细分详情:
SELECT
*
FROM
dba_segments
WHERE
segment_name = 'SYS_LOB0000072887C00005$$';
相关细节:
表空间详细信息:
SELECT
*
FROM
dba_tablespaces
WHERE
tablespace_name = 'MY_DATA';
相关细节:
确切的 Oracle 版本:
Oracle Database 19c 企业版 19.0.0.0.0 版 - 生产
据我所知,一切都是应有的,所以我不确定缺少什么。
我们有一个总大小为 3886 GB 的数据库。其中 778 GB 是免费的。因此,总共存在 3108 GB 的数据。
其中 2458 GB 是“LOB 数据”,400 GB 是“常规”。
由于数据库托管在 AWS 上,因此为了节省成本,我们正在尝试缩小数据文件以释放空间。儿子为了容纳数据,我们已经有两个 2 TB 的驱动器,而且都快满了,我的经理不想创建另一个驱动器并将新文件放在那里。
但是,当我们尝试一次缩小 2 GB 时,会花费很多时间(看到 dbcc lobcompact 在 sp_who2 中运行),而且我们有时也会看到阻塞。谷歌搜索后,我在下面看到 Paul S. Randal 的博客文章,他还指出 LOB 数据使收缩变慢。
https://www.sqlskills.com/blogs/paul/why-lob-data-makes-shrink-run-slooooowly-t-sql-tuesday-006/
我担心的是:
在这种情况下,有什么办法可以让收缩更快,或者根本没有办法?
当涉及到云时,其他人在这种情况下正在做什么,他们想通过减少存储大小来节省一些成本?
我的理解是正确的,即缩小文件可以以某种方式节省组织成本,还是我在浪费时间并使事情变得更糟?如果是,那我该如何说服他?
我有一个生产 SQL Server 2008,其中 8 TB 分布在多个数据库上。我已经删除了每个数据库中大约 85% 的数据,并且必须恢复磁盘空间。所有 USED_SPACE 的最终 SUM 将为 1.2 TB。
此 SHRINKFILE 进程必须适合每个数据库的 7 小时维护窗口。
但是,每个上的 DBCC SHRINKFILE 都需要很多小时才能运行。例如,将 800 GB 的数据库缩小到 120 GB 需要 15 多个小时。
不幸的是,这超出了我的维护窗口,我被迫终止进程,希望数据库不会损坏(随后的 DBCC CHECKDB 显示它们很好)。
我可以看到 DBCC SHRINKFILE 没有充分利用可用的磁盘 I/O 和 CPU 资源。
例如,可以在几个小时内将完整大小的数据库文件从一个磁盘复制到另一个磁盘,但 SHRINKFILE 过程需要相当长的时间。
注意:数据库都设置为 SIMPLE 恢复模式并且 AUTO_SHRINK 关闭。
是的,我看到很多人说永远不要这样做,因为它会破坏索引——我确实计划在 SHRINKFILE 完成时重建索引。
有什么方法可以提高 SHRINKFILE 命令的优先级或任何替代解决方案?以下是我正在考虑的一些选项:
我们刚刚为我们的应用程序迁移到一种新的图像存储方法,这意味着我们不再需要在数据库中存储图像字节数组。
为此,我UPDATE
从单个表的列中删除了(通过声明)大约 19k 字节的数组,其中包含高分辨率图像(大约 8 GB)。没有图像,我不希望数据库恢复到现在的大小。再次请注意,我没有在此处删除行,而只是将字段值设置为 NULL。
其他信息:
DELETE
声明后收缩。我没有删除任何行,我只是将所有行的字段值设置为 null。这会改变什么吗?编辑: 我刚刚想到另一种可能性。图像数据消失后,最好只编写一个脚本来完全重建整个数据库,而无需列图像列。想法?
我知道由于索引碎片,在 SQL Server 中缩小数据文件是一个坏主意。
在争论我的观点之前,我想确保我完全理解。
我知道当dbcc shrinkfile
(除非 with truncateonly
)运行时,后面的页面将移动到较早位置的可用空间。
此函数是否获取数据文件中的最后一页并将其放在第一个可用空间中?
换句话说,如果我们遇到这种情况:
[ Page 1 ] [ Page 2 ] [ empty1 ] [ empty2 ] [ Page 3 ] [ Page 4 ] [ empty3 ] [ empty4 ] [ Page 5 ]
...在执行 a 之后dbcc shrinkfile
会[ Page 5 ]
被移动到,[ empty1 ]
因为那是第一个可用的插槽?等等...
最后它最终看起来像这样:
[ Page 1 ] [ Page 2 ] [ Page 5 ] [ Page 4 ] [ Page 3 ]
任何帮助,将不胜感激。