Kullanılmayan alanı geri alma girişimleri SQL Server'da kullanılan alanın önemli ölçüde artmasına neden olur


15

383 GB kullanılmayan 525 GB büyüklüğünde bir üretim veritabanında bir tablo var:

Kullanılmayan Alan

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:

Kullanılmayan Alan

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ı SIMPLEkurtarma 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:

    Kullanılmayan Alan

  • 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:

  1. 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.
  2. 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ı:

Disk kullanımı

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:

resim açıklamasını buraya girin

Ve genel disk kullanımı:

resim açıklamasını buraya girin

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!

Yanıtlar:


10

Belirtiler tutarsız alan kullanımı gösterdiğinden, DBCC UPDATEUSAGE öğesini ilk adım olarak tabloya karşı çalıştırırım .

DBCC GÜNCELLEME, bir tablo veya dizindeki her bölüm için satırları, kullanılmış sayfaları, ayrılmış sayfaları, yaprak sayfalarını ve veri sayfası sayılarını düzeltir. Sistem tablolarında herhangi bir yanlışlık yoksa, DBCC UPDATEUSAGE veri döndürmez. Yanlışlıklar bulunur ve düzeltilirse ve WITH NO_INFOMSGS kullanılmazsa, DBCC UPDATEUSAGE sistem tablolarında güncellenen satırları ve sütunları döndürür.

Sözdizimi:

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

Bunu çalıştırdıktan sonra EXEC sys.sp_spaceused, masaya karşı koşardım:

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

Yukarıdaki komutun kullanımı güncelleme seçeneği vardır, ancak DBCC UPDATEUSAGEönce manuel olarak çalıştırdığınız için bu ayarı false olarak bırakın. DBCC UPDATEUSAGEElle çalıştırmak , bir şeyin düzeltilip düzeltilmediğini görmenizi sağlar.

Aşağıdaki sorgu, tablodaki boş bayt yüzdesini ve tablodaki boş sayfaların yüzdesini göstermelidir. Sorgu belgelenmemiş bir özellik kullandığından, sonuçlara güvenmek akıllıca değildir, ancak sys.sp_spaceusedyüksek düzeydeki çıktıyla karşılaştırıldığında doğru görünüyor .

Serbest bayt yüzdesi, boş sayfaların yüzdesinden önemli ölçüde yüksekse, birçok boş sayfanız vardır.

Kısmen boş sayfalar aşağıdakiler de dahil olmak üzere bir dizi nedenden kaynaklanabilir:

  1. Kümelenmiş dizine yeni ekler eklemek için sayfanın bölünmesi gereken sayfa bölünmeleri

  2. Sütun boyutu nedeniyle sayfayı sütunlarla dolduramama.

Sorgu, belgelenmemiş sys.dm_db_database_page_allocationsdinamik yönetim işlevini kullanır :

;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

Çıktı şöyle görünür:

╔═════════╦════════╦════════════╦═════════════════ ╦══════════════════╦════════════════════╗
║ TotalKB ║ FreeKB ║ Toplam Sayfalar ║ TotalEmptyPages ║ BytesFreePercent ║ Kullanılmayan SayfalarPercent ║
╠═════════╬════════╬════════════╬═════════════════ ╬══════════════════╬════════════════════╣
║ 208 ║ 96 ║ 26 ║ 12 ║ 46.153800 ║ 46.153800 ║
╚═════════╩════════╩════════════╩═════════════════ ╩══════════════════╩════════════════════╝

Buradaki işlevi açıklayan bir blog yazısı yazdım .

Senaryonuzda, idam ALTER TABLE ... REBUILDettiğiniz için TotalEmptyPages, çok düşük bir sayı görmelisiniz , ancak sanırım hala% 72 civarında olacaksınız BytesFreePercent.

Ben senin kullandım CREATE TABLEsenin senaryoyu yeniden denemek için komut dosyası.

Bu kullandığım MCVE :

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

Aşağıdaki sorgu, tabloya atanan her sayfa için tek bir satır gösterir ve aynı belgelenmemiş DMV'yi kullanır:

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

Test ortamınızdaki gerçek tablonuza karşı çalıştırırsanız çıktı çok sayıda satır gösterir , ancak sorunun nerede olduğunu görmenize izin verebilir.

Aşağıdaki komut dosyasını çalıştırabilir ve sonuçları sorunuza gönderebilir misiniz? Sadece aynı sayfada olduğumuzdan emin olmaya çalışıyorum.

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
Çalıştırıldığında DBCC UPDATEUSAGEkullanı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!
Ken

0

Sütunlardan biri LOB tipi bir resimdir ve boyutu birkaç KB ile birkaç yüz MB arasında değişen dosyaları depolar

Dahili parçalanma yaşıyor olabilirsiniz. Bu tablo için sayfa parçalanması
nedir ? Ve satır içi parçalanma satır dışı sayfalardan farklı mı?

Birkaç KB'lik dosyalarınız olduğunu söylüyorsunuz.
SQL Server her şeyi 8060 Byte sayfada saklar. Yani, 4040 baytlık bir satırınız (veya satır dışı verileriniz) ve bir sonrakine benzerseniz, her ikisine de aynı sayfaya sığamaz ve alanınızın yarısını boşa harcarsınız. Değişken uzunluktaki sütunları (örneğin, resimle başlayın) farklı bir tabloda depolayarak satır boyutunuzu değiştirmeyi deneyin.


Sorunun parçalanma olduğunu düşünmüyorum. Dizinleri yeniden oluşturduktan sonra, kümelenmiş dizin için parçalanma% 0.45 ve sayfa dolgunluğu% 98.93'tür.
Ken

8KB sayfalara tam olarak sığmayan çok büyük satırlardan veya LOB verilerinden muzdaripseniz bir tabloyu veya dizini yeniden oluşturmak yardımcı olmaz. Max Vernon'un daha ayrıntılı olarak açıklaması: "kısmen boş sayfalarınız var." ayrıca iç parçalanma olarak da adlandırılır
DrTrunks Bell

-3

Veritabanı tam kurtarma modunda mı? Öyleyse, bir küçültme yaptığınızda, tüm değişiklikleri günlüğe kaydeder ve beklediğiniz şekilde küçültmez. Çalışma saatlerinize bağlı olarak, bir yedek alabilir, toplu gönderim kurtarma moduna geçebilir ve ardından veri dosyasında daralmayı çalıştırabilirsiniz. Bundan sonra, onarmak / yeniden oluşturmak ve tam kurtarmaya geri dönmek için dizin komut dosyalarını çalıştırmak istersiniz. Ben yine de denemek istiyorum ama yine de, tüm bunlar için çalışma saatlerine bağlıdır.


4
Kurtarma modelini getirmek ilginçtir. Ben OP günlük dosyasının boyutu ile ilgili sorunlar yaşıyorsanız daha uygulanabilir olacağını düşünüyorum . Olduğu gibi, veri dosyasının boyutu ile sorun yaşıyorsanız , bu yüzden kurtarma modeli açıklanan soruna neden oluyorsa şaşırırdım.
Josh Darnell

Doğru ama bir küçültme yaptığım ve alanı gerçekten etkilemediğim zamanlar kurtarma modeli yüzünden oldu, bu yüzden yanlış teşhis olması durumunda ortaya çıkmaya değer olduğunu düşündüm.
John-Henry Lochbaum

-3

Bir DB'yi küçültemediğim ve alanı geri kazanamadığım tek zaman, DB'yi oluşturulduğu zaman DB'nin ilk boyutunun ötesine küçültememenizdir. Örneğin, DB'niz üretim DB'sinin bir kopyasıysa ve DB'yi ilk önce 525GB'de oluşturduysanız, sql sunucusu, DB'den ne kadar veri sildiğiniz önemli değil, 525GB'ın altındaki boyutu küçültmenize izin vermez. Ancak, DB 383GB'ın altında oluşturulduysa ve daha sonra 525GB olarak büyüdüyse, alanı geri kazanmakta sorun yaşamamalısınız. Uzun zamandır bunun Microsoft tarafından aptalca ve keyfi bir kısıtlama olduğunu düşündüm.

Veritabanını yalnızca, veritabanı oluşturulduktan sonra ayarlanan başlangıç ​​boyutuna kadar küçült


Soru, bir veritabanını daraltmakla ilgili değil (ve eğer küçülme yeteneği, ilk büyüklük bölgesinden sonra kullanılan alana bağlıdır)
eckes

Kullanılmayan alan olduğu sürece, veritabanını orijinal boyutundan bağımsız olarak birkaç MB'ye küçültmek mümkündür. Mutlaka iyi bir fikir değil ama veritabanlarını küçültmek ve asla böyle bir sınıra girmek için pek çok fırsatım oldu.
Ray

-3

Daha önce üretim kutularında bu sorunla karşılaştım, yapmanız gereken her tablo için tabloları ve dizinleri (bu sırayla) yeniden oluşturmaktır.

İşte tabloları kontrol altında tutmak için kullandığım sorgu. Hangi tabloların yeniden oluşturulması gerektiğini belirlemenize ve çalıştırmanız gereken SQL sorgularını oluşturmanıza yardımcı olacaktır. Bu sorgu, 1 MB'tan daha fazla kullanılmayan alan ve% 5 kullanılmayan oranı olanlarla sınırlıdır, böylece yalnızca gerçekten odaklanmanız gerekenleri yeniden oluşturursunuz:

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

OP'nin yaptıklarını belirttiği gibi masayı yeniden inşa etmek, parçalanmaların çoğundan kurtulacaktır. Başka bir yeniden inşa yapmak daha fazla yardımcı olacaktır şüpheliyim.
Max Vernon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.