【问题标题】:Speeding up records filtering as and when user types在用户输入时加速记录过滤
【发布时间】:2011-07-27 02:25:08
【问题描述】:

我的应用程序位于 C# [.NET 3.5] 和 MySQL 5.1 后端。

我有一个带有 TextBox 和 DataGridView 的 Windows 窗体。当用户在 TextBox 中键入几个字符时,将运行带有 Like 子句的 SQL Query 来过滤下面 DataGridView 中显示的记录。

项目列表已大大增加,而且我发现在每个字符输入上运行 SQL 查询并不合适。我认为另一种方法是在应用程序加载时创建一个 DataSet 并预先用最近的库存头寸填充它。比使用 LINQ 或类似的东西来过滤内存记录集。但是这种方法也没有优化,因为每当创建新账单时,库存中的商品都会减少,并且每次我都需要更新内存中的记录集。

还有其他优化的更快的方法吗?

【问题讨论】:

  • 如果这是 .NET 4,我建议使用响应式扩展 (Rx):这是介绍性动手实验室中的示例之一。但我不确定 pre-v4 的支持情况如何。
  • 我还可以建议您使用分钟。执行搜索查询之前的长度。因此,例如,仅当搜索词的长度超过 3 个字符时才运行查询。

标签: c# mysql .net-3.5


【解决方案1】:

有一些优化可以做

数据库层
Great post关于如何优化数据库端的一切

你也可以尝试分片和水平缩放

应用端
不要使用数据集,因为它们很重、体积大、速度慢,并且很难维护与数据库上相同的数据副本。思考几个技巧:

  • 缓存用户搜索
  • 仅在输入 2 或 3 个符号后才开始搜索
  • 在后台线程中运行搜索
  • 将搜索限制在 TOP 20(或其他)
  • 确保从各种代码抽象中轻松搜索,使其简单
  • 优化您的搜索查询,SQL 操作的顺序很重要

基础设施

  • 检查您的连接速度,是否有可能改善它?
  • 将您的数据库尽可能靠近应用程序

【讨论】:

    【解决方案2】:

    在工作中我有类似的东西,但根据您的具体要求,它可能没有那么有用。我们所做的实际上是获取应用程序并将数据库查询拆分为一些 REST 服务。在服务器后端部分,我们让应用程序将所有内容移动到内存中并在启动时对其进行缓存。我们通过服务器发送了所有更改,因此我们可以使缓存的部分无效并根据需要重新加载。

    在客户端,一旦输入了几个字符,我们就会向服务器发送一个请求。服务器将匹配的项目列表发回给我们,我们将其缓存在客户端。然后,我们只是过滤了该列表客户端,并且仅在清除该字段或更改前几个字符时才发出另一个请求。

    即使没有服务器部分,您也可以在客户端做类似的事情。

    【讨论】:

      【解决方案3】:

      只是 JaCraig 所说的扩展,我认为您不需要创建 Web 服务,但围绕这段代码画一个边界是有意义的,因为它会很复杂。

      此外,我不会缓存整个数据库,可以进行一些调整和测试以找到正确的数量,但我会为每个字符组合缓存 10 或 20 个项目,最多 2 或 3 个字符深,具体取决于性能(如果不区分大小写且不区分欺骗,则 10 项将在内存中约为 170k 项)

      为每个字符添加使用一个哈希集以返回您的 10 个项目,然后当它们跨越前 3 个字符时,您开始查询数据库。

      JaCraig 在这里指出的关键是,您需要通过相同的代码空间传递任何更新或修改,以保持缓存清洁。

      如果你有一个 DAL,那么它可以作为一个单独的数据提供者在下面做一些类似的事情:

      public Items[] GetItems(string searchString)
      {
        if (searchString.Length < 4)
        {
          return _cacheDataProvider.GetItems(searchString);
        }
      
        return _mySqlDataProvider.GetItems(searchString);
      }
      
      public void UpdateItem(Item itemToBeUpdated)
      {
        _cacheDataProvider.UpdateItem(itemToBeUpdated);
        _mySqlDataProvider.UpdateItem(itemToBeUpdated);
      }
      

      【讨论】:

        【解决方案4】:

        考虑使用 SOLR 从您的数据库中构建搜索索引:http://lucene.apache.org/solr/ 并在您选择的网络服务端点中查询。

        仅在用户停止输入后发送查询也有很大帮助,我使用了大约 300 毫秒作为何时发送下一个查询的等待时间。如果您不想自己构建它,那么有很多前端插件可以为您提供类似的规则。

        【讨论】:

          【解决方案5】:

          我建议查看 MSIL 中的编码。我们有一个类似的场景,我们需要快速更新内存中的记录。使用标准的.NET方式太慢了,所以我们通过玩底层MSIL直接写入内存。这很危险,但如果操作正确,您可以通过使用非托管内存获得好处。

          Increasing Application Performance

          【讨论】:

            【解决方案6】:

            解决前瞻问题的“正确”方法是使用“trie”或“radix tree”。如果需要,这可以在 SQL 中实现,尽管这是一个工作点。而且我不确定适应数据集动态变化的情况有多容易。

            对于“相对较小”的数据集(可能最多 10K 个项目,具体取决于您的环境),可以将 trie 保存在 RAM 中。

            【讨论】:

            • 正确的做法其实是使用实现你所描述的数据结构的东西,所以你不必这样做:) SOLR和Lucene就是这样的技术。
            【解决方案7】:

            我不确定您在 like 子句中允许多大的灵活性,但您应该能够判断用户何时在文本框中键入新的数据网格视图是否是您现在拥有的内容的子集 -通常是因为更多的字符使搜索更加具体。

            因此,只有当新数据不是您已有数据的子集时,您才可以为新数据库创建查询,并将其保存到数据集。当新数据成为子集时,更新数据集的过滤器。

            就使数据保持最新(如果这就是您对库存变化的意思),您还可以有一个计时器以合理的时间间隔重新查询。您可以在输入文本框导致数据库查询时重置计时器,以及计时器导致数据库查询时。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-08-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-03-24
              • 1970-01-01
              相关资源
              最近更新 更多