news 2026/6/10 17:27:46

Linux 环境下 SQL Server 自动收缩日志作业创建脚本(Shell 版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 环境下 SQL Server 自动收缩日志作业创建脚本(Shell 版)

随着SQL Server在Linux平台的普及,很多运维人员需要在Linux服务器上实现数据库日志的自动收缩。本文将原SQL脚本改造为适配Linux环境的Shell脚本,兼容SQL Server 2017及以上Linux版本(2017/2019/2022),保留全版本适配、安全合规、易维护的核心特性,同时贴合Linux系统的操作习惯。

一、完整Shell脚本

#!/bin/bash# =========================================================================# 脚本名称:sqlserver_shrink_log_job.sh# 适用环境:Linux + SQL Server 2017/2019/2022(x64)# 前置条件:# 1. Linux服务器已安装SQL Server,且启动sqlserver服务# 2. 已安装sqlcmd工具(/opt/mssql-tools/bin/sqlcmd)# 3. master库已创建dbo.ShrinkUser_DATABASESLogFile存储过程# 4. 执行脚本的Linux用户具备执行sqlcmd的权限# 核心功能:在Linux的SQL Server中创建自动收缩日志的定时作业# 作者:运维研发组# 日期:2025-12-16# =========================================================================set-euo pipefail# Shell严格模式:未定义变量报错、管道失败则脚本退出# ======================== 自定义配置参数(根据实际需求修改) ========================exportSQL_SERVER="localhost"# SQL Server实例地址(本地填localhost,远程填IP/主机名)exportSQL_USER="sa"# SQL登录账户(建议替换为低权限运维账户)# 建议通过环境变量传入密码,避免硬编码(执行前执行:export SQL_PWD="你的密码")# export SQL_PWD="YourStrongPassword" # 注释:生产环境请勿直接写入脚本!exportJOB_NAME="ShrinkFile_DB_Logfile"# 作业名称exportJOB_CATEGORY="Database Maintenance"# 作业分类exportSCHEDULE_NAME="Shrink_DB_Logfile_Schedule"# 调度名称exportDAILY_EXEC_TIME="050000"# 每日执行时间(HHMMSS,050000=凌晨5点)exportDELETE_EXIST_JOB="1"# 是否删除已存在的同名作业(1=删除,0=不删除)exportNOTIFY_LEVEL="2"# 作业失败时记录事件日志(0=不记录,2=失败记录)# ======================== 依赖检查 ========================# 检查sqlcmd是否安装if!command-v /opt/mssql-tools/bin/sqlcmd&>/dev/null;thenecho"【错误】未找到sqlcmd工具,请先安装:sudo apt-get install mssql-tools unixodbc-dev(Debian/Ubuntu)或 sudo yum install mssql-tools unixODBC-devel(RHEL/CentOS)"exit1fi# 检查密码是否传入if[-z"${SQL_PWD:-}"];thenecho"【错误】未设置SQL_PWD环境变量,请执行:export SQL_PWD='你的SQL账户密码' 后再运行脚本"exit1fi# 检查SQL Server服务是否运行(可选)if!systemctl is-active --quiet mssql-server;thenecho"【警告】SQL Server服务未运行,建议先启动:sudo systemctl start mssql-server"read-p"是否继续执行脚本?(y/n) "-n1-rechoif[[!$REPLY=~ ^[Yy]$]];thenexit1fifi# ======================== 构建TSQL脚本内容 ========================TSQL_SCRIPT=$(cat<<EOF SET NOCOUNT ON;SET XACT_ABORT ON;-- 检查依赖的收缩存储过程是否存在 IF NOT EXISTS(SELECT1FROM master.sys.objects WHERE name=N'ShrinkUser_DATABASESLogFile'ANDtype=N'P'AND schema_id=SCHEMA_ID(N'dbo'))BEGIN RAISERROR(N'前置条件不满足:master库中未找到dbo.ShrinkUser_DATABASESLogFile存储过程!',16,1);RETURN;END;-- 检查并处理已存在的同名作业 IF EXISTS(SELECT1FROM msdb.dbo.sysjobs WHERE name=N'$JOB_NAME')BEGIN IF$DELETE_EXIST_JOB=1BEGIN EXEC msdb.dbo.sp_delete_job @job_name=N'$JOB_NAME', @delete_unused_schedules=1;PRINT N'已删除同名作业:$JOB_NAME';END ELSE BEGIN RAISERROR(N'作业【%s】已存在,若需重新创建请将DELETE_EXIST_JOB设为1',16,1,N'$JOB_NAME');RETURN;END END BEGIN TRY BEGIN TRANSACTION;-- 创建作业分类(若不存在) IF NOT EXISTS(SELECT1FROM msdb.dbo.syscategories WHERE name=N'$JOB_CATEGORY'AND category_class=1)BEGIN DECLARE @ReturnCode INT=0;EXEC @ReturnCode=msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'$JOB_CATEGORY';IF @ReturnCode<>0BEGIN RAISERROR(N'创建作业分类【%s】失败,返回码:%d',16,1,N'$JOB_CATEGORY',@ReturnCode);END PRINT N'已创建作业分类:$JOB_CATEGORY';END -- 创建核心作业 DECLARE @JobId BINARY(16), @ReturnCode INT=0;EXEC @ReturnCode=msdb.dbo.sp_add_job @job_name=N'$JOB_NAME', @enabled=1, @notify_level_eventlog=$NOTIFY_LEVEL, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'Linux环境自动收缩用户数据库日志文件(适配SQL Server Linux版),依赖master.dbo.ShrinkUser_DATABASESLogFile存储过程', @category_name=N'$JOB_CATEGORY', @owner_login_name=N'$SQL_USER', @job_id=@JobId OUTPUT;IF @ReturnCode<>0BEGIN RAISERROR(N'创建作业【%s】失败,返回码:%d',16,1,N'$JOB_NAME',@ReturnCode);END PRINT N'已创建作业主体:$JOB_NAME';-- 添加作业执行步骤 EXEC @ReturnCode=msdb.dbo.sp_add_jobstep @job_id=@JobId, @step_name=N'Execute_Shrink_Log_Procedure', @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' BEGIN TRY PRINT N''开始执行日志收缩存储过程:''+ CONVERT(NVARCHAR(30), GETDATE(),120);EXEC master.dbo.ShrinkUser_DATABASESLogFile;PRINT N''日志收缩存储过程执行完成:''+ CONVERT(NVARCHAR(30), GETDATE(),120);END TRY BEGIN CATCH DECLARE @ErrMsg NVARCHAR(4000)=ERROR_MESSAGE();RAISERROR(N''收缩日志失败:%s'',16,1,@ErrMsg);END CATCH', @database_name = N'master', @flags = 0; IF @ReturnCode <> 0 BEGIN RAISERROR(N'添加作业步骤失败,返回码:%d',16,1,@ReturnCode); END PRINT N'已添加作业执行步骤'; -- 配置作业调度 EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id = @JobId, @name = N'$SCHEDULE_NAME', @enabled = 1, @freq_type = 8, @freq_interval = 127, @freq_subday_type = 1, @freq_subday_interval = 0, @freq_relative_interval = 0, @freq_recurrence_factor = 1, @active_start_date = CONVERT(INT, REPLACE(CONVERT(VARCHAR(10), GETDATE(), 112), '-', '')), @active_end_date=99991231, @active_start_time=$DAILY_EXEC_TIME, @active_end_time=235959;IF @ReturnCode<>0BEGIN RAISERROR(N'配置作业调度失败,返回码:%d',16,1,@ReturnCode);END PRINT N'已配置作业调度:每日$DAILY_EXEC_TIME执行';-- 关联作业到本地服务器(Linux下SQL Server实例默认名为MSSQLSERVER) EXEC @ReturnCode=msdb.dbo.sp_add_jobserver @job_id=@JobId, @server_name=N'(local)';IF @ReturnCode<>0BEGIN RAISERROR(N'关联作业到服务器失败,返回码:%d',16,1,@ReturnCode);END PRINT N'已将作业关联到本地服务器';COMMIT TRANSACTION;PRINT N'============================================';PRINT N'作业【$JOB_NAME】创建成功!';PRINT N'============================================';END TRY BEGIN CATCH IF @@TRANCOUNT>0ROLLBACK TRANSACTION;DECLARE @ErrorMessage NVARCHAR(4000)=ERROR_MESSAGE(), @ErrorSeverity INT=ERROR_SEVERITY(), @ErrorState INT=ERROR_STATE();RAISERROR(N'创建作业失败:%s',@ErrorSeverity,@ErrorState,@ErrorMessage);END CATCH SET NOCOUNT OFF;EOF)# ======================== 执行TSQL脚本 ========================echo"【信息】开始执行TSQL脚本,创建自动收缩日志作业..."/opt/mssql-tools/bin/sqlcmd -S"$SQL_SERVER"-U"$SQL_USER"-P"$SQL_PWD"-Q"$TSQL_SCRIPT"# 检查执行结果if[$?-eq0];thenecho"【成功】作业创建脚本执行完成!"echo"【提示】可通过以下命令查看作业:"echo" /opt/mssql-tools/bin/sqlcmd -S$SQL_SERVER-U$SQL_USER-P$SQL_PWD-Q 'SELECT name, enabled FROM msdb.dbo.sysjobs WHERE name = N''$JOB_NAME'';'"echo"【提示】查看作业执行历史:"echo" /opt/mssql-tools/bin/sqlcmd -S$SQL_SERVER-U$SQL_USER-P$SQL_PWD-Q 'EXEC msdb.dbo.sp_help_jobhistory @job_name = N''$JOB_NAME'';'"elseecho"【错误】作业创建脚本执行失败!"exit1fi

二、使用步骤

1. 前置准备

  • 确保Linux服务器已安装SQL Server并启动服务;
  • 安装sqlcmd工具:
    • Debian/Ubuntu:sudo apt-get update && sudo apt-get install -y mssql-tools unixodbc-dev
    • RHEL/CentOS:sudo yum install -y mssql-tools unixODBC-devel
  • master库创建dbo.ShrinkUser_DATABASESLogFile存储过程(核心收缩逻辑);
  • 创建低权限SQL运维账户(可选,替代sa)。

2. 脚本部署与执行

# 1. 将脚本保存为sqlserver_shrink_log_job.shvimsqlserver_shrink_log_job.sh# 2. 添加执行权限chmod+x sqlserver_shrink_log_job.sh# 3. 设置SQL密码环境变量(关键:避免硬编码)exportSQL_PWD="你的SQL账户密码"# 4. 执行脚本./sqlserver_shrink_log_job.sh

3. 验证作业创建结果

# 查看创建的作业/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P"$SQL_PWD"-Q"SELECT name, enabled FROM msdb.dbo.sysjobs WHERE name = N'ShrinkFile_DB_Logfile';"# 手动执行作业(测试)/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P"$SQL_PWD"-Q"EXEC msdb.dbo.sp_start_job @job_name = N'ShrinkFile_DB_Logfile';"# 查看作业执行历史/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P"$SQL_PWD"-Q"EXEC msdb.dbo.sp_help_jobhistory @job_name = N'ShrinkFile_DB_Logfile';"

三、重要注意事项

1. 安全规范

  • 禁止硬编码密码:永远不要将SQL密码直接写入脚本,通过环境变量或配置文件传入;
  • 最小权限原则:避免使用sa账户,创建专门的运维账户(授予SQLAgentOperatorRoledb_owner(master库)等最小权限);
  • 脚本权限:限制脚本的读取权限(chmod 700 sqlserver_shrink_log_job.sh),避免密码泄露。

2. 性能与业务风险

  • 收缩日志的适用场景:仅用于日志异常增长的应急场景,不要作为常规运维手段;
  • 完整恢复模式处理:若数据库为完整恢复模式,需在收缩前执行日志备份(BACKUP LOG),否则收缩无效;
  • 避免碎片化:频繁收缩会导致日志文件碎片化,建议收缩后调整日志文件的自动增长规则(如按固定大小增长,而非百分比)。

3. 运维监控

  • 定期检查作业执行历史,确认收缩逻辑正常运行;
  • 监控数据库日志文件大小,从根源解决增长问题(如优化长事务、调整恢复模式、配置定时日志备份);
  • Linux下可通过cron定时检查作业状态(可选)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 23:29:16

java后端工程师+AI大模型开发进修ing(研一版‖day63)

今日总结 java随笔录——什么是聚簇索引&#xff0c;什么是非聚簇索引&#xff1f;什么是覆盖索引&#xff1f;AI随探录——NLP中RNN到Attention机制的演进代码随想录——n皇后&#xff0c;贪心算法—分发饼干 目录 今日总结 详细内容 java随笔录 1、什么是聚簇索引&#x…

作者头像 李华
网站建设 2026/6/10 15:51:23

【TypeScript全栈开发指南:从入门到企业级应用实战-web技术栈】

一、TypeScript的价值与优势 1.1 为什么选择TypeScript&#xff1f; 在现代Web开发中&#xff0c;TypeScript已经成为JavaScript的强力替代品。它不仅保持了JavaScript的灵活性&#xff0c;还提供了静态类型检查的安全性&#xff1a; 类型安全&#xff1a;编译时发现错误&am…

作者头像 李华
网站建设 2026/6/10 14:46:11

C语言实现memcpy函数功能(附带源码)

一、项目背景详细介绍在C语言标准库中&#xff0c;memcpy 是一个极其基础但又极其重要的内存操作函数&#xff0c;用于将一段内存的数据复制到另一段内存中。它不关心数据类型&#xff0c;也不关心数据内容的含义&#xff0c;只负责按字节进行拷贝。memcpy 被广泛应用于以下场景…

作者头像 李华
网站建设 2026/6/10 14:41:14

说说线程的生命周期和状态

在Java中&#xff0c;线程的生命周期和状态是由java.lang.Thread.State枚举定义的。 目录NEW&#xff08;新建&#xff09;RUNNABLE&#xff08;可运行&#xff09;BLOCKED&#xff08;阻塞&#xff09;WAITING&#xff08;等待&#xff09;TIMED_WAITING&#xff08;超时等待&…

作者头像 李华
网站建设 2026/6/10 12:18:36

性能测试怎么做?看完这篇文章你就懂了

性能测试流程介绍&#xff1a; 01 流程一 — 问清性能测试需求 1、新系统能力验证 2、明确客户需求 3、找出系统性能瓶颈 4、稳定性验证&#xff08;强度测试&#xff09; 02 流程二 — 了解系统结构 系统架构对于测试新手来是最难的&#xff1b;先来了解系统所使用的技…

作者头像 李华