通过


MSDB 数据库在具有补充字符排序规则的 SQL Server 上增长

原始产品版本: SQL Server 12 及更高版本

症状

请参考以下方案:

  • 在 SQL Server 中使用系统数据库的补充字符安装了具有排序规则的实例。
  • 已配置管理数据仓库(MDW)和数据收集。

在此方案中,当数据收集创建的 SQL Server Integration Services (SSIS) 包运行时,你会发现 MSDB 数据库意外增长。

注意

此类排序规则名称以_SC结尾,例如 Latin1_General_100_CI_AS_SC

每 10 秒,以下 11 条警告消息将 msdb.dbo.sysssislog 插入系统表中:

由于从数据库列“task_state”检索数据(长度为 20 到数据流列“task_state”且长度为 10)而导致截断。

由于从数据库列“request_status”检索数据,长度为 30 的数据流列“request_status”,长度为 15,因此可能会发生截断。

由于从数据库列“session_status”检索数据(长度为 30 到数据流列“session_status”且长度为 15 的数据流列“session_status”)可能会发生截断。

由于从数据库列“host_name”检索数据(长度为 40 到数据流列“host_name”且长度为 20)而导致截断。

由于从数据库列“program_name”检索数据(长度为 100 到数据流列“program_name”且长度为 50)而导致截断。

截断可能是由于从数据库列“login_name”检索数据,其长度为 60 到数据流列“login_name”,长度为 30。

截断可能是由于从数据库列“wait_type”检索数据,长度为 60 到数据流列“wait_type”且长度为 45 的数据流列“wait_type”。

由于从数据库列“last_wait_type”检索数据,长度为 60 到数据流列“last_wait_type”的数据,长度为 45,则可能会出现截断。

由于从数据库列“wait_resource”检索数据(长度为 100 到数据流列“wait_resource”且长度为 50)而导致截断。

由于从数据库列“resource_description”检索数据(长度为 280 到数据流列“resource_description”且长度为 140)而导致截断。

ODS 的外部列 - 获取dm_exec_requests快照与数据源列同步。 需要更新外部列“task_state”。 需要更新外部列“request_status”。 需要更新外部列“session_status”。 需要更新外部列“host_name”。 需要更新外部列“program_name”。 需要更新外部列“login_name”。 需要更新外部列“wait_type”。 需要更新外部列“last_wait_type”。 需要更新外部列“wait_resource”。 需要更新外部列“resource_description”。

因此, msdb.dbo.sysssislog 表每 10 秒增长一页(8 KB)。 对磁盘空间的影响是:

  • 每小时 2.8 MB (8 KB x 6 x 60)
  • 每天 67.5 MB (8 KB x 6 x 60 x 24)
  • 每月 1.97 GB(8 KB x 6 x 60 x 24 x 30)

原因

使用补充字符的排序规则将更改某些动态管理视图(DMV)列的大小。 例如 sys.dm_exec_requests,数据收集器工具捕获某些 DMV 的内容,并使用 SSIS 包将结果添加到 MDW 数据库中。 在这些 SSIS 包中,根据排序规则的列大小(不使用补充字符)预定义列大小。 当包运行时,将为每个大小大于预定义大小的列返回警告消息,并将其添加到 msdb.dbo.sysssislog 表中。

注意

这些警告消息不会影响从 DMV 插入到数据收集表中的实际数据。

详细信息

数据收集过程在调用 sp_syscollector_snapshot_dm_exec_requests时收集第一个结果集的元数据。 以下 sql 脚本是一个示例:

exec [sys].sp_describe_first_result_set N'EXEC [msdb].[dbo].[sp_syscollector_snapshot_dm_exec_requests] 5',NULL,1

此调用返回不同的结果,具体取决于排序规则,使用补充字符或否:

  • 具有不使用补充字符的排序规则的实例:

    注意

    为了更加清楚起见,只显示受影响的行和列。

    列序号 name 是否可为 null 系统type_id 系统type_name 最大长度 排序规则名称
    11 task_state 1 231 nvarchar(10) 20 SQL_Latin1_General_CP1_CI_AS
    12 request_status 1 231 nvarchar(15) 30 SQL_Latin1_General_CP1_CI_AS
    13 session_status 1 231 nvarchar(15) 30 SQL_Latin1_General_CP1_CI_AS
    ...
    17 host_name 1 231 nvarchar(20) 40 SQL_Latin1_General_CP1_CI_AS
    18 program_name 1 231 nvarchar(50) 100 SQL_Latin1_General_CP1_CI_AS
    19 login_name 1 231 nvarchar(30) 60 SQL_Latin1_General_CP1_CI_AS
    20 wait_type 1 231 nvarchar(45) 90 SQL_Latin1_General_CP1_CI_AS
    21 last_wait_type 1 231 nvarchar(45) 90 SQL_Latin1_General_CP1_CI_AS
    22 wait_duration_ms 0 127 bigint 8 Null
    23 wait_resource 1 231 nvarchar(50) 100 SQL_Latin1_General_CP1_CI_AS
    24 resource_description 1 231 nvarchar(140) 280 SQL_Latin1_General_CP1_CI_AS
  • 具有使用补充字符的排序规则的实例:

    注意

    为了更加清楚起见,只显示受影响的行和列。

    列序号 name 是否可为 null 系统type_id 系统type_name 最大长度 排序规则名称
    11 task_state 1 231 nvarchar(20) 40 SQL_Latin1_General_CP1_CI_AS
    12 request_status 1 231 nvarchar(30) 60 SQL_Latin1_General_CP1_CI_AS
    13 session_status 1 231 nvarchar(30) 60 SQL_Latin1_General_CP1_CI_AS
    ...
    17 host_name 1 231 nvarchar(20) 40 SQL_Latin1_General_CP1_CI_AS
    18 program_name 1 231 nvarchar(100) 200 SQL_Latin1_General_CP1_CI_AS
    19 login_name 1 231 nvarchar(60) 120 SQL_Latin1_General_CP1_CI_AS
    20 wait_type 1 231 nvarchar(60) 120 SQL_Latin1_General_CP1_CI_AS
    21 last_wait_type 1 231 nvarchar(60) 120 SQL_Latin1_General_CP1_CI_AS
    23 wait_resource 1 231 nvarchar(50) 100 SQL_Latin1_General_CP1_CI_AS
    24 resource_description 1 231 nvarchar(280) 560 SQL_Latin1_General_CP1_CI_AS

这两个实例都显示某些列的差异。 例如,该 wait_type 列在标准排序规则上具有最大长度为 90 的 nvarchar(45) 的系统类型名称。 但是,使用补充字符的 排序规则具有 nvarchar(60) 的系统类型名称,最大长度为 120。 大小差异会导致 SSIS 包记录的警告消息。

解决方法

可以使用以下解决方法之一:

重要

如果使用解决方法 1 和解决方法 2,则任何现有登录名、作业或包都将丢失。 这些解决方法应仅在非生产环境中使用。

解决方法 1

使用排序规则卸载并重新安装 SQL Server 实例,而无需使用补充字符。

解决方法 2

使用排序规则重新生成系统数据库实例,而不使用补充字符。

解决方法 3

创建作业以从 msdb.dbo.sysssislog 表中删除不必要的警告。 在以下示例中,作业计划每小时运行一次。 可以通过更改 @freq_subday_interval 值来根据需要定义不同的计划。

例如,可以将值从 1 更改为 @freq_subday_interval 2,每两小时运行一次作业。

USE [msdb]
GO

/****** Object:  Job [Data Collection Warnings Cleanup]    Script Date: <Datetime> ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [[Uncategorized (Local)]]    Script Date: <Datetime> ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

END

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'Data Collection Warnings Cleanup',
              @enabled=1,
              @notify_level_eventlog=0,
              @notify_level_email=0,
              @notify_level_netsend=0,
              @notify_level_page=0,
              @delete_level=0,
              @description=N'This jobs removes uneccessary Data Colletion Warnings from msdb.dbo.sysssislog table. These warnings are logged when system uses a supplementary characters collation.',
              @category_name=N'[Uncategorized (Local)]',
              @owner_login_name=N'WIN-BINNHII7A8S\Administrator', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Delete warrnings]    Script Date: <Datetime> ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Delete warrnings',
              @step_id=1,
              @cmdexec_success_code=0,
              @on_success_action=1,
              @on_success_step_id=0,
              @on_fail_action=2,
              @on_fail_step_id=0,
              @retry_attempts=0,
              @retry_interval=0,
              @os_run_priority=0, @subsystem=N'TSQL',
              @command=N'set nocount on

declare @system_collation nvarchar(128)
declare @CountWarn1 int, @CountWarn2 int
declare @InfoMsg nvarchar(200)

select @system_collation = cast(SERVERPROPERTY(''collation'') as nvarchar(128))
set @CountWarn1 = 0
set @CountWarn2 = 0

if upper(right(@system_collation,2)) = ''SC''
   begin   -- we have a supplementary characters collation we need to remove unnecessary warnings from msdb.dbo.sysssislog table

   delete
              from msdb.dbo.sysssislog
              where event = ''OnWarning''
              and source like ''Set%Master_Package_Collection''
              and message like ''Truncation may occur%''

       Set @CountWarn1 = @@ROWCOUNT

       delete
              from msdb.dbo.sysssislog
              where event = ''OnWarning''
              and source like ''Set%Master_Package_Collection''
              and message like ''The external columns for ODS - Get snapshot of%''
       Set @CountWarn2 = @@ROWCOUNT

       set @InfoMsg = ''Data Collection warning clean up job deleted ''+ltrim(str(@CountWarn1+@CountWarn2,8))+'' warnings from msdb.dbo.sysssislog table.''

       print @InfoMsg

       end
',
              @database_name=N'master',
              @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Run every Hour',
              @enabled=1,
              @freq_type=4,
              @freq_interval=1,
              @freq_subday_type=8,
              @freq_subday_interval=1,
              @freq_relative_interval=0,
              @freq_recurrence_factor=0,
              @active_start_date=20201224,
              @active_end_date=99991231,
              @active_start_time=0,
              @active_end_time=235959,
              @schedule_uid=N'684bccd2-7424-4011-85d6-1d81791c53fe'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO