首页 > 数据库 >SQLServer删除数据库特别耗时

SQLServer删除数据库特别耗时

时间:2023-12-16 14:16:32浏览次数:35  
标签:set name 数据库 SQLServer msdb 耗时 backup id SELECT

在老库删除数据库的时候,如果选中到了选项"Delete backup and Restore History Information for databases"。发现删除操作要耗费很久的时间,甚至好几天。

查看一下正在执行的会话信息,看看数据库都在做啥:

 SELECT s.session_id
    ,r.STATUS
    ,r.blocking_session_id 'Blk by'
    ,r.wait_type
    ,wait_resource
    ,r.wait_time / (1000.0) 'Wait Sec'
    ,r.cpu_time
    ,r.logical_reads
    ,r.reads
    ,r.writes
    ,r.total_elapsed_time / (1000.0) 'Elaps Sec'
    ,Substring(st.TEXT, (r.statement_start_offset / 2) + 1, (
            (
                CASE r.statement_end_offset
                    WHEN - 1
                        THEN Datalength(st.TEXT)
                    ELSE r.statement_end_offset
                    END - r.statement_start_offset
                ) / 2
            ) + 1) AS statement_text
    ,Coalesce(Quotename(Db_name(st.dbid)) + N'.' + Quotename(Object_schema_name(st.objectid, st.dbid)) + N'.' + Quotename(Object_name(st.objectid, st.dbid)), '') AS command_text
    ,r.command
    ,s.login_name
    ,s.host_name
    ,s.program_name
    ,s.host_process_id
    ,s.last_request_end_time
    ,s.login_time
    ,r.open_transaction_count
FROM sys.dm_exec_sessions AS s
INNER JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
WHERE r.session_id != @@SPID
ORDER BY r.cpu_time DESC
    ,r.STATUS
    ,r.blocking_session_id
    ,s.session_id

可以看到,数据库一直在执行下面的SQL语句:

CREATE   PROCEDURE sp_delete_database_backuphistory    @database_name sysname  AS  BEGIN    SET NOCOUNT ON      DECLARE @backup_set_id TABLE      (backup_set_id INT)    DECLARE @media_set_id TABLE       (media_set_id INT)    DECLARE @restore_history_id TABLE (restore_history_id INT)      INSERT INTO @backup_set_id (backup_set_id)    SELECT DISTINCT backup_set_id    FROM msdb.dbo.backupset    WHERE database_name = @database_name      INSERT INTO @media_set_id (media_set_id)    SELECT DISTINCT media_set_id    FROM msdb.dbo.backupset    WHERE database_name = @database_name      INSERT INTO @restore_history_id (restore_history_id)    SELECT DISTINCT restore_history_id    FROM msdb.dbo.restorehistory    WHERE backup_set_id IN (SELECT backup_set_id                            FROM @backup_set_id)      BEGIN TRANSACTION      DELETE FROM msdb.dbo.backupfile    WHERE backup_set_id IN (SELECT backup_set_id                            FROM @backup_set_id)    IF (@@error > 0)      GOTO Quit      DELETE FROM msdb.dbo.backupfilegroup    WHERE backup_set_id IN (SELECT backup_set_id                            FROM @backup_set_id)    IF (@@error > 0)      GOTO Quit      DELETE FROM msdb.dbo.restorefile    WHERE restore_history_id IN (SELECT restore_history_id                                 FROM @restore_history_id)    IF (@@error > 0)      GOTO Quit      DELETE FROM msdb.dbo.restorefilegroup    WHERE restore_history_id IN (SELECT restore_history_id                                 FROM @restore_history_id)    IF (@@error > 0)      GOTO Quit      DELETE FROM msdb.dbo.restorehistory    WHERE restore_history_id IN (SELECT restore_history_id                                 FROM @restore_history_id)    IF (@@error > 0)      GOTO Quit      DELETE FROM msdb.dbo.backupset    WHERE backup_set_id IN (SELECT backup_set_id                            FROM @backup_set_id)    IF (@@error > 0)      GOTO Quit      DELETE msdb.dbo.backupmediafamily    FROM msdb.dbo.backupmediafamily bmf    WHERE bmf.media_set_id IN (SELECT media_set_id                               FROM @media_set_id)      AND ((SELECT COUNT(*)            FROM msdb.dbo.backupset            WHERE media_set_id = bmf.media_set_id) = 0)    IF (@@error > 0)      GOTO Quit      DELETE msdb.dbo.backupmediaset    FROM msdb.dbo.backupmediaset bms    WHERE bms.media_set_id IN (SELECT media_set_id                               FROM @media_set_id)      AND ((SELECT COUNT(*)            FROM msdb.dbo.backupset            WHERE media_set_id = bms.media_set_id) = 0)    IF (@@error > 0)      GOTO Quit      COMMIT TRANSACTION    RETURN    Quit:    ROLLBACK TRANSACTION  END  

检查sys.dm_exec_requests,可以看到cpu和io都在忙着做delete操作。虽然gui端看上去是卡住了,后台还是一直在做删除操作的。

 

那么为何这么慢呢?

首要要明白msdb都存放了哪些数据。MSDB存储SQL Server代理任务、历史记录、日程表、数据库邮件、服务代理、备份和还原历史记录。如果不进行定期清理、没有常规的维护操作,MSDB 的大小可能会变得很庞大。默认情况下,SQL Server 不会清除历史表中的数据。主要有以下一些表:

·backupfile
·backupfilegroup
·backupmediafamily
·backupmediaset
·backupset
·restorefile
·restorefilegroup
·restorehistory
接下来看看msdb库的大小。检查发现msdb库已经有33GB大小了。查看库中各个对象的大小:
USE[msdb]
GO
SELECT 
     t.name TableName
    ,s.name SchemaName
    ,p.ROWS TotalRows
    ,CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalMB
    ,CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedMB
FROM sys.tables t
INNER JOIN sys.indexes i ON t.OBJECT_ID = i.OBJECT_ID
INNER JOIN sys.partitions p ON i.OBJECT_ID = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.name IN 
('backupset','backupfile','backupfilegroup','backupmediafamily','backupmediaset','restorefile','restorefilegroup','restorehistory')
GROUP BY t.name, s.name, p.ROWS
ORDER BY TotalMB DESC, t.name
结果可以看到,与备份相关的表都很大了

如果表很大,可以看看每个月的历史记录。比如:

SELECT
     DATEPART(YEAR,[backup_start_date]) BackupYear
    ,DATEPART(MONTH,[backup_start_date]) BackupMonth
    ,COUNT(*) BackupCount
FROM [msdb].[dbo].[backupset]
GROUP BY DATEPART(YEAR,[backup_start_date]), DATEPART(MONTH,[backup_start_date])
ORDER BY BackupYear, BackupMonth

那么如何删除备份和还原记录呢?

官方提供了两个存储过程来修建这些表的大小。一个(sp_delete_backuphistory)用于根据日期删除备份和还原记录;一个(sp_delete_database_backuphistory)根据数据库名删除备份和还原记录。

例如:

-- delete all backup/restore history prior to a specified date
use msdb
go
exec sp_delete_backuphistory '2023-12-04' 
go
-- delete all backup history for a specific database 
use msdb
go
exec sp_delete_database_backuphistory 'test' 
go

在删除数据库的时候,如果同时选中了删除备份信息,就需用从上面这些表中删除指定库的对应记录。但是默认sqlserver没有给这些表创建合适的索引。从而导致在删除数据的时候,上面的存储过程执行特别慢。

查看一下msdb数据库上都有哪些索引:

SELECT t.name as [Table], ind.name as [Index], col.name as [Column], ind.type_desc [Index Type]
FROM sys.indexes ind
inner join sys.index_columns ic
    on ind.object_id = ic. object_id and ind.index_id = ic. index_id
inner join sys.columns col
    on ic.object_id = col.object_id and ic.column_id = col.column_id
inner join sys.tables t
    on ind.object_id = t. object_id WHERE ind.is_unique = 0 and ind. is_unique_constraint = 0
    and t.name in ( 'backupfile', 'backupfilegroup', 'backupmediafamily', 'backupmediaset', 'backupset', 'restorefile', 'restorefilegroup', 'restorehistory' ) ORDER BY t .name, ind.name

可以看到,只有这几个索引:

慢的问题,就可以通过在存储过程实用到的表列上新加一些索引来解决。比如:

/************************************************************************
* * Title: msdb index creation 
* * Author: Geoff N. Hiten 
* * Purpose: Index msdb database 
* * Date: 12/12/2005 
* * Modifications: * 
************************************************************************/ 
use msdb
go

--backupset 
Create index IX_backupset_backup_set_id on backupset(backup_set_id) 
go
Create index IX_backupset_backup_set_uuid on backupset(backup_set_uuid) 
go
Create index IX_backupset_media_set_id on backupset(media_set_id) 
go
Create index IX_backupset_backup_finish_date on backupset(backup_finish_date) 
go
Create index IX_backupset_backup_start_date on backupset(backup_start_date) 
go

--backupmediaset 
Create index IX_backupmediaset_media_set_id on backupmediaset(media_set_id) 
go

--backupfile 
Create index IX_backupfile_backup_set_id on backupfile(backup_set_id) 
go

--backupmediafamily 
Create index IX_backupmediafamily_media_set_id on backupmediafamily(media_set_id) 
go

--restorehistory 
Create index IX_restorehistory_restore_history_id on restorehistory(restore_history_id) 
go
Create index IX_restorehistory_backup_set_id on restorehistory(backup_set_id) 
go

--restorefile 
Create index IX_restorefile_restore_history_id on restorefile(restore_history_id) 
go

--restorefilegroup 
Create index IX_restorefilegroup_restore_history_id on restorefilegroup(restore_history_id) 
go
检查一下是否有数据库已经被删除,但是备份记录还保存在msdb库中
use msdb

SELECT database_name AS [Database], 
COUNT(backup_set_id) AS Orphans
FROM   backupset
WHERE  database_name NOT IN (SELECT name FROM master.dbo.sysdatabases)
GROUP BY database_name;

以下是批量删除的脚本:摘自https://sqlsolutionsgroup.com/how-to-clear-backup-history/

USE [msdb]
GO
/* user variables */
DECLARE  @DeleteRange NVARCHAR(100) = 'YEAR'    /* HOUR,DAY,WEEK,MONTH,YEAR */
        ,@Retain INT = 3                        /* same units as the @DeleteRange variable */
 
/* stuff we'll use later */
DECLARE  @DATE DATE
        ,@loop INT
        ,@SQL NVARCHAR(MAX)
        ,@BatchStart DATETIME = GETDATE()
        ,@DeleteDate DATETIME
 
/* create log table */
IF OBJECT_ID(N'msdb.dbo.BackupDeleteLog') IS NULL
BEGIN
    CREATE TABLE msdb.dbo.BackupDeleteLog
    (
     ID INT IDENTITY(1,1)
    ,BatchStart DATETIME
    ,LoopNumber INT
    ,DeleteDate DATETIME
    ,StartTime DATETIME
    ,FinishTime DATETIME
    )
END
 
/* find the number of loops we need to do based upon @DeleteRange and @retain */
SET @SQL = N'SELECT @loopOUT = DATEDIFF(' + @DeleteRange + ', MIN(backup_start_date),GETDATE()) FROM [msdb].[dbo].[backupset]'
EXEC SP_EXECUTESQL @SQL, N'@DeleteRange nvarchar(100), @loopOUT int OUTPUT', @DeleteRange = @DeleteRange, @loopOUT = @loop OUTPUT
 

/* delete backup history in batches */
WHILE @loop >= @retain
BEGIN
 
    SET @SQL = N'SELECT @DateOUT = DATEADD(' + @DeleteRange + ',-' + CONVERT(VARCHAR,@loop) + ',GETDATE())'
    EXEC SP_EXECUTESQL @SQL, N'@DeleteRange nvarchar(100), @DateOUT datetime OUTPUT', @DeleteRange = @DeleteRange, @DateOUT = @DeleteDate OUTPUT
 
    INSERT INTO msdb.dbo.BackupDeleteLog (BatchStart, LoopNumber, DeleteDate, StartTime)
    SELECT @BatchStart, @loop, @DeleteDate, GETDATE()
 
    --EXEC sp_delete_backuphistory @DeleteDate
    SELECT @DeleteDate
 
    UPDATE msdb.dbo.BackupDeleteLog SET FinishTime = GETDATE() WHERE LoopNumber = @loop AND BatchStart = @BatchStart
 
    SET @loop = @loop - 1
 
END
 
/* check what we've just deleted */
SELECT * FROM msdb.dbo.BackupDeleteLog WHERE BatchStart = @BatchStart

 

标签:set,name,数据库,SQLServer,msdb,耗时,backup,id,SELECT
From: https://www.cnblogs.com/abclife/p/17878180.html

相关文章

  • SQLServer 添加数据文件
    限制:1.backup语句正在运行时,不能添加或删除文件2.可以为每个数据库指定最多32767个文件和32767个文件组一、新增文件之前查看usetestselectfile_id,file_guid,type,type_desc,data_space_id,name,physical_name,state,state_descfromsys.database_filesSELECT......
  • 2014SQL附加数据库失败,操作系统错误 5:"5(拒绝访问。)"的解决办法
    点击数据库右键附加,出现如下错误  使用sql语句附加出现如下EXECsp_attach_db@dbname='你的数据库名',@filename1='mdf文件路径(包缀名)',@filename2='Ldf文件路径(包缀名)' 解决方法:找到xxx.MDF与xxx_log.LDF文件,右键-属性-安全-在组或用户名处添加AuthenticatedU......
  • 数据库同步工具,PanguSync后起之秀
    随着数字化时代的快速发展,数据已经成为企业运营的核心。为了确保数据的准确性和一致性,数据库同步工具成为了企业不可或缺的工具。而在众多数据库同步工具中,PanguSync以其卓越的性能和强大的功能,逐渐成为了行业中的后起之秀。 一、高效稳定的同步性能PanguSync以其高效稳定的......
  • openGauss学习笔记-160 openGauss 数据库运维-备份与恢复-导出数据-使用gs_dump和gs_d
    openGauss学习笔记-160openGauss数据库运维-备份与恢复-导出数据-使用gs_dump和gs_dumpall命令导出数据-导出所有数据库-导出全局对象160.1导出全局对象openGauss支持使用gs_dumpall工具导出所有数据库公共的全局对象,包含数据库用户和组、表空间及属性(例如:适用于数据库整体的......
  • Docker部署mysql5.7数据库
    1、拉取镜像dockerpullmysql:5.72、启动mysql5.7镜像dockerrun-p3306:3306--namemysql\-v/mydata/mysql/log:/var/log/mysql\-v/mydata/mysql/data:/var/lib/mysql\-v/mydata/mysql/conf:/etc/mysql\-eMYSQL_ROOT_PASSWORD=root\-dmysql:5.7参数说明......
  • spring boot启动耗时分析-spring-startup-analyzer使用
    github地址:https://github.com/linyimin0812/spring-startup-analyzer1、安装curl-sShttps://raw.githubusercontent.com/linyimin0812/spring-startup-analyzer/main/bin/install.sh|sh 2、maven<parent><groupId>io.github.linyimin0812</groupI......
  • 九、数据库设计的三范式
    一、数据库设计三范式二、数据库设计第一范式三、数据库设计第二范式四、数据库设计第三范式五、总结数据库表的设计六、以满足客户需求为准......
  • 【腾讯云云上实验室】用向量数据库在金融信用数据库分析中的实战运用
    一、前言这篇文章将带领读者探索数据库的多样化解决方案及其演进历程,特别关注向量数据库的重要性和在实际项目中的应用。通过深入剖析腾讯云向量数据库及其在金融信用数据库分析中的实战运用,为读者提供全面而实用的指南,帮助他们理解、应用和掌握这一技术领域的关键要点。二、数......
  • Win11无法启动SqlServer服务问题,SqlServer服务启动1067错误
    因为SQLServer当前支持512字节和4KB的扇区存储大小。所以需要将SqlServer安装到支持4KB的磁盘。以管理员权限运行PowerShell,执行fsutilfsinfosectorinfoC:命令查看各磁盘是否支持4kb存储查找以下字段值(单位为字节)PhysicalBytesPerSectorForAtomicityPhysicalBytesPe......
  • 第五十九天 Djando和数据库之间的联动
    一、表查询数据准备及测试环境搭建1.django自带一个sqlite3小型数据库 该数据库功能非常有限并且针对日期类型的数据兼容性很差2.django切换MySQL数据django1.X importpymysql pymysql.install_as_MySQLdb()django2.X3.X4.X pipinstallmysqlclient"""在服务器上启......