我的应用程序在C#[.NET 3.5]和MySQL 5.1后端。
我有一个带有TextBox和DataGridView的Windows窗体。当用户在TextBox中键入几个字符时,将运行带有Like子句的SQL查询来过滤下面DataGridView中显示的记录。
项目列表已经大大增加,我也没有发现在每个字符输入上运行适当的SQL查询。我认为另一种方法是在应用程序加载时创建一个DataSet,并将其填入最近的库存位置。比使用LINQ或类似的东西来过滤内存中的记录集。但是这种方法也没有优化,因为无论何时创建新账单,库存中的项目都会减少,每次我都需要更新内存中的记录集。
还有其他优化和更快的方法吗?
答案 0 :(得分:5)
可以做一些优化
数据库层
Great post关于如何优化数据库端的所有内容
您还可以尝试分片和水平缩放
申请方
不要使用数据集,因为它们繁重,笨重,速度慢,并且难以维护与数据库相同的数据副本。想一些技巧:
<强>基础设施强>
答案 1 :(得分:2)
在工作中,我有类似的东西,但根据您的具体要求,它可能没那么有用。我们所做的实际上是拿应用程序并将数据库分解为一些REST服务。在服务器后端部分,我们让应用程序将所有内容移动到内存中并在启动时将其缓存。我们通过服务器发送了所有更改,因此我们可以使部分缓存无效并根据需要重新加载。
在客户端,输入几个字符后,我们向服务器发送了一个请求。服务器向我们发送了与之匹配的项目列表,我们将其缓存在客户端。然后,我们只是过滤了列表客户端,只在清除字段或更改了前几个字符时才执行了另一个请求。
即使没有服务器部分,您也可以与客户端做类似的事情。
答案 2 :(得分:2)
只是JaCraig所说的扩展,我认为你不需要创建Web服务,但是围绕这段代码绘制边界是有道理的,因为它很复杂。
此外,我不会缓存整个数据库,可以进行一些调整和测试以找到正确的数量,但我会为每个字符组合缓存10或20个项目,最多2个或3个字符深,具体取决于性能(如果不区分大小写并且不区分欺骗,那么10个项目将是~17万项内存)
为每个字符添加使用hashset返回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);
}
答案 3 :(得分:1)
考虑使用SOLR在数据库中构建搜索索引:http://lucene.apache.org/solr/ 并在您选择的Web服务端点中查询。
仅在用户停止输入后发送查询也有很多帮助,我使用大约300毫秒作为发送下一个查询的等待时间。如果您不想自己构建它,前端有很多插件可以为您提供类似规则的终点。
答案 4 :(得分:0)
我建议在MSIL中查看编码。我们有一个类似的场景,我们需要快速更新内存中的记录。使用标准的.NET方式太慢了,所以我们通过玩底层MSIL直接写入内存。这很危险,但如果操作正确,您可以通过非托管内存使用获益。
答案 5 :(得分:0)
解决前瞻问题的“正确”方法是使用“trie”或“基数树”。如果需要,这可以在SQL中实现,尽管它是一个工作点。而且我不确定适应数据集动态变化的情况会有多容易。
对于“相对较小”的数据集(最多可能是10K项目,具体取决于您的环境),可以将trie保存在RAM中。
答案 6 :(得分:0)
我不确定你在like子句中允许多大的灵活性,但是如果新的数据网格视图将是你现在所拥有的子集,你应该能够告诉用户何时在文本框中键入内容 - 通常这是因为更多的字符使搜索更具体。
因此,只有当新数据不是您已有数据的子集时,您才可以为新数据库创建查询数据库,并将其保存到数据集中。当新数据成为子集时,请更新数据集的过滤器。
至于保持数据最新,(如果这是你对库存变化中的项目的意思),你也可以有一个计时器以合理的间隔重新查询。您可以在文本框中键入时导致数据库查询以及计时器导致查询时重置计时器。