K09*_*K09 4 sql-server disk-space
我们的服务器管理员要求我释放 SQL 服务器上的磁盘空间,因为 SQL 数据文件所在的驱动器的使用率为 97%。
我发现了一张失控的桌子。它现在包含超过 3 亿行,所以我将设置一项工作以在一夜之间删除这些行。
我想避免 SHRINKFILE
,因为不推荐。
Ore*_*reo 10
首先,我会通过在您的 SQL Server 上运行一些可用空间诊断来确认服务器管理员看到了什么:
/* Get SQL Server Drive Usage Stats */
IF OBJECT_ID('master.sys.dm_os_volume_stats') IS NOT NULL
SELECT vs.volume_mount_point AS Drive, vs.file_system_type AS [Type]
,vs.logical_volume_name AS LogicalName
,MAX(CAST( 1.0*vs.total_bytes / 1073741824 AS DECIMAL(18,2)))AS[Drive Size (GB)]
,CAST(SUM( 1.0*size) / 128 / 1000 AS DECIMAL(18,2)) AS [SQL Size (GB)]
,MAX(CAST( 1.0*vs.available_bytes/1073741824 AS DECIMAL(18,2)))AS[Free Space (GB)]
,MIN(CAST(100.0*vs.available_bytes/vs.total_bytes AS DECIMAL(5,1)))AS[Free Space (%)]
FROM master.sys.master_files AS f WITH (NOLOCK)
CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.[file_id]) AS vs
GROUP BY vs.volume_mount_point, vs.file_system_type, vs.logical_volume_name
ORDER BY 1
OPTION (RECOMPILE);
SELECT Drive
,ISNULL([ROWS], 0) + ISNULL([LOG], 0)
+ ISNULL([TempROWS], 0) + ISNULL([TempLOG], 0)
AS 'TotalUsed (MB)'
,[ROWS] AS 'Data (MB)'
,[LOG] AS 'Logs (MB)'
,[TempROWS] AS 'TempData (MB)'
,[TempLOG] AS 'TempLogs (MB)'
FROM (
SELECT LEFT(Physical_Name, 3) 'Drive'
,CASE WHEN database_id = 2 THEN 'Temp' ELSE '' END + type_desc 'FileType'
,SUM(size) / 128 'SizeMB'
FROM master.sys.master_files
GROUP BY LEFT(Physical_Name, 3)
,CASE WHEN database_id = 2 THEN 'Temp' ELSE '' END + type_desc
) Results
PIVOT(SUM(SizeMB) FOR FileType IN ([ROWS], [LOG], [TempROWS], [TempLOG])) pvt
ORDER BY 1
OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)
然后检查问题驱动器上哪些文件最大/最差:
/* Get Individual Database Stats */
SELECT mf.database_id 'DB_ID'
,DB_NAME(mf.database_id) 'DBName'
,d.state_desc 'DBState'
,d.recovery_model_desc AS RecoveryModel
,CASE WHEN Log_ReUse_Wait_Desc = 'NOTHING' THEN ''
ELSE Log_ReUse_Wait_Desc END AS LogReUseWait
,mf.[File_ID]
,mf.NAME 'LogicalName'
,mf.type_desc 'Type'
,mf.Physical_Name
,mf.state_desc 'FileState'
,CAST(size / 128.0 + 0.5 AS INT) AS SizeMB
,CAST(max_size / 128.0 + 0.5 AS INT) AS MaxSizeMB
,CASE is_percent_growth
WHEN 0 THEN CAST(growth / 128 AS VARCHAR(10)) + ' MB'
ELSE CAST(growth AS VARCHAR(10)) + ' %' END AS 'AutoGrowth'
,CASE
WHEN d.STATE <> 6 /* 6 = OFFLINE */
AND mf.type_desc = 'ROWS'
AND mf.database_id <> 2 /* not TempDB */
THEN 'USE '+QUOTENAME(DB_NAME(mf.database_id))
+ '; DBCC SHRINKFILE(' + CAST(file_id AS VARCHAR(2))
+ ',1,TRUNCATEONLY);
GO'
ELSE '' END AS 'ShrinkTruncateOnlyCommand'
FROM [master].sys.master_files mf
LEFT JOIN [master].sys.databases d ON d.database_id = mf.database_id
WHERE 1 = 1
AND d.STATE <> 6 /* 6 = OFFLINE */
AND mf.database_id > 4 --user DBs only
--AND mf.database_id <= 4 --system DBs only
ORDER BY SizeMB DESC, DB_NAME(mf.database_id), [file_id]
OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)
在你走 SHRINKFILE 路线之前,你应该问自己一些更高层次的问题,比如:
SHRINKFILE
?由于您发现了一个包含可以(希望)删除数据的表(请与使用该数据的人核对!),请继续删除数据,如果您担心长时间锁定表,可以分批删除:
DELETE FROM <table> WHERE <pick the primary keys to delete in this batch>
Run Code Online (Sandbox Code Playgroud)
如果在删除旧的/无用的行后,表中还剩下有用的行,我会重建表的主键:
USE YourDB;
SELECT s.[Name] + '.' + t.[Name] AS ObjectName
,'ALTER INDEX [' + i.[Name] + '] ON [' + s.[Name] + '].[' + t.[Name] + '] REBUILD'
FROM sys.indexes i
JOIN sys.tables t ON i.object_id = t.object_id
AND i.type = 1 --clustered index
AND OBJECTPROPERTY(t.[object_id], 'IsUserTable') = 1
JOIN sys.schemas s ON s.schema_id = t.schema_id
--AND s.[Name] = 'YourSchema'
AND t.[Name] = 'YourTable'
ORDER BY 1
Run Code Online (Sandbox Code Playgroud)
...最后缩小数据库文件。我会先尝试使用TRUNCATEONLY选项,因为它比在 DB 文件中重新排列页面的普通 SHRINKFILE 更快/更安全:
/* Get Individual Database Stats */
SELECT d.Name DB
,mf.type_desc
,CASE
WHEN d.STATE <> 6 /* 6 = OFFLINE */
AND mf.type_desc = 'ROWS'
AND mf.database_id <> 2 /* not TempDB */
THEN 'USE '+QUOTENAME(DB_NAME(mf.database_id))
+ '; DBCC SHRINKFILE(' + CAST(file_id AS VARCHAR(2))
+ ',1,TRUNCATEONLY);'
ELSE ''
END AS 'ShrinkTruncateOnlyCommand'
FROM sys.master_files mf
LEFT JOIN sys.databases d ON d.database_id = mf.database_id
WHERE d.Name = 'YourDB'
AND mf.type_desc = 'ROWS' --data only
ORDER BY DB_NAME(mf.database_id), [file_id]
OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2355 次 |
最近记录: |