SSMS 中的网格控制
Posted
技术标签:
【中文标题】SSMS 中的网格控制【英文标题】:Grid control in SSMS 【发布时间】: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) 【参考方案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,但我根本不是该领域的专家。以上是关于SSMS 中的网格控制的主要内容,如果未能解决你的问题,请参考以下文章