【问题标题】:Grid control in SSMSSSMS 中的网格控制
【发布时间】:2017-11-05 17:56:50
【问题描述】:

我注意到在 SSMS (SQL Server Management Studio 2016) 中,查询结果在一秒钟内返回(超过 10k+ 行)。结果表/网格滚动非常平滑,并且在 SSMS 上具有极低的内存占用 (~80MB)。这种类似于网格/视图的控制方式执行 ListView(~200MB,2-3 秒)和 DataGrid(~600MB,8-10 秒)。即使我关闭所有可视化或调整 cancententscroll 或修复其高度以优化速度,它们在 SSMS 中的表现仍然远远落后于网格,仍然具有缓慢的滚动和 GUI 操作。

SSMS 中使用的网格控件背后是什么让它如此流畅?

【问题讨论】:

  • 良好的编码实践,从 VB6 开始就可用。不加载 更多 数据而不是显示、滚动和数据虚拟化。 ListView 或 DataGrid 没有任何问题 - SSMS 很可能正在使用其中之一
  • 请注意,您的屏幕截图仅显示 16 行,而不是 10K。当您只显示 16 行时,没有理由将所有 10K 行加载到内存中。您可以加载 100 行并使用虚拟化。当用户向下滚动前 10 条记录时,应用程序已经加载了接下来的 100 条记录,而用户没有注意到
  • 我可以更改图像。即使使用虚拟化,它也不会达到那样的速度。请参阅我的其他网格/虚拟化问题.. 否则我不会开始赏金。任何在 wpf 控件上使用过大数据的人都应该体验过这一点
  • 不,他们没有——他们使用数据绑定和虚拟化,所以他们避免这种情况。您提到的内存大小很大 - 这意味着您将所有结果加载到内存中,并且可能也将所有结果作为行添加到网格中。虚拟化意味着数据在需要时才加载。仅加载 100 行的网格并没有什么呆滞
  • 我猜——它很可能是用 C 开发的自定义组件(或者不太可能是 C++/MFC)。我们要求微软开源它! (opensource.microsoft.com)

标签: c# sql-server wpf winforms ssms


【解决方案1】:

SSMS 网格不是 C++,它不是 ListView 也不是 DataGrid,它不使用 Windows 原生控件,它“只是”一个名为 GridControl(在 Microsoft.SqlServer.Management.UI.Grid 命名空间中)的自定义 .NET 控件,属于名为 Microsoft.SqlServer.GridControl.dll 的程序集。

您可以在不同的地方找到它:GAC%ProgramFiles(x86)%\Common Files\Microsoft Shared\SQL Server Developer Tools%ProgramFiles(x86)%\Microsoft SQL Server Management Studio 18\Common7\IDE、Visual Studio 文件等。

它不是一个可再发行的二进制 AFAIK,所以你不应该发布它,它没有文档记录,也不是像其他的全功能网格。但是,正如您所发现的,它是轻量级的,而且速度很快,与您的底层数据访问一样快。

如果您想使用它,这里有一个小的 Winforms C# 示例(一个 10000 x 256 网格,即立即打开的 250 万个单元格)演示如何使用它:

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.SqlServer.Management.UI.Grid;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private GridControl _control = new GridControl();

        public Form1()
        {
            InitializeComponent();

            for (int i = 0; i < 256; i++)
            {
                _control.AddColumn(new GridColumnInfo { HeaderType = GridColumnHeaderType.Text, IsUserResizable = true });
                _control.SetHeaderInfo(i, "Column " + i, null);
            }

            _control.Dock = DockStyle.Fill;
            _control.GridStorage = new GridStorage();
            Controls.Add(_control);
        }
    }

    // represents a datasource
    public class GridStorage : IGridStorage
    {
        public long EnsureRowsInBuf(long FirstRowIndex, long LastRowIndex)
        {
            return NumRows(); // pagination, dynamic load, virtualization, could happen here
        }

        public void FillControlWithData(long nRowIndex, int nColIndex, IGridEmbeddedControl control)
        {
            // for cell edition
            control.SetCurSelectionAsString(GetCellDataAsString(nRowIndex, nColIndex));
        }

        public string GetCellDataAsString(long nRowIndex, int nColIndex)
        {
            // get cell data
            return nRowIndex + " x " + nColIndex;
        }

        public int IsCellEditable(long nRowIndex, int nColIndex)
        {
            return 1; // 1 means yes, 0 means false
        }

        public long NumRows()
        {
            return 10000;
        }

        public bool SetCellDataFromControl(long nRowIndex, int nColIndex, IGridEmbeddedControl control)
        {
            // when a cell has changed, you're supposed to change your data here
            return true;
        }

        public Bitmap GetCellDataAsBitmap(long nRowIndex, int nColIndex) => throw new NotImplementedException();
        public void GetCellDataForButton(long nRowIndex, int nColIndex, out ButtonCellState state, out Bitmap image, out string buttonLabel) => throw new NotImplementedException();
        public GridCheckBoxState GetCellDataForCheckBox(long nRowIndex, int nColIndex) => throw new NotImplementedException();
    }
}

这就是它的样子。您可以在一台不错的计算机上滚动而不会减慢速度。

【讨论】:

  • 在不依赖 SQL Server 的应用程序中分发此网格的最简单方法是什么?
  • 从技术上讲,我认为您只需将其复制到某个地方即可。从法律上讲,我认为您无权这样做,因为它属于 Microsoft,但我根本不是该领域的专家。
猜你喜欢
  • 2010-10-19
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
  • 1970-01-01
  • 1970-01-01
  • 2015-02-27
相关资源
最近更新 更多