¿La mejor manera de reducir una base de datos después de anular datos de varbinary (max)?


8

Tenemos una base de datos con una gran cantidad de datos almacenados en un campo de tipo varbinary (max) . En algún momento podemos purgar esos datos para la mayoría de las filas, pero no para todas. Nuestro plan es hacer que ese campo sea anulable y simplemente anular los datos cuando ya no sean necesarios. Una vez que lo hagamos, nos gustaría reducir el tamaño de la base de datos. Cuál es la mejor manera de lograr esto?

Si no hay una buena manera de recuperar espacio con la configuración actual, una idea que tengo es mover ese campo de datos a una tabla separada con solo dos columnas: la clave de la tabla principal y el campo de datos. Entonces podríamos simplemente eliminar las filas cuando ya no sean necesarias. (Y luego haga algún tipo de reducción). Sin embargo, este sería un cambio mucho más difícil de hacer que simplemente hacer que el campo existente sea anulable.

Nota: en realidad no me importa mucho hacer que el archivo de la base de datos sea más pequeño, pero me importa que el espacio recién liberado se vuelva reutilizable.

Más del 90% del tamaño de la base de datos es este campo. Ya estoy en 3TB.

Respuestas:


13

Me parece que simplemente actualizo las columnas para NULLliberar páginas para su reutilización. Aquí hay una demostración de Very Scottish®, para celebrar que son casi las 5 p.m. EST.

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);

Con las filas insertadas, veamos nuestras páginas de índice.

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;

Después del inserto, obtengo esto. Las páginas reales pueden variar para usted.

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5587
RobertBurns ix_novarbinary                  10
RobertBurns ix_yesvarbinary                 5581

¡Salgamos NULLalgunas filas!

UPDATE rb
    SET rb.HaggisAddress = NULL
FROM dbo.RobertBurns AS rb
WHERE rb.Id % 15 = 0;

Y vuelva a visitar nuestras páginas:

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5300
RobertBurns ix_novarbinary                  10
RobertBurns ix_yesvarbinary                 5273

Entonces se redujo el recuento de páginas. Huzzah! Para los dos índices que tocan nuestros VARBINARYdatos, perdieron una página buncha. Eso significa que están de vuelta en circulación para que otros objetos los usen. Como estoy en tempdb, probablemente se engullen rápidamente por todas las cosas basura que suceden aquí.

Ahora volvamos a poner algunos datos:

INSERT dbo.RobertBurns (Scotch, HaggisAddress )
SELECT TOP 10 rb.Scotch, rb.HaggisAddress
FROM dbo.RobertBurns AS rb;

Y comprobando de nuevo:

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5330
RobertBurns ix_novarbinary                  11
RobertBurns ix_yesvarbinary                 5305

Los recuentos de páginas aumentaron un poco.

Entonces, parece que no tienes que hacer nada demasiado loco, o incluso reducir tu base de datos para reutilizar el espacio. Creo que estaba combinando el comportamiento de soltar columnas y necesitando correr DBCC CLEANTABLEcon lo que realmente está haciendo.

¡Espero que esto ayude!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.