设为首页 收藏本站
查看: 1199|回复: 0

使用PowerShell排错----使用PowerShell调校SQL Server性能

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-7-18 10:35:11 | 显示全部楼层 |阅读模式


这里会测试一些脚本,用于SQL Server调校,如索引维护、管理磁盘空间和导出DDL脚本,最后看看如何排Job来自动运行PowerShell脚本。

索引维护

要确保最佳性能,索引维护是一项重要的工作。传统地,DBA会写一些T-SQL来执行索引维护,但这并非容易的任务。PowerShell与SQL Server SMO库一起,提供了一个简练的解决方案用于索引维护。下面的脚本显示了如何如何通过执行PowerShell来完成广泛的索引维护日常工作。该脚本遍历用户数据库中所有表的所有索引,并基于索引的碎片水平来执行3项任务中的一个(代码文件:PS_ManageFragmentation01.PS1):

    如果索引碎片低于5%,则不作任何事情,因为对性能的影响微不足道;
    如果索引碎片位于5%和30%之间,则执行索引重组(reorganization);
    如果索引碎片高于30%,则执行索引重建(rebuild)。


    [string] $ServerName = $args[0]  
    [string] $TargetDatabaseName = $args[1]  
    [Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null  
    $server = New-Object Microsoft.SqlServer.Management.Smo.Server $ServerName  
    $targetDB = $server.Databases[$targetDatabaseName]  
    foreach ($table in $targetDB.Tables)  
    {  
        foreach($index in $table.Indexes)  
        {  
            $fragmentation = $index.EnumFragmentation()  
            $averageFragmentation = $fragmentation.Rows[0].AverageFragmentation  
            if($averageFragmentation -lt .05)  
            {  
                continue  
            }  
            if($averageFragmentation -ge .05 -and $averageFragmentation -lt .3)  
            {  
                $index.Reorganize()  
                continue  
            }  
            $index.Rebuild()  
        }  
    }  

管理备份的磁盘空间使用率

使用PowerShell操作文件系统很简单。下面的例子中,创建了一个脚本来删除2天前的事务日志备份、8天前的差异备份,91天前的完整备份。基于文件扩展名和最后一次写入时间,把查询分成了3份,根据当前日期减去天数来定义各种备份类型的保存期(代码文件:PS_DeleteOldBackups01.PS1):


    Get-ChildItem .\Backups -include *.trn -recurse '  
    | Where-Object { $_.lastwritetime -lt (Get-Date).AddDays(-2) } '  
    | Remove-Item  
    Get-ChildItem .\Backups -include *.dif -recurse '  
    | Where-Object { $_.lastwritetime -lt (Get-Date).AddDays(-8) } '  
    | Remove-Item  
    Get-ChildItem .\Backups -include *.bak -recurse '  
    | Where-Object { $_.lastwritetime -lt (Get-Date).AddDays(-91) } '  
    | Remove-Item  

使用SMO提取DDL

错位索引或表定义不佳两种情况会有严重的性能影响,需要改变数据库DDL。处于这种考虑,我创建了下面的脚本,它可以排Job一天运行一次,从数据库中提取所有的DDL对象,并存放到磁盘中以提取时间命名的文件夹中。如果发现性能不佳,按天比对文件,来识别是不是因为DDL改变而引起数据库性能下降。这个脚本很长,但它组合了前面所讲的所有的概念及技术,把所有的数据库对象导入到文件(代码文件:PS_ExtractDDL01.PS1):


    #Helper function to script the DDL Object to disk  
    function Write-DDLOutput ($filename, $object)  
    {  
        New-Item $filename -type file -force | Out-Null  
        #Specify the filename  
        $ScriptingOptions.FileName = $filename  
        #Assign the scripting options to the Scripter  
        $Scripter.Options = $ScriptingOptions  
        #Script the index  
        $Scripter.Script($object)  
    }  
      
    #Load the SMO assembly  
    [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null  
    #Create all the global vars we need  
    $Server = New-Object ("Microsoft.SqlServer.Management.Smo.Server")  
    $Scripter = New-Object ("Microsoft.SqlServer.Management.Smo.Scripter")  
    $ScriptingOptions = New-Object  
    ("Microsoft.SqlServer.Management.SMO.ScriptingOptions")  
    $Scripter.Server = $Server  
    #Specifies the root folder that we'll store the Scripts into This will probably  
    become a param in future  
    $RootBackupFolder = "C:\SqlBackups\DDL"  
    #Get the day of the week so that we can create a folder for each day  
    $Today = [System.DateTime]::Today.DayOfWeek  
    #Store today's backup folder  
    $DDLBackupFolder = Join-Path -Path $RootBackupFolder -ChildPath $Today  
    #Check if today's folder exists  
    if ([System.IO.Directory]::Exists($DDLBackupFolder))  
    {  
        #If it does delete it's contents  
        Remove-Item (Join-Path -Path $DDLBackupFolder -ChildPath *) -Recurse  
    }  
    else  
    {  
        #Otherwise create it  
        [System.IO.Directory]::CreateDirectory($DDLBackupFolder) | Out-Null  
    }  
         
    #Setup the scripting options  
    $ScriptingOptions.AppendToFile = $true  
    $ScriptingOptions.FileName = $filename  
    $ScriptingOptions.ToFileOnly = $true  
    $ScriptingOptions.ScriptData = $false  
    #Loop through all the databases to script them out  
    foreach ($database in ($Server.databases | where {$_.IsSystemObject -eq $false -and  
    $_.IsDatabaseSnapshot -eq $false}))  
    {  
        $databaseBackupFolder = Join-Path -Path $DDLBackupFolder -ChildPath  
        $Database.Name  
        #This will be the database create script  
        Write-DDLOutput (Join-Path -Path ($databaseBackupFolder) -ChildPath  
        ($Database.Name + ".sql")) $database  
        $ProgrammabilityBackupFolder = Join-Path -Path  
        $databaseBackupFolder -ChildPath "Programmability"  
        $DefaultsBackupFolder = Join-Path -Path  
        $ProgrammabilityBackupFolder -ChildPath "Defaults"  
        foreach ($default in $database.Defaults)  
        {  
            #Generate a filename for the default  
            Write-DDLOutput (Join-Path -Path  
            ($DefaultsBackupFolder) -ChildPath  
            ($default.Schema + "." + $default.Name + ".sql"))  
            $default  
        }  
        #Create a folders to store the functions in  
        $FunctionsBackupFolder = Join-Path -Path  
        $ProgrammabilityBackupFolder -ChildPath "Functions"  
        $ScalarFunctionsBackupFolder = Join-Path -Path  
        $FunctionsBackupFolder -ChildPath "Scalar-valued Functions"  
        $TableValuedFunctionsBackupFolder = Join-Path -Path  
        $FunctionsBackupFolder -ChildPath "Table-valued Functions"  
        foreach ($function in $database.UserDefinedFunctions | where  
        {$_.IsSystemObject -eq $false})  
        {  
            #script the functions into folders depending upon type. We're  
            only interested in scalar and table  
            switch ($function.FunctionType)  
            {  
                scalar  
                {  
                    #Generate a filename for the scalar function  
                    $filename = Join-Path -Path  
                    ($ScalarFunctionsBackupFolder) -ChildPath  
                    ($function.Schema + "." + $function.Name + ".sql")  
                }  
                table  
                {  
                    #Generate a filename for the table value function  
                    $filename = Join-Path -Path  
                    ($TableValuedFunctionsBackupFolder) -ChildPath  
                    ($function.Schema + "." + $function.Name + ".sql")  
                }  
                default { continue }  
            }  
            #Script the function  
            Write-DDLOutput $filename $function  
        }  
        $RulesBackupFolder = Join-Path -Path  
        $ProgrammabilityBackupFolder -ChildPath "Rules"  
        foreach ($rule in $database.Rules)  
        {  
            #Script the rule  
            Write-DDLOutput (Join-Path -Path  
            ($RulesBackupFolder) -ChildPath  
            ($rule.Schema + "." + $rule.Name + ".sql")) $rule  
        }  
        #Create a folder to store the Sprocs in  
        $StoredProceduresBackupFolder = Join-Path -Path  
        $ProgrammabilityBackupFolder -ChildPath "Stored Procedures"  
        #Loop through the sprocs to script them out  
        foreach ($storedProcedure in $database.StoredProcedures | where  
        {$_.IsSystemObject -eq $false})  
        {  
            #script the sproc  
            Write-DDLOutput ($filename = Join-Path -Path  
            ($StoredProceduresBackupFolder) -ChildPath  
            ($storedProcedure.Schema + "." +  
            $storedProcedure.Name + ".sql"))  
            $storedProcedure  
        }  
        #Create a folder to store the table scripts  
        $TablesBackupFolder = Join-Path -Path $databaseBackupFolder -ChildPath  
        "Tables"  
        $TableIndexesBackupFolder = Join-Path -Path  
        $TablesBackupFolder -ChildPath "Indexes"  
        $TableKeysBackupFolder = Join-Path -Path  
        $TablesBackupFolder -ChildPath "Keys"  
        $TableConstraintsBackupFolder = Join-Path -Path  
        $TablesBackupFolder -ChildPath "Constraints"  
        $TableTriggersBackupFolder = Join-Path -Path  
        $TablesBackupFolder -ChildPath "Triggers"  
        #Loop through the tables to script them out  
        foreach ($table in $database.Tables | where  
        {$_.IsSystemObject -eq $false})  
        {  
            #Script the Table  
            Write-DDLOutput (Join-Path -Path  
            ($TablesBackupFolder) -ChildPath  
            ($table.Schema + "." + $table.Name + ".sql")) $table  
            foreach($Constraint in $table.Checks)  
            {  
                #Script the Constraint  
                Write-DDLOutput (Join-Path -Path  
                ($TableConstraintsBackupFolder) -ChildPath  
                ($table.Schema + "." + $table.Name + "." +  
                $Constraint.Name + ".sql")) $Constraint  
            }  
            foreach ($index in $table.Indexes)  
            {  
                #Generate a filename for the table  
                switch($index.IndexKeyType)  
                {  
                    DriPrimaryKey  
                    {  
                        $filename = Join-Path -Path  
                        ($TableKeysBackupFolder) -ChildPath  
                        ($table.Schema + "." +  
                        $table.Name + "." +  
                        $index.Name + ".sql")  
                    }  
                    default  
                    {  
                        $filename = Join-Path -Path  
                        ($TableIndexesBackupFolder) -ChildPath  
                        ($table.Schema + "." +  
                        $table.Name + "." +  
                        $index.Name + ".sql")  
                    }  
                }  
                #Script the index  
                Write-DDLOutput $filename $index  
            }  
            foreach ($trigger in $table.Triggers)  
            {  
                #Script the trigger  
                Write-DDLOutput (Join-Path -Path  
                ($TableTriggersBackupFolder) -ChildPath  
                ($table.Schema + "." + $table.Name + "." +  
                $trigger.Name + ".sql")) $trigger  
            }  
        }  
        #Create a folder to store the view scripts  
        $ViewsBackupFolder = Join-Path -Path $databaseBackupFolder -ChildPath  
        "Views"  
        $ViewKeysBackupFolder = Join-Path -Path $ViewsBackupFolder -ChildPath  
        "Keys"  
        $ViewIndexesBackupFolder = Join-Path -Path  
        $ViewsBackupFolder -ChildPath "Indexes"  
        $ViewTriggersBackupFolder = Join-Path -Path  
        $ViewsBackupFolder -ChildPath "Triggers"  
        #Loop through the views to script them out  
        foreach ($view in $database.Views | where  
        {$_.IsSystemObject -eq $false})  
        {  
            #Script the view  
            Write-DDLOutput (Join-Path -Path  
            ($ViewsBackupFolder) -ChildPath  
            ($view.Schema + "." + $view.Name + ".sql")) $view  
            foreach ($index in $view.Indexes)  
            {  
                #Generate a filename for the table  
                switch($index.IndexKeyType)  
                {  
                    DriPrimaryKey  
                    {  
                        $filename = Join-Path -Path  
                        ($ViewKeysBackupFolder) -ChildPath  
                        ($view.Schema + "." +  
                        $view.Name + "." + $index.Name + ".sql")  
                    }  
                    default  
                    {  
                        $filename = Join-Path -Path  
                        ($ViewIndexesBackupFolder) -ChildPath  
                        ($view.Schema + "." + $view.Name + "." +  
                        $index.Name + ".sql")  
                    }  
                }  
                Write-DDLOutput $filename $index  
            }  
            foreach ($trigger in $view.Triggers)  
            {  
                #Script the trigger  
                Write-DDLOutput (Join-Path -Path  
                ($ViewTriggersBackupFolder) -ChildPath  
                ($view.Schema + "." + $view.Name + "." +  
                $trigger.Name + ".sql")) $trigger  
            }  
        }  
    }  

脚本执行排Job
有两种方式对脚本执行排Job。第一种是使用Windows Task Scheduler,如果你没有安装SQL  Server且希望执行PowerShell脚本时,用这种方式很有用。你可以很容易添加一项新任务到Scheduler,并执行PowerShell.exe, 把你要执行的脚本作为参数传给它。

对于安装SQL Server 2008 R2或更高版本的服务器而言,你还可以通过SQL Server Agent Job来执行PowerShell。通过新建Job,并在Type下拉框里选择PowerShell,可以很容易实现。然后数据PowerShell脚本到Commend文本框。

不幸的是,在SQL Server 2008 R2里使用PowerShell Job不是非常有用,因为它不能调用PowerShell 1.0,所以很多脚本和模块不能正常工作。如果你想在SQL Server 2008 R2中执行PowerShell 2.0脚本,你最好使用前面讲的执行PowerShell.exe的方式。幸运的是,这个问题在SQL Server 2012中解决了,因为他装载了PowerShell 2.0。

SQL Server代理Job的优势是你或许已经有Job在跑,这种方式能够让你在一个地方管理所有的Job。你也可以使用嵌入在SQL Job引擎里的日志功能来监控PowerShell脚本的执行情况。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-22295-1-1.html 上篇帖子: 使用PowerShell排错----使用PowerShell调查Server问题 下篇帖子: 在CMD命令行和PowerShell中实现复制粘贴功能 调校
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表