Tôi có một bảng trong cơ sở dữ liệu sản xuất có kích thước 525 GB, trong đó 383 GB không được sử dụng:
Tôi muốn lấy lại một số không gian này, nhưng, trước khi làm hỏng DB sản xuất, tôi đang thử nghiệm một số chiến lược trên một bảng giống hệt nhau trong một DB thử nghiệm với ít dữ liệu hơn. Bảng này có một vấn đề tương tự:
Một số thông tin về bảng:
- Hệ số lấp đầy được đặt thành 0
- Có khoảng 30 cột
- Một trong các cột là LOB loại hình ảnh và nó lưu trữ các tệp có kích thước từ vài KB đến vài trăm MB
- Bảng không có bất kỳ chỉ mục giả định nào liên quan đến nó
Máy chủ đang chạy SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). Cơ sở dữ liệu đang sử dụng SIMPLE
mô hình phục hồi.
Một số điều tôi đã thử:
- Xây dựng lại các chỉ mục :
ALTER INDEX ALL ON dbo.MyTable REBUILD
. Điều này đã có một tác động không đáng kể. - Sắp xếp lại các chỉ mục :
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
. Điều này đã có một tác động không đáng kể. Sao chép cột LOB sang một bảng khác, bỏ cột, tạo lại cột và sao chép dữ liệu trở lại (như được nêu trong bài đăng này: Giải phóng Bảng máy chủ SQL không gian không sử dụng ). Điều này làm giảm không gian không sử dụng, nhưng dường như chỉ chuyển đổi nó thành không gian đã sử dụng:
Đã sử dụng tiện ích bcp để xuất bảng, cắt bớt nó và tải lại nó (như được nêu trong bài đăng này: Cách giải phóng không gian không sử dụng cho một bảng ). Điều này cũng làm giảm không gian không sử dụng và tăng không gian sử dụng đến một mức độ tương tự như hình ảnh trên.
- Mặc dù điều đó không được khuyến khích, tôi đã thử các lệnh DBCC SHRINKFILE và DBCC SHRINKDATABASE, nhưng chúng không có bất kỳ tác động nào đến không gian không sử dụng.
- Chạy
DBCC CLEANTABLE('myDB', 'dbo.myTable')
không làm nên sự khác biệt - Tôi đã thử tất cả các cách trên cả hai trong khi duy trì các kiểu dữ liệu hình ảnh và văn bản và sau khi thay đổi các kiểu dữ liệu thành varbinary (max) và varchar (max).
- Tôi đã thử nhập dữ liệu vào một bảng mới trong cơ sở dữ liệu mới và điều này cũng chỉ chuyển đổi không gian chưa sử dụng thành không gian đã sử dụng. Tôi đã phác thảo chi tiết về nỗ lực này trong bài viết này .
Tôi không muốn thực hiện những nỗ lực này trên DB sản xuất nếu đây là những kết quả tôi có thể mong đợi, vì vậy:
- Tại sao không gian chưa sử dụng chỉ được chuyển đổi thành không gian đã sử dụng sau một số nỗ lực này? Tôi cảm thấy mình không hiểu rõ về những gì đang diễn ra dưới mui xe.
- Có cách nào khác tôi có thể làm để giảm không gian không sử dụng mà không tăng không gian sử dụng không?
EDIT: Đây là báo cáo và kịch bản sử dụng đĩa cho bảng:
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
Dưới đây là kết quả thực hiện các lệnh trong câu trả lời của Max Vernon:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
CẬP NHẬT:
Tôi đã chạy như sau theo đề xuất của Max Vernon:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
Và đây là đầu ra:
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.
Điều này cập nhật việc sử dụng đĩa cho bảng:
Và việc sử dụng đĩa tổng thể:
Vì vậy, có vẻ như vấn đề là việc sử dụng đĩa được theo dõi bởi SQL Server trở nên không đồng bộ với việc sử dụng đĩa thực tế. Tôi sẽ xem xét vấn đề này được giải quyết, nhưng tôi muốn biết tại sao điều này lại xảy ra ngay từ đầu!
DBCC CHECKDB
không? Bạn đã xem xét di chuyển ra khỏi các loại dữ liệu không dùng nữa , text
và image
? Họ có thể đang đóng góp cho các số liệu thống kê không phù hợp.