Upaya untuk mendapatkan kembali ruang yang tidak digunakan menyebabkan ruang yang digunakan meningkat secara signifikan di SQL Server

15

Saya memiliki tabel di database produksi yang memiliki ukuran 525 GB, di mana 383 GB tidak digunakan:

Ruang yang Tidak Terpakai

Saya ingin mendapatkan kembali sebagian ruang ini, tetapi, sebelum mengacaukan DB produksi, saya menguji beberapa strategi pada tabel yang sama dalam tes DB dengan lebih sedikit data. Tabel ini memiliki masalah serupa:

Ruang yang Tidak Terpakai

Beberapa informasi tentang tabel:

  • Faktor pengisian diatur ke 0
  • Ada sekitar 30 kolom
  • Salah satu kolom adalah LOB jenis gambar, dan itu menyimpan file dengan ukuran mulai dari beberapa KB hingga beberapa ratus MB
  • Tabel tidak memiliki indeks hipotetis yang terkait dengannya

Server menjalankan SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). Basis data menggunakan SIMPLEmodel pemulihan.

Beberapa hal yang saya coba:

  • Membangun kembali indeks: ALTER INDEX ALL ON dbo.MyTable REBUILD. Ini memiliki dampak yang dapat diabaikan.
  • Reorganisasi indeks: ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON). Ini memiliki dampak yang dapat diabaikan.
  • Menyalin kolom LOB ke tabel lain, menjatuhkan kolom, menciptakan kembali kolom, dan menyalin data kembali (seperti yang diuraikan dalam posting ini: Membebaskan Ruang SQL Server Tabel yang Tidak Terpakai ). Ini mengurangi ruang yang tidak digunakan, tetapi sepertinya hanya mengubahnya menjadi ruang yang digunakan:

    Ruang yang Tidak Terpakai

  • Menggunakan utilitas bcp untuk mengekspor tabel, memotongnya, dan memuatnya kembali (seperti diuraikan dalam posting ini: Cara membebaskan ruang yang tidak digunakan untuk sebuah tabel ). Ini juga mengurangi ruang yang tidak digunakan dan meningkatkan ruang yang digunakan ke tingkat yang sama seperti gambar di atas.

  • Meskipun tidak disarankan, saya mencoba perintah DBCC SHRINKFILE dan DBCC SHRINKDATABASE, tetapi tidak berdampak pada ruang yang tidak digunakan.
  • Berlari DBCC CLEANTABLE('myDB', 'dbo.myTable')tidak membuat perbedaan
  • Saya sudah mencoba semua hal di atas, sekaligus mempertahankan gambar dan tipe data teks dan setelah mengubah tipe data menjadi varbinary (max) dan varchar (max).
  • Saya mencoba mengimpor data ke tabel baru dalam database baru, dan ini juga hanya mengubah ruang yang tidak digunakan menjadi ruang yang digunakan. Saya menguraikan detail dari upaya ini di pos ini .

Saya tidak ingin melakukan upaya ini pada DB produksi jika ini adalah hasil yang dapat saya harapkan, jadi:

  1. Mengapa ruang yang tidak digunakan baru saja dikonversi ke ruang yang digunakan setelah beberapa upaya ini? Saya merasa tidak memiliki pemahaman yang baik tentang apa yang terjadi di bawah tenda.
  2. Apakah ada hal lain yang bisa saya lakukan untuk mengurangi ruang yang tidak digunakan tanpa menambah ruang yang digunakan?

EDIT: Inilah laporan Penggunaan Disk dan skrip untuk tabel:

Penggunaan Disk

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

Berikut adalah hasil dari mengeksekusi perintah dalam jawaban Max Vernon:

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

MEMPERBARUI:

Saya menjalankan yang berikut seperti yang disarankan oleh Max Vernon:

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

Dan inilah hasilnya:

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.

Ini memperbarui penggunaan disk untuk tabel:

masukkan deskripsi gambar di sini

Dan keseluruhan penggunaan disk:

masukkan deskripsi gambar di sini

Jadi, sepertinya masalahnya adalah bahwa penggunaan disk yang dilacak oleh SQL Server menjadi sangat tidak sinkron dengan penggunaan disk yang sebenarnya. Saya akan mempertimbangkan masalah ini terselesaikan, tetapi saya akan tertarik untuk mengetahui mengapa hal ini terjadi sejak awal!

Ken
sumber

Jawaban:

10

Saya menjalankan DBCC UPDATEUSAGE di atas meja sebagai langkah pertama, karena gejalanya menunjukkan penggunaan ruang yang tidak konsisten.

DBCC UPDATEUSAGE mengoreksi baris, halaman yang digunakan, halaman yang dipesan, halaman daun dan jumlah halaman data untuk setiap partisi dalam tabel atau indeks. Jika tidak ada ketidakakuratan dalam tabel sistem, UPDATEUSAGE DBCC tidak mengembalikan data. Jika ketidakakuratan ditemukan dan diperbaiki dan TANPA NO_INFOMSGS tidak digunakan, UPDATEUSAGE DBCC mengembalikan baris dan kolom yang diperbarui dalam tabel sistem.

Sintaksnya adalah:

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

Setelah Anda menjalankannya, saya akan berlari EXEC sys.sp_spaceusedmelawan meja:

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

Perintah di atas memiliki opsi untuk memperbarui penggunaan, tetapi karena Anda menjalankannya DBCC UPDATEUSAGEsecara manual terlebih dahulu, biarkan saja yang disetel ke false. Menjalankan DBCC UPDATEUSAGEsecara manual memungkinkan Anda untuk melihat apakah ada yang diperbaiki.

Kueri berikut akan menampilkan persentase byte gratis di tabel dan persentase halaman gratis di tabel. Karena kueri menggunakan fitur tidak berdokumen, tidak bijaksana untuk menghitung hasilnya, tetapi tampaknya akurat jika dibandingkan dengan output dari sys.sp_spaceused, pada level tinggi.

Jika persentase byte gratis secara signifikan lebih tinggi daripada persentase halaman gratis, maka Anda memiliki banyak halaman yang sebagian kosong.

Sebagian halaman yang kosong dapat berasal dari sejumlah penyebab, termasuk:

  1. Pemecahan halaman, di mana halaman harus dipisah untuk mengakomodasi sisipan baru ke dalam indeks berkerumun

  2. Ketidakmampuan untuk mengisi halaman dengan kolom karena ukuran kolom.

Kueri menggunakan sys.dm_db_database_page_allocationsfungsi manajemen dinamis tidak berdokumen :

;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

Outputnya seperti:

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

Saya menulis posting blog yang menjelaskan fungsi di sini .

Dalam skenario Anda, karena Anda telah dieksekusi ALTER TABLE ... REBUILD, Anda akan melihat jumlah yang sangat rendah untuk TotalEmptyPages, tapi aku menebak Anda masih akan memiliki sekitar 72% di BytesFreePercent.

Saya telah menggunakan CREATE TABLEskrip Anda untuk mencoba membuat ulang skenario Anda.

Ini adalah MCVE yang saya gunakan:

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

Kueri berikut menunjukkan satu baris untuk setiap halaman yang dialokasikan ke tabel, dan menggunakan DMV tidak berdokumen yang sama:

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

Output akan menampilkan banyak baris jika Anda menjalankannya terhadap tabel asli Anda di lingkungan pengujian Anda, tetapi ini memungkinkan Anda melihat di mana masalahnya.

Bisakah Anda menjalankan skrip berikut dan memposting hasil dalam pertanyaan Anda? Saya hanya berusaha memastikan kita berada di halaman yang sama.

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;
Max Vernon
sumber
2
Menjalankan DBCC UPDATEUSAGEmemperbarui ruang yang tidak digunakan dan jumlah halaman yang tidak digunakan. Sepertinya penggunaan disk dan informasi halaman yang dilaporkan oleh SQL Server sangat tidak sinkron - Saya memperbarui posting saya dengan detailnya. Saya ingin tahu tentang bagaimana ini akan terjadi di tempat pertama, tetapi setidaknya masalah ditemukan. Terima kasih atas semua bantuan Anda, saya sangat menghargainya!
Ken
0

Salah satu kolom adalah LOB jenis gambar, dan itu menyimpan file dengan ukuran mulai dari beberapa KB hingga beberapa ratus MB

Anda bisa mengalami fragmentasi internal.
Apa fragmentasi halaman untuk tabel ini?
Dan apakah fragmentasi untuk baris berbeda dari halaman baris kosong?

Anda mengatakan Anda memiliki file yang beberapa KB.
SQL Server menyimpan semuanya di halaman 8060 Byte. Artinya, jika Anda memiliki baris (atau data tidak-baris) yaitu 4040 byte dan yang berikutnya serupa, itu tidak dapat masuk dalam halaman yang sama dan Anda akan menghabiskan setengah ruang Anda. Coba ubah ukuran baris Anda dengan menyimpan kolom panjang variabel (mulai dengan gambar misalnya) di tabel yang berbeda.

DrTrunks Bell
sumber
Saya tidak berpikir fragmentasi adalah masalahnya. Setelah membangun kembali indeks, fragmentasi untuk indeks berkerumun adalah 0,45% dan kepenuhan halamannya adalah 98,93%.
Ken
Membangun kembali tabel atau indeks tidak akan membantu jika Anda menderita baris yang sangat besar atau data LOB yang tidak sesuai dengan halaman 8KB dengan baik. Itulah yang dijelaskan Max Vernon secara lebih terperinci: "Anda memiliki banyak halaman yang sebagian kosong." juga disebut fragmentasi internal
DrTrunks Bell
-3

Apakah database dalam mode pemulihan penuh? Jika demikian, saat Anda melakukan psikiater, itu mencatat semua perubahan dan tidak akan menyusutkan seperti yang Anda harapkan. Tergantung pada jam operasi Anda, Anda bisa mengambil cadangan, beralih ke mode pemulihan pengiriman massal dan kemudian menjalankan menyusut pada file data. Setelah itu, Anda ingin menjalankan skrip indeks untuk memperbaiki / membangun kembali dan kembali ke pemulihan penuh. Itulah yang akan saya coba, tetapi sekali lagi, itu tergantung pada jam operasi Anda untuk semua ini.

John-Henry Lochbaum
sumber
4
Memunculkan model pemulihan itu menarik. Saya pikir itu akan lebih berlaku jika OP mengalami masalah dengan ukuran file log mereka . Seperti berdiri, mereka mengalami masalah dengan ukuran file data, jadi saya akan terkejut jika model pemulihan menyebabkan masalah yang dijelaskan.
Josh Darnell
Benar, tetapi satu-satunya saat saya menjalankan psikiater dan itu tidak benar-benar berdampak pada ruang adalah karena model pemulihan, jadi saya pikir itu layak dibesarkan kalau-kalau itu salah diagnosis.
John-Henry Lochbaum
-3

Satu-satunya saat saya tidak dapat mengecilkan DB dan mendapatkan kembali ruang karena Anda tidak dapat mengecilkan DB di luar ukuran awal DB saat dibuat. Jadi misalnya, jika DB Anda adalah salinan dari DB produksi dan Anda pertama kali membuat DB pada 525GB, sql server tidak akan memungkinkan Anda untuk mengecilkan ukuran di bawah 525GB tidak peduli berapa banyak data yang Anda hapus dari DB. Tetapi jika DB dibuat di bawah 383GB dan kemudian tumbuh menjadi 525GB Anda seharusnya tidak mengalami kesulitan untuk mendapatkan kembali ruang tersebut. Saya sudah lama berpikir ini adalah pembatasan bodoh dan sewenang-wenang oleh Microsoft.

Kecilkan basis data hanya hingga ukuran awalnya yang ditetapkan setelah membuat basis data

ZyxwvuTJ
sumber
Pertanyaannya bukan tentang menyusutkan database (dan jika itu, kemampuan untuk mengecilkannya tergantung pada ruang yang digunakan setelah wilayah ukuran awal)
eckes
Selama ada ruang yang tidak digunakan, dimungkinkan untuk mengecilkan basis data menjadi beberapa MB terlepas dari ukuran aslinya. Ini tidak selalu merupakan ide yang baik tetapi saya memiliki banyak kesempatan untuk mengecilkan basis data dan tidak pernah mengalami batas seperti ini.
Ray
-3

Saya pernah mengalami masalah ini sebelumnya pada kotak produksi, yang perlu Anda lakukan adalah membangun kembali tabel dan indeks untuk setiap tabel (dalam urutan itu).

Inilah kueri yang saya gunakan untuk menjaga tabel di cek. Ini akan membantu Anda menentukan tabel mana yang perlu dibangun kembali, dan membuat query SQL yang perlu Anda jalankan. Kueri ini terbatas pada yang memiliki ruang lebih dari 1MB yang tidak digunakan dan rasio 5% yang tidak digunakan, sehingga Anda hanya membangun kembali apa yang benar-benar Anda butuhkan untuk fokus:

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
Luis Alberto Barandiaran
sumber
membangun kembali tabel, seperti yang telah dilakukan OP, akan menghilangkan sebagian besar fragmentasi. Saya ragu melakukan pembangunan kembali yang lain akan membantu lebih lanjut.
Max Vernon