383 GB kullanılmayan 525 GB büyüklüğünde bir üretim veritabanında bir tablo var:
Bu alanın bir kısmını geri almak istiyorum, ama üretim DB ile uğraşmadan önce, daha az veri ile bir test DB aynı tabloda bazı stratejileri test ediyorum. Bu tablonun benzer bir sorunu var:
Tablo hakkında bazı bilgiler:
- Dolum faktörü 0 olarak ayarlanmıştır
- Yaklaşık 30 sütun var
- Sütunlardan biri LOB tipi bir resimdir ve boyutu birkaç KB ile birkaç yüz MB arasında değişen dosyaları depolar
- Tabloda ilişkili herhangi bir varsayımsal dizin yok
Sunucu, SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64) çalıştırıyor. Veritabanı SIMPLE
kurtarma modelini kullanıyor .
Denediğim bazı şeyler:
- Endeksleri Yeniden:
ALTER INDEX ALL ON dbo.MyTable REBUILD
. Bunun ihmal edilebilir bir etkisi oldu. - Endeksleri yeniden düzenlenmesi:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
. Bunun ihmal edilebilir bir etkisi oldu. LOB sütununu başka bir tabloya kopyaladı, sütunu bıraktı, sütunu yeniden oluşturdu ve verileri geri kopyaladı (bu yayında belirtildiği gibi: Kullanılmayan Space SQL Server Tablosunu Serbest Bırakma ). Bu, kullanılmayan alanı azalttı, ancak sadece kullanılan alana dönüştürdüğü görülüyordu:
Tabloyu dışa aktarmak, kısaltmak ve yeniden yüklemek için bcp yardımcı programını kullanın (bu yayında belirtildiği gibi: Bir tablo için kullanılmayan alan nasıl serbest bırakılır ). Bu aynı zamanda kullanılmayan alanı azalttı ve kullanılan alanı yukarıdaki görüntüye benzer ölçüde artırdı.
- Tavsiye edilmese de, DBCC SHRINKFILE ve DBCC SHRINKDATABASE komutlarını denedim, ancak kullanılmayan alan üzerinde herhangi bir etkisi olmadı.
- Koşmak
DBCC CLEANTABLE('myDB', 'dbo.myTable')
fark yaratmadı - Hem görüntü hem de metin veri tiplerini korurken ve veri türlerini varbinary (max) ve varchar (max) olarak değiştirdikten sonra yukarıdakilerin hepsini denedim.
- Yeni bir veritabanındaki yeni bir tabloya veri aktarmayı denedim ve bu da sadece kullanılmayan alanı kullanılan alana dönüştürdü. Bu yazıda bu girişimin ayrıntılarını özetledim .
Bekleyebileceğim sonuçlar bu ise üretim DB bu girişimleri yapmak istemiyorum, yani:
- Kullanılmayan alan neden bu denemelerden sonra kullanılmaya dönüştürülüyor? Kaputun altında neler olup bittiğine dair iyi bir anlayışım yok gibi hissediyorum.
- Kullanılmamış alanı, kullanılan alanı arttırmadan azaltmak için yapabileceğim başka bir şey var mı?
EDIT: İşte Tablo için Disk Kullanımı raporu ve komut dosyası:
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
Max Vernon'un cevabında komutları yürütmenin sonuçları:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
GÜNCELLEME:
Max Vernon'un önerdiği şekilde aşağıdakileri yaptım:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
İşte çıktı:
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.
Bu tablo için disk kullanımını güncelledi:
Ve genel disk kullanımı:
Yani, sorun, SQL Server tarafından izlenen disk kullanımının gerçek disk kullanımı ile çılgınca senkronize olmamasıydı. Bu sorunun çözüldüğünü düşüneceğim, ancak bunun neden ilk başta olacağını bilmek isterim!
DBCC UPDATEUSAGE
kullanılmayan alan ve kullanılmayan sayfa sayısı güncellendi. SQL Server tarafından bildirilen disk kullanımı ve sayfa bilgilerinin son derece senkronize olmadığı anlaşılıyor - Yazımı ayrıntılarla güncelledim. Bunun en başta nasıl olacağını merak ediyorum, ama en azından sorun bulundu. Tüm yardımlarınız için teşekkür ederim, gerçekten minnettarım!