65.9K
CodeProject 正在变化。 阅读更多。
Home

基于 Web 的实时 SQL Server 性能仪表板

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (62投票s)

2014年7月21日

CPOL

6分钟阅读

viewsIcon

149014

SQL Server 性能仪表板(SSPD)是一个小型开源Web应用程序,可近乎实时地显示一个或多个SQL Server实例及其数据库的性能和问题。

引言

SQL Server 性能仪表板(SSPD)是一个小型开源Web应用程序,可近乎实时地显示一个或多个SQL Server实例及其数据库的性能和问题。它使用动态管理视图(DMV)从详细输出中收集有用的数据,并结合实用存储过程,从而从中获取有意义、易于理解的信息。您可以使用它快速发现阻塞查询、谁在阻塞谁、消耗高CPU或磁盘的昂贵查询、查看是否存在异常锁定、非常高的磁盘活动等问题。

查看实时演示

http://dashboard.omaralzabir.com/

获取代码

二进制文件在此处,您可以将其解压到IIS文件夹中,将连接字符串放入web.config文件中,即可开始使用。

SqlServerPerformanceDashboard GitHub项目二进制文件

如果您不使用sa用户,而是使用自己的用户,请为该用户授予正确的权限。

USE master;
GO
GRANT VIEW SERVER STATE TO MyUser;
GO

这是一个连接字符串示例

<add name="DB1" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=YourDatabase;User ID=MyUser;Password=MyPassword" />

或者您可以从GitHub项目站点获取源代码: 

https://github.com/oazabir/SQLServerPerformanceDashboard/

为什么不使用SQL Server Management Studio?

SQL Server Management Studio附带活动报告,显示服务器的实时性能,以及各种报告以显示顶级查询、阻塞会话等。这些当然非常有用,但我们需要的是有人确切地告诉我们查询有什么问题,或者某个特定的WAIT有什么问题,或者某些看起来很高的图表到底有什么问题。例如,在“Top IO query report”(顶级IO查询报告)中,了解查询的哪一部分导致高IO会很有用。是否存在表扫描?索引扫描?同样,在阻塞会话报告中,了解谁在阻塞谁会很有用。SSPD试图通过确切地告诉我们问题所在来减轻我们的痛苦。此外,它作为一个网站提供,无需启动SQL Server Management Studio并运行报告即可随时使用。SSPD还会实时刷新,每5-10秒显示服务器的最新状态。

服务器上现在发生了什么?

SSPD使用一些自定义脚本来查询DMV并理解其含义。例如,我们来看第一个:“What's going on”(正在发生什么)。它向您显示当前正在运行的查询的近乎实时视图,并且还会告诉您这些查询的真正问题。

它使用了Adam Machanic制作的著名 Who is Active 脚本,该脚本提供了有关服务器上当前正在发生的事情的非常有益的视图。

一旦它拉取输出,它就会绑定到一个 DataGrid ,并且对于每一行,然后它会检查是否有超出图表范围的内容。

<asp:GridView CssClass="table table-striped" ID="GridView1" runat="server" DataSourceID="sqlDataSource" EnableModelValidation="True">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <%# Convert.ToDecimal(Eval("CPU")) > 1000 ? "<span class='label label-warning'>High CPU</span>" : "" %>
                <%# Convert.ToDecimal(Eval("physical_reads")) > 1000 ? "<span class='label label-warning'>High Physical Read</span>" : "" %>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>  
    <EmptyDataTemplate>
        No Query running at the moment.
    </EmptyDataTemplate>                  
</asp:GridView>         

在这里您可以看到,它会查看特定值,如果这些值异常高,它会注入一个警告标签。这使您无需扫描输出以查看是否有异常。您可以轻松设置所需的阈值,并在屏幕上获得即时警告标签。

无论您在哪里看到查询,都可以单击它以查看完整详细信息。

最昂贵的查询

这可能是日常监控中最有用的功能。它查询SQL Server自上次重启或调用DBCC FREEPROCCACHE以来运行的查询的缓存计划。然后它不仅显示最昂贵的查询,还准确显示查询的哪个部分导致了问题。您可以看到导致最高IO负载的WHERE子句。

在这里你可以看到一些表扫描正在进行。你还可以看到WHERE子句中导致表扫描的部分。 

如果单击查询(向右滚动),它将显示完整的查询。

昂贵的存储过程

接下来是“昂贵的存储过程”视图,它显示了在CPU或IO方面最昂贵的存储过程。

您可以看到 QueryOrders 的 AvgLogicalReads 非常高。那个存储过程正在拖垮数据库。

工作原理

看,妈妈,没有AJAX!

您会注意到面板会定期刷新。您可能认为我正在使用AJAX调用一些服务器端Web服务,以获取JSON/XML响应,然后使用一些jQuery模板渲染HTML输出。不,我使用的是我们的祖先世代幸福使用的东西。自然、有机的IFRAME解决方案,没有副作用。每个面板的HTML输出都来自单独的ASP.NET页面,通过IFRAME,然后它们被注入到主仪表板页面上的DIV中。

这种方法有几个好处

  • 这些小部件是单独的页面,用户可以在完整的浏览器视图中直接浏览。
  • 每个小部件都是一个普通的ASP.NET页面。无需构建Web服务来以JSON/XML格式返回数据。也无需任何通常用于序列化为JSON/XML的实体类。
  • HTML内容是在服务器端使用常规ASP.NET生成的。因此无需使用任何基于Javascript的HTML模板库。
  • 由于不需要AJAX或HTML模板,因此无需担心jQuery或其插件在新版本中破坏兼容性,也无需定期更新javascript库。

我们来看看如何做到这一点。首先是绘制面板的HTML标记

<div class="row">
    <div class="panel panel-success">
        <div class="panel-heading"><a href="WhoIsActive.aspx?c=<%= ConnectionString %>">What's going on</a></div>
        <div class="panel-body panel-body-height" id="WhoIsActive">
            <div class="progress">
                <div class="progress-bar progress-bar-striped" style="width: 60%"><span class="sr-only">100% Complete</span></div>
            </div>
        </div>
        <iframe class="content_loader" onload="setContent(this, 'WhoIsActive')" src="WhoIsActive.aspx?c=<%= ConnectionString %>" style="width: 100%; height: 100%; border: none; display: none" frameborder="0"></iframe>
    </div>
</div>

这是从 Twitter Bootstrap主题 中提取的标记。

您会注意到那里有一个不可见的IFRAME。当IFRAME加载时,它会调用 setContent 函数。该函数获取IFRAME的全部内容并将其注入到panel-body div中。

function setContent(iframe, id) {
        ...
        $('#' + id)
                .html($(iframe).contents().find("form").html())
            .dblclick(function () {
                iframe.contentWindow.location.reload();
            })
            ...
    }

瞧,这是一个干净的类似AJAX的解决方案,无需任何AJAX:没有XMLHTTP,没有JSON管道,没有HTML模板,也没有服务器端Web服务。

现在,这对于挂钩在IFRAME内部的任何事件处理程序都无效。那么,点击查询如何显示带有完整查询的弹出窗口呢?此外,如果它是一个IFRAME,弹出窗口难道不应该实际出现在IFRAME内部吗?

点击功能在主仪表板页面上完成。在将内容注入DIV后,它会挂钩点击处理程序,以在主页面上显示弹出窗口。

function setContent(iframe, id) {
    $('#' + id)
        .find('td.large-cell').off('click');

    if ($('#' + id).scrollLeft() == 0) {
            $('#' + id)
                .html($(iframe).contents().find("form").html())
                .dblclick(function () {
                    iframe.contentWindow.location.reload();
                })
                .find('td.large-cell').find('div').click(function () {
                    $('#content_text').text($(this).html());
                    $('#basic-modal-content').modal();
            });
    }

这里它寻找任何具有large-cell类的元素。然后它会挂钩其点击事件并显示模态对话框。模态对话框来自 Eric Martin的SimpleModal 插件。

绘制图表

图表使用jQuery插件 Flot 来将一些性能计数器渲染为运行图表。

有一个PerformanceCounter.aspx,负责渲染显示性能计数器的表格。它选择了一些重要的计数器,并将其标记为显示在图表上。首先它遍历表格,寻找计数器,并将计数器的标签标记为x轴,计数器的值标记为y轴。

var plot = ["Batch Requests/sec", "Full Scans/sec", "SQL Compilations/sec", "Total Latch Wait Time (ms)"];
$('td').each(function (i, e) {
        td = $(e);
    if (td.text().trim().length > 0) {
        for (var i = 0; i < plot.length; i ++) {
            if (plot[i] == td.text().trim()) {
                if (td.prev().text() == "_Total" || td.prev().text().trim().length == 0) {
                    td.addClass("x-axis");
                    td.next().addClass("y-axis");
                }
            }
        }
    }
})

现在,这个页面托管在仪表板页面的IFRAME中。因此,仪表板页面会扫描IFRAME内容,查找这些标签,获取它们的值并将其传递给Flot图表插件。

$(iframe).contents().find("form").find(".x-axis").each(function (i, e) {
        var x = $(e);
    var y = x.next('.y-axis');
    var xname = x.text();
    var yvalue = parseInt(y.text());
    if (datasets[xname]) {
        var data = datasets[xname].data;

        data.pop();

        data.splice(0, 0, yvalue);
    }
});

更新Flot图表的其余工作由常规Flot代码完成。

function updatePlot() {
    var index = 0;

    $.each(datasets, function (key, val) {
        var items = [];
        for (var i = 0; i < val.data.length; i++)
            items.push([i, val.data[i]]);

        var data = { color: val.color, data: items };

        if (plots[index] != null) {
            plot = plots[index];
            plot.setData([data]);
            plot.draw();
        }
        else {
            plot = $.plot("#placeholder" + (index + 1), [data], {
                series: {
                    //shadowSize: 0 // Drawing is faster without shadows
                },
                lines: { show: true, fill: true },
                grid: {
                    hoverable: true,
                    clickable: true
                },
                yaxis: {
                    min: 0,
                    max: val.ymax
                },
                xaxis: {
                    show: false
                }
            });

就这样!再次,没有AJAX,没有Web服务,没有HTML模板,没有JSON管道。纯粹的有机IFRAME和HTML。

结论

SSPD致力于使我们轻松监控SQL Server的健康状况。它从SQL Server内置视图产生的冗长数据中提取有意义的信息。它准确地显示问题所在。您可以随意自定义代码,添加自己的警告、自己的阈值,使其满足您的特定需求。

© . All rights reserved.