Làm thế nào để giải phóng không gian không sử dụng cho một bảng


8

Câu hỏi này được hỏi như hàng chục lần, và thật ngạc nhiên, một yêu cầu đơn giản như vậy lại trở nên khó khăn. Tuy nhiên, tôi không thể giải quyết vấn đề này.

Tôi sử dụng phiên bản SQL Server 2014 Express với giới hạn 10GB kích thước cơ sở dữ liệu (không phải kích thước nhóm tệp, kích thước cơ sở dữ liệu).

Tôi đã thu thập tin tức và chèn HTML vào một bảng. Lược đồ của bảng là:

Id bigint identity(1, 1) primary key,
Url varchar(250) not null,
OriginalHtml nvarchar(max),
...

Cơ sở dữ liệu hết kích thước và tôi nhận được insufficient disk space

Tất nhiên thu hẹp cơ sở dữ liệu và filegroup đã không giúp đỡ. DBCC SHRINKDATABASEđã không giúp đỡ. Vì vậy, tôi đã viết một ứng dụng đơn giản để đọc từng bản ghi, loại bỏ một số phần không mong muốn của OriginalHtmlphần đầu giống như và phần chân trang để chỉ giữ phần thân chính và bây giờ tôi thấy hình ảnh này khi nhận được báo cáo về việc sử dụng đĩa theo bảng trên cùng:

nhập mô tả hình ảnh ở đây

Theo tôi hiểu bức tranh này, không gian chưa sử dụng hiện chiếm 50% tổng kích thước. Đó là, bây giờ tôi có 5 GB dung lượng chưa sử dụng. Nhưng tôi không thể đòi lại nó. Xây dựng lại các chỉ số đã không giúp đỡ. Các truncateonlytùy chọn sẽ không giúp đỡ bởi vì như tôi hiểu không có hồ sơ sẽ bị xóa, chỉ có kích thước của mỗi bản ghi là giảm.

Tôi bị mắc kẹt tại thời điểm này. Xin hãy giúp đỡ, tôi nên làm gì?

Chỉ số cụm là trên cột Id.

Đây là kết quả của EXECUTE sys.sp_spaceused @objname = N'dbo.Articles', @updateusage = 'true';

name        rows     reserved     data        index_size   unused
----------- -------- ------------ ----------- ------------ -----------
Articles    112258   8079784 KB   5199840 KB  13360 KB     2866584 KB 

Câu trả lời:


10

Tất cả mọi thứ đều bằng nhau, nó phải đủ để nén cột đối tượng lớn (LOB) OriginalHTML. Bạn không chỉ định tên chỉ mục được nhóm trong câu hỏi, vì vậy:

ALTER INDEX ALL
ON dbo.Articles
REORGANIZE 
WITH (LOB_COMPACTION = ON);

Xem ALTER INDEX (Transact-SQL)

Nếu bạn có tên chỉ mục được nhóm (không chỉ (các) cột được phân cụm), hãy thay thế tên ALLtrên bằng tên đó.

Các LOB_COMPACTIONgiá trị mặc định tùy chọn để ON, nhưng không có thiệt hại trong việc rõ ràng. Bạn có thể cần phải chạy REORGANIZEliên tục để hoàn tất việc lấy lại tất cả các không gian chưa sử dụng.

Thật không may, cách tổ chức dữ liệu LOB và cách triển khai nén LOB có nghĩa là phương pháp này có thể không phải lúc nào cũng có thể lấy lại tất cả không gian chưa sử dụng, bất kể bạn chạy nó bao nhiêu lần. Nó cũng có thể rất chậm.

Bạn cũng có thể thử phương thức trong Bảng Máy chủ SQL không gian không sử dụng miễn phí có liên quan

Nếu vì lý do nào đó, những điều trên không phù hợp với bạn, hãy xuất dữ liệu vào một tệp, cắt bớt bảng, sau đó tải lại . Có một số phương pháp để đạt được điều đó, ví dụ như tiện ích bcp .

Thí dụ

Sau đây tạo một bảng có 10.000 hàng rộng:

CREATE TABLE dbo.Test 
(
    c1 bigint IDENTITY NOT NULL, 
    c2 nvarchar(max) NOT NULL,

    CONSTRAINT PK_dbo_Test
        PRIMARY KEY CLUSTERED (c1)
);

-- Load 10,000 wide rows
INSERT dbo.Test WITH (TABLOCKX)
    (c2)
SELECT TOP (10000)
    REPLICATE(CONVERT(nvarchar(max), 'X'), 50000)
FROM master.sys.columns AS C1
CROSS JOIN master.sys.columns AS C2;

Chúng ta có thể thấy việc sử dụng không gian bằng sys.dm_db_index_physical_statsDMV:

SELECT
    DDIPS.index_id,
    DDIPS.partition_number,
    DDIPS.index_type_desc,
    DDIPS.index_depth,
    DDIPS.index_level,
    DDIPS.page_count,
    DDIPS.avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats
(
    DB_ID(),
    OBJECT_ID(N'dbo.Test', N'U'),
    1,
    NULL,
    'DETAILED'
) AS DDIPS
WHERE 
    DDIPS.alloc_unit_type_desc = N'LOB_DATA';

Đầu ra DMV

Bây giờ chúng tôi cập nhật nội dung LOB lên kích thước nhỏ hơn (nhưng vẫn yêu cầu lưu trữ ngoài hàng):

-- Change LOB data to a smaller value (that will not move in-row)
UPDATE dbo.Test WITH (TABLOCKX)
SET c2 = REPLICATE(CONVERT(nvarchar(max), 'Y'), 5000);

Đầu ra DMV

Lưu ý rằng một số không gian đã được thu hồi, nhưng các trang còn lại ít hơn nhiều so với trước đây.

Chúng tôi có thể nén không gian LOB bằng cách sử dụng:

ALTER INDEX PK_dbo_Test ON dbo.Test 
REORGANIZE 
WITH (LOB_COMPACTION = ON);

Đầu ra DMV

Điều này dẫn đến một số nén và tiết kiệm không gian, nhưng nó không hoàn hảo. Chạy lại nén có thể hoặc không thể cải thiện tình hình. Trong thử nghiệm của tôi, nó đã không, bất kể bao nhiêu lần tôi chạy lại nó.

Xuất, cắt, tải lại

Một cách để làm điều này hoàn toàn từ Management Studio liên quan đến việc sử dụng xp_cmdshellđể xuất dữ liệu bảng vào một tệp. Nếu xp_cmdshellhiện không được bật, những điều sau đây sẽ làm điều đó:

-- Enable xp_cmdshell if necessary
EXECUTE sys.sp_configure
    @configname = 'show advanced options',
    @configvalue = 1;

RECONFIGURE;

EXECUTE sys.sp_configure
    @configname = 'xp_cmdshell',
    @configvalue = 1;

RECONFIGURE;

Bây giờ chúng ta có thể thực hiện xuất khẩu:

-- Export table
EXECUTE sys.xp_cmdshell
    'bcp Sandpit.dbo.Test out c:\temp\Test.bcp -n -S .\SQL2017 -T';

Lưu ý bạn sẽ cần thay đổi đường dẫn và -Stên máy chủ và có thể cung cấp thông tin đăng nhập.

Làm thế nào chúng ta có thể cắt bớt bảng và tải lại bằng cách sử dụng BULK INSERT:

-- Truncate
TRUNCATE TABLE dbo.Test;

-- Switch to BULK_LOGGED recovery model if currently set to FULL
-- Bulk load
BULK INSERT dbo.Test
FROM 'c:\temp\Test.bcp' 
WITH 
(
    DATAFILETYPE = 'widenative', 
    ORDER (c1), 
    TABLOCK,
    KEEPIDENTITY
);

Bước cuối cùng là thiết lập lại hạt giống nhận dạng:

-- Check and reseed identity
DBCC CHECKIDENT('dbo.Test', RESEED);

Chuỗi hoạt động này thường nhanh hơn so với nén LOB và phải luôn tạo ra kết quả tối ưu:

Đầu ra DMV

Ở trên không hoàn toàn hiệu quả như có thể là do lỗi đã tồn tại từ lâu: BULK INSERT với cột IDENTITY tạo kế hoạch truy vấn với SORT . Cách giải quyết được liệt kê ở đó là hiệu quả, nhưng tôi sẽ chỉ bận tâm với nó nếu bảng rất lớn.

Đừng quên xóa tệp tạm thời được sử dụng để giữ dữ liệu đã xuất.

Tất nhiên bạn được tự do sử dụng bất kỳ cách tiếp cận xuất / nhập số lượng lớn nào thuận tiện nhất cho bạn. Nó không bắt buộc phải sử dụng xp_cmdshellhoặc bcp.

Ghi chú bổ sung:

  • FILLFACTORchỉ áp dụng cho các trang chỉ mục . Nó không ảnh hưởng đến lưu trữ LOB ngoài hàng (không được lưu trữ trên các trang chỉ mục).
  • Nén hàng và trang không có sẵn để lưu trữ ngoài hàng.
  • Thay vào đó, bạn có thể nén và giải nén dữ liệu một cách rõ ràng bằng cách sử dụng COMPRESSvà các DECOMPRESSchức năng có sẵn từ SQL Server 2016.

    Tùy chọn cho những người sử dụng SQL Server 2014 (trường hợp ở đây) hoặc cũ hơn (xuống SQL Server 2005) để có cùng chức năng nén được cung cấp bởi các hàm COMPRESSDECOMPRESShàm tích hợp là sử dụng SQLCLR. Các hàm dựng sẵn chỉ thực hiện điều này có sẵn trong phiên bản SQL # miễn phí được viết bởi Solomon Rutzky . Các hàm Util_GZipUtil_GUnzip phải tương ứng với COMPRESSDECOMPRESS, tương ứng. Và, bất cứ ai sử dụng SQL Server 2012 hoặc mới hơn nên đảm bảo rằng máy chủ đang chạy SQL Server được cập nhật với .NET Framework phiên bản 4.5 trở lên để thuật toán nén được cải thiện nhiều sẽ được sử dụng.


1

Nếu bạn có thể nâng cấp lên SQL Server Express 2016 SP1 trở lên, bạn có thể nhận được một khoản tiết kiệm không gian rất lớn bằng cách sử dụng DỮ LIỆU DỮ LIỆU .

Bạn có thể có những thứ khác đang làm hỏng cơ sở dữ liệu của bạn, tuy nhiên, như nhận xét của Dan Guzman, bạn nên kiểm tra hệ số lấp đầy trên tất cả các chỉ mục của mình.

Bất cứ điều gì khác 0 (không) hoặc 100 có nghĩa là, khi chỉ mục được tạo (hoặc được xây dựng lại), SQL Server chỉ điền vào mỗi trang tối đa tỷ lệ phần trăm của hệ số điền. Vì vậy, ví dụ, nếu bạn có hệ số lấp đầy là 50, chỉ 50% trang sẽ được lấp đầy trong quá trình tạo / xây dựng lại chỉ mục, về cơ bản sẽ tăng gấp đôi dung lượng cần thiết để giữ dữ liệu.

Kéo một truy vấn từ bài viết Tìm các yếu tố điền cho các chỉ mục trong cơ sở dữ liệu máy chủ SQL

Nếu bạn muốn tìm tất cả các chỉ mục cho tất cả các bảng người dùng trong cơ sở dữ liệu SQL Server có hệ số điền khác 0 hoặc 100:

SELECT DB_NAME() AS Database_Name
, sc.name AS Schema_Name
, o.name AS Table_Name
, o.type_desc
, i.name AS Index_Name
, i.type_desc AS Index_Type
, i.fill_factor
FROM sys.indexes i
INNER JOIN sys.objects o ON i.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE i.name IS NOT NULL
AND o.type = 'U'
AND i.fill_factor not in (0, 100)
ORDER BY i.fill_factor DESC, o.name

Thông tin bổ sung có giá trị liên quan đến yếu tố điền có thể được tìm thấy tại

5 điều về Fillfactor

Kết quả Blitz: Yếu tố điền (%)


2
Một lưu ý quan trọng về DATA_COMPRESSION. Nén sẽ không nén dữ liệu được lưu trữ ngoài hàng, chẳng hạn như dữ liệu LOB hoặc dữ liệu ROW_OVERFLOW. Trong trường hợp này, chỉ các cột ID & URL sẽ nén - có thể không tiết kiệm đáng kể. Tuy nhiên, năm 2016 cũng giới thiệu COMPRESS()chức năng, cho phép OP sử dụng thuật toán gzip để nén dữ liệu OriginalHTML trong bảng.
AMtwo

Cảm ơn bạn cho truy vấn đó. Tôi đã thực hiện nó, và không có kết quả nào được trả về. Vì vậy, không có yếu tố điền nào ngoài 0 hoặc 100.
Saeed Neamati
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.