我有一个winforms应用程序,我有一个Telerik dropdownchecklist,让用户选择一组州名。
使用EF和数据库存储在Azure SQL中。然后,代码将访问包含约17,000条记录的数据库,并对结果进行过滤,只包含已检查的状态。
工作好。我想更新一个计数在屏幕上每当他们改变列表框。
这是itemCheckChanged事件中的代码:
var states = stateDropDownList.CheckedItems.Select(i => i.Value.ToString()).ToList();
var filteredStops = (from stop in aDb.Stop_address_details where states.Contains(stop.Stop_state) select stop).ToArray();
ExportInfo_tb.Text = "Current Stop Count: " + filteredStops.Count();
它工作,但它很慢。我试图将所有内容加载到内存变量中,然后对数据库进行查询,但似乎无法弄清楚如何做到这一点。
有什么建议吗?
改进:通过限制传入的数据量,我获得了显著的改进:
var filteredStops = (from stop in aDb.Stop_address_details where states.Contains(stop.Stop_state) select stop.Stop_state).ToList();
更好的是——
int count = (from stop in aDb.Stop_address_details where
states.Contains(stop.Stop_state)
select stop).Count();
ExportInfo_tb.Text = "Current Stop Count: " + count.ToString();
在本例中,查询的性能实际上与Contiains
无关。Contains性能很好。正如您在第三个解决方案中发现的那样,问题是您通过网络提取的数据远远超过所需的数据。
在第一个解决方案中,您将从具有匹配停止状态的服务器回拉所有行,并在本地执行计数。这是最糟糕的方法。你回拉数据只是为了计算它,你回拉的数据远远超过你需要的。
在第二个解决方案中,您限制了返回到单个字段的数据,这就是性能提高的原因。如果您的表非常宽,这可能会导致显著的改进。这样做的问题是,您仍然只是在本地计算所有数据。
在您的第三个解决方案中,EF将把.Count()
方法转换为为您执行计数的查询。因此计数将发生在服务器上,返回的唯一数据是单个值;计数的结果。由于网络延迟通常是(但并不总是)执行查询时最长的步骤,因此返回更少的数据通常可以显著提高查询速度。
最终解决方案的查询翻译应该是这样的:
SELECT COUNT(*) AS [value]
FROM [Stop_address_details] AS [t0]
WHERE [t0].[Stop_state] IN (@p0)