Beim Versuch, nicht verwendeten Speicherplatz freizugeben, nimmt der verwendete Speicherplatz in SQL Server erheblich zu


15

Ich habe eine Tabelle in einer Produktionsdatenbank mit einer Größe von 525 GB, von denen 383 GB nicht verwendet werden:

Unbenutzter Speicherplatz

Ich möchte einen Teil dieses Speicherplatzes zurückfordern, aber bevor ich mich mit der Produktionsdatenbank beschäftige, teste ich einige Strategien für eine identische Tabelle in einer Testdatenbank mit weniger Daten. Diese Tabelle hat ein ähnliches Problem:

Unbenutzter Speicherplatz

Einige Informationen zur Tabelle:

  • Der Füllfaktor wird auf 0 gesetzt
  • Es gibt ungefähr 30 Spalten
  • Eine der Spalten ist ein LOB vom Typ Image, in dem Dateien mit einer Größe von wenigen KB bis zu mehreren hundert MB gespeichert werden
  • Der Tabelle sind keine hypothetischen Indizes zugeordnet

Auf dem Server wird SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64) ausgeführt. Die Datenbank verwendet das SIMPLEWiederherstellungsmodell.

Einige Dinge, die ich ausprobiert habe:

  • Wiederaufbau der Indizes: ALTER INDEX ALL ON dbo.MyTable REBUILD. Dies hatte vernachlässigbare Auswirkungen.
  • Umordnung der Indizes: ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON). Dies hatte vernachlässigbare Auswirkungen.
  • Kopierte die LOB-Spalte in eine andere Tabelle, löschte die Spalte, erstellte die Spalte neu und kopierte die Daten zurück (wie in diesem Beitrag erläutert: Freigeben von nicht verwendetem Speicherplatz in der SQL Server-Tabelle ). Dadurch wurde der ungenutzte Speicherplatz verkleinert, aber scheinbar nur in belegten Speicherplatz umgewandelt:

    Unbenutzter Speicherplatz

  • Verwenden Sie das Dienstprogramm bcp, um die Tabelle zu exportieren, zu kürzen und neu zu laden (wie in diesem Beitrag erläutert: Freigeben des nicht verwendeten Speicherplatzes für eine Tabelle ). Dadurch wurde auch der nicht genutzte Speicherplatz reduziert und der genutzte Speicherplatz in einem ähnlichen Ausmaß wie im obigen Bild vergrößert.

  • Obwohl dies nicht empfohlen wird, habe ich die Befehle DBCC SHRINKFILE und DBCC SHRINKDATABASE ausprobiert, aber sie hatten keine Auswirkungen auf den nicht verwendeten Speicherplatz.
  • Laufen DBCC CLEANTABLE('myDB', 'dbo.myTable')machte keinen Unterschied
  • Ich habe all das versucht, während die Bild- und Textdatentypen beibehalten wurden und nachdem die Datentypen in varbinary (max) und varchar (max) geändert wurden.
  • Ich habe versucht, die Daten in eine neue Tabelle in einer neuen Datenbank zu importieren. Dabei wurde auch nur der nicht verwendete Speicherplatz in den verwendeten Speicherplatz konvertiert. Ich habe die Details dieses Versuchs in diesem Beitrag beschrieben .

Ich möchte diese Versuche nicht in der Produktionsdatenbank durchführen, wenn dies die erwarteten Ergebnisse sind.

  1. Warum wird der ungenutzte Speicherplatz nach einigen dieser Versuche nur in benutzten Speicherplatz konvertiert? Ich habe das Gefühl, ich habe kein gutes Verständnis dafür, was unter der Haube passiert.
  2. Kann ich noch etwas tun, um den nicht genutzten Speicherplatz zu verringern, ohne den genutzten Speicherplatz zu vergrößern?

BEARBEITEN: Hier ist der Datenträgernutzungsbericht und das Skript für die Tabelle:

Festplattennutzung

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MyTable](
    [Column1]  [int] NOT NULL,
    [Column2]  [int] NOT NULL,
    [Column3]  [int] NOT NULL,
    [Column4]  [bit] NOT NULL,
    [Column5]  [tinyint] NOT NULL,
    [Column6]  [datetime] NULL,
    [Column7]  [int] NOT NULL,
    [Column8]  [varchar](100) NULL,
    [Column9]  [varchar](256) NULL,
    [Column10] [int] NULL,
    [Column11] [image] NULL,
    [Column12] [text] NULL,
    [Column13] [varchar](100) NULL,
    [Column14] [varchar](6) NULL,
    [Column15] [int] NOT NULL,
    [Column16] [bit] NOT NULL,
    [Column17] [datetime] NULL,
    [Column18] [varchar](50) NULL,
    [Column19] [varchar](50) NULL,
    [Column20] [varchar](60) NULL,
    [Column21] [varchar](20) NULL,
    [Column22] [varchar](120) NULL,
    [Column23] [varchar](4) NULL,
    [Column24] [varchar](75) NULL,
    [Column25] [char](1) NULL,
    [Column26] [varchar](50) NULL,
    [Column27] [varchar](128) NULL,
    [Column28] [varchar](50) NULL,
    [Column29] [int] NULL,
    [Column30] [text] NULL,
 CONSTRAINT [PK] PRIMARY KEY CLUSTERED 
(
    [Column1] ASC,
    [Column2] ASC,
    [Column3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column4]  DEFAULT (0) FOR [Column4]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column5]  DEFAULT (0) FOR [Column5]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column15]  DEFAULT (0) FOR [Column15]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column16]  DEFAULT (0) FOR [Column16]
GO

Hier sind die Ergebnisse der Ausführung der Befehle in Max Vernons Antwort:

╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
 TotalBytes  FreeBytes  TotalPages  TotalEmptyPages  PageBytesFreePercent  UnusedPagesPercent 
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
  9014280192 8653594624     1100376          997178             95.998700           90.621500 
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
 ObjectName   ReservedPageCount       UsedPageCount 
╠═════════════╬═══════════════════╬════════════════════╣
 dbo.MyTable            5109090             2850245 
╚═════════════╩═══════════════════╩════════════════════╝

AKTUALISIEREN:

Ich habe folgendes ausgeführt, wie von Max Vernon vorgeschlagen:

DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');

Und hier war die Ausgabe:

DBCC UPDATEUSAGE: Usage counts updated for table 'MyTable' (index 'PK_MyTable', partition 1):
        USED pages (LOB Data): changed from (568025) to (1019641) pages.
        RSVD pages (LOB Data): changed from (1019761) to (1019763) pages.

Dadurch wurde die Datenträgerverwendung für die Tabelle aktualisiert:

Bildbeschreibung hier eingeben

Und die Gesamtbelegung der Festplatte:

Bildbeschreibung hier eingeben

Es sieht also so aus, als ob das Problem darin bestand, dass die Datenträgernutzung, die von SQL Server verfolgt wurde, nicht mehr mit der tatsächlichen Datenträgernutzung synchronisiert war. Ich werde dieses Problem als gelöst betrachten, aber ich würde gerne wissen, warum dies überhaupt passiert wäre!


Wurden die Verkleinerungen nach dem Ändern der Datentypen versucht?
LowlyDBA

1
Haben Sie die Möglichkeit, den von Ihnen gemachten Repro mit uns zu teilen, oder verwenden Sie nur eine Sicherungskopie Ihrer Produktionsdatenbank als Testkopie?
John Eisbrener

@ LowlyDBA Ja, ich habe versucht, die Daten zu verkleinern, nachdem ich den Datentyp geändert habe.
Ken

Ich habe das Skript ausgeführt und bestätigt, dass es keine hypothetischen Indizes gibt.
Ken

1
Wie lange ist diese Datenbank schon in Produktion? Wie oft rennst du DBCC CHECKDB? Haben Sie darüber nachgedacht , von den sich bewegenden entfernt veraltete Datentypen , textund image? Sie könnten zu den falschen Statistiken beitragen.
Max Vernon

Antworten:


9

Als ersten Schritt würde ich DBCC UPDATEUSAGE für die Tabelle ausführen , da die Symptome eine inkonsistente Speichernutzung anzeigen.

DBCC UPDATEUSAGE korrigiert die Anzahl der Zeilen, verwendeten Seiten, reservierten Seiten, Blattseiten und Datenseiten für jede Partition in einer Tabelle oder einem Index. Wenn die Systemtabellen keine Ungenauigkeiten enthalten, gibt DBCC UPDATEUSAGE keine Daten zurück. Wenn Ungenauigkeiten gefunden und korrigiert werden und WITH NO_INFOMSGS nicht verwendet wird, gibt DBCC UPDATEUSAGE die Zeilen und Spalten zurück, die in den Systemtabellen aktualisiert werden.

Die Syntax lautet:

DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');

Nachdem Sie das ausgeführt haben, würde ich EXEC sys.sp_spaceusedgegen den Tisch laufen :

EXEC sys.sp_spaceused @objname = N'dbo.MyTable'
    , @updateusage = 'false' --true or false
    , @mode = 'ALL' --ALL, LOCAL_ONLY, REMOTE_ONLY
    , @oneresultset = 1;

Der obige Befehl bietet die Möglichkeit, die Verwendung zu aktualisieren. Da Sie ihn jedoch DBCC UPDATEUSAGEzuerst manuell ausgeführt haben, belassen Sie diesen Wert einfach auf false. Ausführen von DBCC UPDATEUSAGEHand können Sie sehen , ob etwas korrigiert.

Die folgende Abfrage sollte den Prozentsatz der freien Bytes in der Tabelle und den Prozentsatz der freien Seiten in der Tabelle anzeigen. Da die Abfrage eine undokumentierte Funktion verwendet, ist es nicht ratsam, sich auf die Ergebnisse zu verlassen, sie erscheint jedoch im Vergleich zur Ausgabe von sys.sp_spaceusedauf hoher Ebene genau .

Wenn der Prozentsatz der freien Bytes deutlich höher ist als der Prozentsatz der freien Seiten, haben Sie viele teilweise leere Seiten.

Teilweise leere Seiten können verschiedene Ursachen haben:

  1. Seitenteile, bei denen die Seite geteilt werden muss, um neue Einfügungen in den gruppierten Index aufzunehmen

  2. Die Seite kann aufgrund der Spaltengröße nicht mit Spalten gefüllt werden.

Die Abfrage verwendet die undokumentierte sys.dm_db_database_page_allocationsdynamische Verwaltungsfunktion:

;WITH dpa AS 
(
    SELECT dpa.*
        , page_free_space_percent_corrected = 
          CASE COALESCE(dpa.page_type_desc, N'')
            WHEN N'TEXT_MIX_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            WHEN N'TEXT_TREE_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            ELSE COALESCE(dpa.page_free_space_percent, 100)
          END
    FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('dbo.MyTable'), NULL, NULL, 'DETAILED') dpa
)
, src AS
(
SELECT TotalKB = COUNT_BIG(1) * 8192 / 1024
    , FreeKB = SUM((dpa.page_free_space_percent_corrected / 100) * CONVERT(bigint, 8192)) / 1024
    , TotalPages = COUNT_BIG(1)
    , TotalEmptyPages = SUM(CASE WHEN dpa.page_free_space_percent_corrected = 100 THEN 1 ELSE 0 END) --completely empty pages
FROM dpa
)
SELECT *
    , BytesFreePercent = (CONVERT(decimal(38,2), src.FreeKB) / src.TotalKB) * 100
    , UnusedPagesPercent = (CONVERT(decimal(38,2), src.TotalEmptyPages) / src.TotalPages) * 100
FROM src

Die Ausgabe sieht folgendermaßen aus:

╔═════════╦════════╦════════════╦═════════════════ ╦══════════════════╦════════════════════╗
║ TotalKB ║ FreeKB ║ TotalPages ║ TotalEmptyPages ║ BytesFreePercent ║ UnusedPagesPercent ║
╠═════════╬════════╬════════════╬═════════════════ ╬══════════════════╬════════════════════╣
║ 208 ║ 96 ║ 26 ║ 12 ║ 46.153800 ║ 46.153800 ║
╚═════════╩════════╩════════════╩═════════════════ ╩══════════════════╩════════════════════╝

Ich habe einen Blog-Beitrag geschrieben, der die Funktion hier beschreibt .

In Ihrem Szenario sollten Sie, seit Sie ausgeführt haben ALTER TABLE ... REBUILD, eine sehr niedrige Zahl für sehen TotalEmptyPages, aber ich schätze, Sie werden immer noch rund 72% in haben BytesFreePercent.

Ich habe Ihr CREATE TABLESkript verwendet, um zu versuchen, Ihr Szenario neu zu erstellen.

Dies ist das MCVE, das ich verwende:

DROP TABLE IF EXISTS dbo.MyTable;

CREATE TABLE [dbo].[MyTable](
    [Column1]  [int]            NOT NULL IDENTITY(1,1),
    [Column2]  [int]            NOT NULL,
    [Column3]  [int]            NOT NULL,
    [Column4]  [bit]            NOT NULL,
    [Column5]  [tinyint]        NOT NULL,
    [Column6]  [datetime]       NULL,
    [Column7]  [int]            NOT NULL,
    [Column8]  [varchar](100)   NULL,
    [Column9]  [varchar](256)   NULL,
    [Column10] [int]            NULL,
    [Column11] [image]          NULL,
    [Column12] [text]           NULL,
    [Column13] [varchar](100)   NULL,
    [Column14] [varchar](6)     NULL,
    [Column15] [int]            NOT NULL,
    [Column16] [bit]            NOT NULL,
    [Column17] [datetime]       NULL,
    [Column18] [varchar](50)    NULL,
    [Column19] [varchar](50)    NULL,
    [Column20] [varchar](60)    NULL,
    [Column21] [varchar](20)    NULL,
    [Column22] [varchar](120)   NULL,
    [Column23] [varchar](4)     NULL,
    [Column24] [varchar](75)    NULL,
    [Column25] [char](1)        NULL,
    [Column26] [varchar](50)    NULL,
    [Column27] [varchar](128)   NULL,
    [Column28] [varchar](50)    NULL,
    [Column29] [int]            NULL,
    [Column30] [text]           NULL,
 CONSTRAINT [PK] PRIMARY KEY CLUSTERED 
(
    [Column1] ASC,
    [Column2] ASC,
    [Column3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column4]  DEFAULT (0) FOR [Column4]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column5]  DEFAULT (0) FOR [Column5]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column15]  DEFAULT (0) FOR [Column15]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column16]  DEFAULT (0) FOR [Column16]
GO

INSERT INTO dbo.MyTable (
      Column2
    , Column3
    , Column4
    , Column5
    , Column6
    , Column7
    , Column8
    , Column9
    , Column10
    , Column11
    , Column12
    , Column13
    , Column14
    , Column15
    , Column16
    , Column17
    , Column18
    , Column19
    , Column20
    , Column21
    , Column22
    , Column23
    , Column24
    , Column25
    , Column26
    , Column27
    , Column28
    , Column29
    , Column30
)
VALUES (
          0
        , 0
        , 0
        , 0
        , '2019-07-09 00:00:00'
        , 1
        , REPLICATE('A', 50)    
        , REPLICATE('B', 128)   
        , 0
        , REPLICATE(CONVERT(varchar(max), 'a'), 1)
        , REPLICATE(CONVERT(varchar(max), 'b'), 9000)
        , REPLICATE('C', 50)    
        , REPLICATE('D', 3)     
        , 0
        , 0
        , '2019-07-10 00:00:00'
        , REPLICATE('E', 25)    
        , REPLICATE('F', 25)    
        , REPLICATE('G', 30)    
        , REPLICATE('H', 10)    
        , REPLICATE('I', 120)   
        , REPLICATE('J', 4)     
        , REPLICATE('K', 75)    
        , 'L'       
        , REPLICATE('M', 50)    
        , REPLICATE('N', 128)   
        , REPLICATE('O', 50)    
        , 0
        , REPLICATE(CONVERT(varchar(max), 'c'), 90000)
);
--GO 100

;WITH dpa AS 
(
    SELECT dpa.*
        , page_free_space_percent_corrected = 
          CASE COALESCE(dpa.page_type_desc, N'')
            WHEN N'TEXT_MIX_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            WHEN N'TEXT_TREE_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            ELSE COALESCE(dpa.page_free_space_percent, 100)
          END
    FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('dbo.MyTable'), NULL, NULL, 'DETAILED') dpa
)
, src AS
(
SELECT TotalKB = COUNT_BIG(1) * 8192 / 1024
    , FreeKB = SUM((dpa.page_free_space_percent_corrected / 100) * CONVERT(bigint, 8192)) / 1024
    , TotalPages = COUNT_BIG(1)
    , TotalEmptyPages = SUM(CASE WHEN dpa.page_free_space_percent_corrected = 100 THEN 1 ELSE 0 END) --completely empty pages
FROM dpa
)
SELECT *
    , BytesFreePercent = (CONVERT(decimal(38,2), src.FreeKB) / src.TotalKB) * 100
    , UnusedPagesPercent = (CONVERT(decimal(38,2), src.TotalEmptyPages) / src.TotalPages) * 100
FROM src

Die folgende Abfrage zeigt eine einzelne Zeile für jede der Tabelle zugewiesene Seite und verwendet dieselbe undokumentierte DMV:

SELECT DatabaseName = d.name
    , ObjectName = o.name
    , IndexName = i.name
    , PartitionID = dpa.partition_id
    , dpa.allocation_unit_type_desc
    , dpa.allocated_page_file_id
    , dpa.allocated_page_page_id
    , dpa.is_allocated
    , dpa.page_free_space_percent --this seems unreliable
    , page_free_space_percent_corrected = 
        CASE COALESCE(dpa.page_type_desc, N'')
        WHEN N'TEXT_MIX_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
        WHEN N'TEXT_TREE_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
        ELSE COALESCE(dpa.page_free_space_percent, 100)
        END
    , dpa.page_type_desc
    , dpa.is_page_compressed
    , dpa.has_ghost_records
FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('dbo.MyTable'), NULL, NULL, 'DETAILED') dpa
    LEFT JOIN sys.databases d ON dpa.database_id = d.database_id
    LEFT JOIN sys.objects o ON dpa.object_id = o.object_id
    LEFT JOIN sys.indexes i ON dpa.object_id = i.object_id AND dpa.index_id = i.index_id
WHERE dpa.database_id = DB_ID() --sanity check for sys.objects and sys.indexes

In der Ausgabe werden viele Zeilen angezeigt, wenn Sie sie in Ihrer Testumgebung für Ihre reale Tabelle ausführen, aber Sie können möglicherweise erkennen, wo das Problem liegt.

Können Sie das folgende Skript ausführen und die Ergebnisse in Ihrer Frage veröffentlichen? Ich versuche nur sicherzustellen, dass wir auf der gleichen Seite sind.

SELECT ObjectName = s.name + N'.' + o.name
    , ReservedPageCount = SUM(dps.reserved_page_count)
    , UsePageCount = SUM(dps.used_page_count)
FROM sys.schemas s
    INNER JOIN sys.objects o ON s.schema_id = o.schema_id
    INNER JOIN sys.partitions p ON o.object_id = p.object_id
    INNER JOIN sys.dm_db_partition_stats dps ON p.object_id = dps.object_id
WHERE s.name = N'dbo'
    AND o.name = N'MyTable'
GROUP BY s.name + N'.' + o.name;

2
Beim Ausführen DBCC UPDATEUSAGEwurden der nicht verwendete Speicherplatz und die nicht verwendete Seitenzahl aktualisiert. Es sieht so aus, als ob die Datenträgernutzung und die von SQL Server gemeldeten Seiteninformationen extrem nicht synchron waren. Ich habe meinen Beitrag mit den Details aktualisiert. Ich bin gespannt, wie das überhaupt passiert wäre, aber zumindest wurde das Problem gefunden. Vielen Dank für all Ihre Hilfe, ich weiß das sehr zu schätzen!
Ken

0

Eine der Spalten ist ein LOB vom Typ Image, in dem Dateien mit einer Größe von wenigen KB bis zu mehreren hundert MB gespeichert werden

Möglicherweise tritt eine interne Fragmentierung auf.
Was ist die Seitenfragmentierung für diese Tabelle?
Und unterscheidet sich die Fragmentierung für die In-Row von den Off-Row-Seiten?

Sie sagen, Sie haben Dateien, die ein paar KB groß sind.
SQL Server speichert alles in 8060-Byte-Seiten. Das heißt, wenn Sie eine Zeile (oder Off-Row-Daten) mit 4040 Bytes haben und die nächste ähnlich ist, können nicht beide auf dieselbe Seite passen, und Sie werden die Hälfte Ihres Speicherplatzes verschwenden. Versuchen Sie, die Zeilengröße zu ändern, indem Sie Spalten mit variabler Länge (beispielsweise mit dem Bild) in einer anderen Tabelle speichern.


Ich denke nicht, dass Fragmentierung das Problem ist. Nach der Neuerstellung der Indizes beträgt die Fragmentierung für den Clustered-Index 0,45% und der Seitenumfang 98,93%.
Ken

Das Neuerstellen einer Tabelle oder eines Index hilft nicht, wenn Sie unter sehr großen Zeilen oder LOB-Daten leiden, die nicht gut in 8-KB-Seiten passen. Es ist, was Max Vernon ausführlicher erklärte: "Sie haben viele teilweise leere Seiten." auch interne Fragmentierung genannt
DrTrunks Bell

-3

Befindet sich die Datenbank im vollständigen Wiederherstellungsmodus? Wenn dies der Fall ist, werden beim Ausführen einer Verkleinerung alle Änderungen protokolliert und nicht so verkleinert, wie Sie es erwarten. Abhängig von Ihren Betriebsstunden können Sie eine Sicherungskopie erstellen, in den Massenversand-Wiederherstellungsmodus wechseln und dann die Verkleinerung der Datendatei ausführen. Danach möchten Sie Index-Skripte ausführen, um zu reparieren / neu zu erstellen und zur vollständigen Wiederherstellung zurückzukehren. Das würde ich auf jeden Fall versuchen, aber es hängt auch hier von Ihren Betriebsstunden ab.


4
Das Wiederherstellungsmodell aufzurufen ist interessant. Ich denke, es wäre sinnvoller, wenn das OP Probleme mit der Größe seiner Protokolldatei hätte. Wie es aussieht, haben sie Schwierigkeiten mit der Größe der Datendatei, so würde ich überrascht sein , wenn das Wiederherstellungsmodell beschrieben , das Problem verursacht wurde.
Josh Darnell

Es ist wahr, aber das einzige Mal, dass ich einen Shrink ausgeführt habe und es keinen wirklichen Einfluss auf den Speicherplatz hatte, war das Wiederherstellungsmodell. Daher dachte ich, dass es sich lohnt, ihn aufzurufen, falls es sich um eine Fehldiagnose handelt.
John-Henry Lochbaum

-3

Das einzige Mal, dass ich eine DB nicht verkleinern und Speicherplatz zurückfordern konnte, ist, dass Sie eine DB nicht über die ursprüngliche Größe der DB, als sie erstellt wurde, hinaus verkleinern können. Wenn Ihre DB beispielsweise eine Kopie der Produktions-DB ist und Sie die DB zum ersten Mal mit 525 GB erstellt haben, können Sie mit SQL Server die Größe nicht unter 525 GB verringern, unabhängig davon, wie viele Daten Sie aus der DB löschen. Wenn die Datenbank jedoch mit weniger als 383 GB erstellt wurde und dann 525 GB umfasst, sollten Sie keine Probleme haben, den Speicherplatz zurückzugewinnen. Ich habe lange gedacht, dass dies eine dumme und willkürliche Einschränkung von Microsoft ist.

Verkleinern Sie die Datenbank nur auf die ursprüngliche Größe, die nach dem Erstellen der Datenbank festgelegt wurde


Bei der Frage geht es nicht um das Verkleinern einer Datenbank (und wenn
ja,

Solange nicht verwendeter Speicherplatz vorhanden ist, kann die Datenbank unabhängig von der ursprünglichen Größe auf einige MB verkleinert werden. Es ist nicht unbedingt eine gute Idee, aber ich hatte viele Gelegenheiten, Datenbanken zu verkleinern und nie an ein Limit wie dieses zu stoßen.
Ray

-3

Ich bin auf dieses Problem bei Produktionsboxen gestoßen. Sie müssen lediglich Tabellen und Indizes für jede Tabelle neu erstellen (in dieser Reihenfolge).

Hier ist die Abfrage, mit der ich Tabellen in Schach halte. Auf diese Weise können Sie ermitteln, welche Tabellen neu erstellt werden müssen, und die SQL-Abfragen erstellen, die Sie ausführen müssen. Diese Abfrage ist auf Abfragen mit mehr als 1 MB ungenutztem Speicherplatz und einer ungenutzten Quote von 5% beschränkt, sodass Sie nur das neu erstellen, worauf Sie sich wirklich konzentrieren müssen:

SELECT  'alter table [' + t.NAME + '] rebuild;' AS SQL1, 'alter index all on [' + t.NAME + '] rebuild;' as SQL2, t.NAME AS TableName, p.rows AS RowCounts, SUM(a.total_pages) * 8/1024 AS TotalSpaceMB,  SUM(a.used_pages) * 8/1024 AS UsedSpaceMB,  (SUM(a.total_pages) - SUM(a.used_pages)) * 8/1024 AS UnusedSpaceMB, case when SUM(a.total_pages)=0 then 0 else (SUM(a.total_pages) - SUM(a.used_pages))*100/SUM(a.total_pages) end as Ratio  FROM     sys.tables t (nolock) INNER JOIN       sys.indexes i (nolock)  ON t.OBJECT_ID = i.object_id INNER JOIN  sys.partitions p (nolock) ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id INNER JOIN  sys.allocation_units a (nolock) ON p.partition_id = a.container_id LEFT OUTER JOIN  sys.schemas s (nolock) ON t.schema_id = s.schema_id WHERE  t.is_ms_shipped = 0 AND i.OBJECT_ID > 255  GROUP BY  t.Name, s.Name, p.Rows  
having  (SUM(a.total_pages) - SUM(a.used_pages)) * 8/1024>1
and (SUM(a.total_pages) - SUM(a.used_pages))*100/SUM(a.total_pages)>5
ORDER BY    5 desc

Ein erneuter Aufbau der Tabelle würde, wie das OP angibt, den größten Teil der Fragmentierung beseitigen. Ich bezweifle, dass ein weiterer Umbau weiterhilft.
Max Vernon
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.