从 varbinary(max) 清空数据后缩小数据库的最佳方法?

TTT*_*TTT 8 sql-server disk-space blob varbinary sql-server-2014

我们有一个数据库,在varbinary(max)类型的字段中存储了大量数据。在某些时候,我们可以清除大多数行的数据,但不是全部。我们的计划是使该字段可以为空,并在不再需要数据时将其清空。一旦我们这样做,我们希望减少数据库的大小。实现这一目标的最佳方法是什么?

如果没有使用当前设置回收空间的好方法,我的一个想法是将该数据字段移动到只有两列的单独表:主表的键和数据字段。然后我们可以简单地删除不再需要的行。(然后进行某种收缩。)但是,这比简单地使现有字段可空要困难得多。

注意:我实际上不太关心使数据库文件变小,但我确实关心新释放的空间变得可重用。

超过 90% 的数据库大小是这一字段。我已经在 3TB 了。

Eri*_*ing 13

在我看来,只需更新列即可NULL发布页面以供重用。这是一个非常苏格兰的演示,以庆祝美国东部标准时间下午 5 点左右。

USE tempdb;

DROP TABLE IF EXISTS dbo.RobertBurns;

CREATE TABLE dbo.RobertBurns
(
    Id INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    Scotch VARCHAR(50),
    HaggisAddress VARBINARY(MAX)
);

DECLARE @AddressToAVarbinaryHaggis VARBINARY(MAX); 
DECLARE @AddressToAHaggis NVARCHAR(MAX) = N'
Good luck to you and your honest, plump face,
Great chieftain of the pudding race!
Above them all you take your place,
        gut, stomach-lining, or intestine,
You''re well worth a grace
        as long as my arm.

The overloaded serving tray there you fill,
Your buttocks shaped like a distant hilltop,
Your wooden skewer could be used to fix a mill
         if need be,
While through your pores your juices drip
         like liquid gold.

His knife see the serving-man clean,
And then cut you up with great skill,
Making a trench in your bright, gushing guts
        To form a ditch,
And then, 0h! What a glorious sight!
        Warm, steaming, and rich!

Then, spoonful after spoonful, they eagerly eat,
The devil will get the last bit, on they go,
Until all their well-stretched stomachs, by-and-by,
        are bent like drums,
Then the head of the family, about to burst,
        murmurs “Thank the Lord".

Is there a pretentious soul who, over his French ragout,
Or Italian cuisine that would make a pig sick,
Or French stew that would make that same pig ill
        with complete and utter disgust,
Looks down with a sneering, scornful attitude,
        on such a meal? (as Haggis)

Poor devil! See him over his trash!
As feeble as a withered bullrush,
His skinny leg no thicker than a thin rope,
        His fist the size of a nut,
Through a river or field to travel,
        Completely unfit!

But look at the healthy, Haggis-fed person!
The trembling earth respects him as a man!
Put a knife in his fist,
        He''ll make it work!
And legs, and arms, and heads will come off,
        Like the tops of thistle.

You Powers who look after mankind,
And dish out his bill of fare,
Old Scotland wants no watery, wimpy stuff
        That splashes about in little wooden bowls!
But, if You will grant her a grateful prayer,
        Give her a Haggis!';


INSERT dbo.RobertBurns (Scotch, HaggisAddress )
SELECT TOP 1000 
CASE WHEN x.c % 15 = 0 THEN 'Laphroaig'
     WHEN x.c % 5 = 0 THEN 'Lagavulin'
     WHEN x.c % 3 = 0 THEN 'Port Ellen'
     ELSE 'Ardbeg'
END AS Scotch, 
CONVERT(VARBINARY(MAX), REPLICATE(@AddressToAHaggis, x.c % 20 + 1))
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY @@ROWCOUNT) AS c
FROM sys.messages AS m
) AS x;

CREATE INDEX ix_novarbinary ON  dbo.RobertBurns (Scotch, Id);
CREATE INDEX ix_yesvarbinary ON dbo.RobertBurns (Scotch, Id) INCLUDE (HaggisAddress);
Run Code Online (Sandbox Code Playgroud)

插入行后,让我们检查我们的索引页。

SELECT   OBJECT_NAME(i.object_id) AS table_name,
         i.name AS index_name,
         MAX(a.used_pages) AS leaf_me_alone
FROM     sys.indexes AS i
JOIN     sys.partitions AS p
ON p.object_id = i.object_id
   AND p.index_id = i.index_id
JOIN     sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE OBJECT_NAME(i.object_id) = 'RobertBurns'
GROUP BY i.object_id, i.index_id, i.name
ORDER BY OBJECT_NAME(i.object_id), i.index_id;
Run Code Online (Sandbox Code Playgroud)

插入后,我得到了这个。实际页面可能因您而异。

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5587
RobertBurns ix_novarbinary                  10
RobertBurns ix_yesvarbinary                 5581
Run Code Online (Sandbox Code Playgroud)

让我们NULL出一些行!

UPDATE rb
    SET rb.HaggisAddress = NULL
FROM dbo.RobertBurns AS rb
WHERE rb.Id % 15 = 0;
Run Code Online (Sandbox Code Playgroud)

并在我们的页面上查看:

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5300
RobertBurns ix_novarbinary                  10
RobertBurns ix_yesvarbinary                 5273
Run Code Online (Sandbox Code Playgroud)

所以页数减少了。哈扎!对于接触我们VARBINARY数据的两个索引,他们丢失了一堆页面。这意味着它们将重新流通以供其他对象使用。因为我在 tempdb,他们可能会很快被这里发生的所有垃圾事情吞噬。

现在让我们放回一些数据:

INSERT dbo.RobertBurns (Scotch, HaggisAddress )
SELECT TOP 10 rb.Scotch, rb.HaggisAddress
FROM dbo.RobertBurns AS rb;
Run Code Online (Sandbox Code Playgroud)

并重新检查:

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5330
RobertBurns ix_novarbinary                  11
RobertBurns ix_yesvarbinary                 5305
Run Code Online (Sandbox Code Playgroud)

页数略有增加。

因此,看起来您不必做任何太疯狂的事情,甚至不必缩小数据库以获得空间重用。我认为您将删除列的行为与需要运行DBCC CLEANTABLE您实际执行的操作混为一谈。

希望这可以帮助!