- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我们有一个 ASP.NET MVC Web 应用程序,它通过 Entity Framework 连接到 SQL Server 数据库。该应用程序的主要任务之一是允许用户快速搜索和过滤包含存档值的庞大数据库表。
表结构相当简单:Timestamp(DateTime)、StationId(int)、DatapointId(int)、Value(double)。该表包含大约 10 到 1 亿行。我用覆盖索引等对数据库表进行了优化,但在按 DatapointId、StationId、Time 和 Skipping and Taking only 我想在页面上显示的部分进行过滤时,用户体验仍然很滞后。
所以我尝试了一种不同的方法:由于我们的服务器有很多 RAM,我认为我们可以简单地将整个存档表加载到 List<ArchiveRow>
中。当 Web 应用程序启动时,只需直接从该列表中获取数据,而不是往返于数据库。这工作得很好,将整个存档表(目前大约有 1000 万个条目)加载到列表中大约需要 9 秒。 ArchiveRow
是一个看起来像这样的简单对象:
public class ArchiveResponse {
public int Length { get; set; }
public int numShown { get; set; }
public int numFound { get; set; }
public int numTotal { get; set; }
public List<ArchiveRow> Rows { get; set; }
}
相应地:
public class ArchiveRow {
public int s { get; set; }
public int d { get; set; }
public DateTime t { get; set; }
public double v { get; set; }
}
当我现在尝试使用 Linq 查询从列表中获取所需数据时,查询数据库已经更快了,但是在按多个条件过滤时仍然很慢。例如,当我按 1 个 StationId 和 12 个 DatapointId 进行筛选时,检索 25 行的窗口大约需要 5 秒。我已经从 Where
过滤切换了使用连接,但我认为仍有改进的余地。有没有更好的方法来实现这种缓存机制,同时保持尽可能低的内存消耗?是否有其他更适合此目的的集合类型?
下面是从 ArchiveCache 列表中过滤和获取相关数据的代码:
// Total number of entries in archive cache
var numTotal = ArchiveCache.Count();
// Initial Linq query
ParallelQuery<ArchiveCacheValue> query = ArchiveCache.AsParallel();
// The request may contain StationIds that the user is interested in,
// so here's the filtering by StationIds with a join:
if (request.StationIds.Count > 0)
{
query = from a in ArchiveCache.AsParallel()
join b in request.StationIds.AsParallel()
on a.StationId equals b
select a;
}
// The request may contain DatapointIds that the user is interested in,
// so here's the filtering by DatapointIds with a join:
if (request.DatapointIds.Count > 0)
{
query = from a in query.AsParallel()
join b in request.DatapointIds.AsParallel()
on a.DataPointId equals b
select a;
}
// Number of matching entries after filtering and before windowing
int numFound = query.Count();
// Pagination: Select only the current window that needs to be shown on the page
var result = query.Skip(request.Start == 0 ? 0 : request.Start - 1).Take(request.Length);
// Number of entries on the current page that will be shown
int numShown = result.Count();
// Build a response object, serialize it to Json and return to client
// Note: The projection with the Rows is not a bottleneck, it is only done to
// shorten 'StationId' to 's' etc. At this point there are only 25 to 50 rows,
// so that is no problem and happens in way less than 1 ms
ArchiveResponse myResponse = new ArchiveResponse();
myResponse.Length = request.Length;
myResponse.numShown = numShown;
myResponse.numFound = numFound;
myResponse.numTotal = numTotal;
myResponse.Rows = result.Select(x => new archRow() { s = x.StationId, d = x.DataPointId, t = x.DateValue, v = x.Value }).ToList();
return JsonSerializer.ToJsonString(myResponse);
更多细节:站的数量通常在 5 到 50 之间,很少超过 50。数据点的数量 <7000。 Web 应用程序设置为 64 位 <gcAllowVeryLargeObjects enabled="true" />
在 web.config 中设置。
我真的很期待进一步的改进和建议。也许有一种完全不同的基于数组或类似方法的方法,在没有 linq 的情况下表现得更好?
最佳答案
您可以针对此特定查询类型调整存储。首先,从内存中的存档创建字典:
ArchiveCacheByDatapoint = ArchiveCache.GroupBy(c => c.DataPointId)
.ToDictionary(c => c.Key, c => c.ToList());
ArchiveCacheByStation = ArchiveCache.GroupBy(c => c.StationId)
.ToDictionary(c => c.Key, c => c.ToList());
然后在您的查询中使用这些词典:
bool hasStations = request.StationIds.Length > 0;
bool hasDatapoints = request.DatapointIds.Length > 0;
int numFound = 0;
List<ArchiveCacheValue> result;
if (hasDatapoints && hasStations) {
// special case - filter by both
result = new List<ArchiveCacheValue>();
// store station filter in hash set
var stationsFilter = new HashSet<int>(request.StationIds);
// first filter by datapoints, because you have more different datapoints than stations
foreach (var datapointId in request.DatapointIds.OrderBy(c => c)) {
foreach (var item in ArchiveCacheByDatapoint[datapointId]) {
if (stationsFilter.Contains(item.StationId)) {
// both datapoint and station matches filter - found item
numFound++;
if (numFound >= request.Start && result.Count < request.Length) {
// add to result list if matches paging criteria
result.Add(item);
}
}
}
}
}
else if (hasDatapoints) {
var query = Enumerable.Empty<ArchiveCacheValue>();
foreach (var datapoint in request.DatapointIds.OrderBy(c => c))
{
var list = ArchiveCacheByDatapoint[datapoint];
numFound += list.Count;
query = query.Concat(list);
}
// execute query just once
result = query.Skip(request.Start).Take(request.Length).ToList();
}
else if (hasStations) {
var query = Enumerable.Empty<ArchiveCacheValue>();
foreach (var station in request.StationIds.OrderBy(c => c))
{
var list = ArchiveCacheByStation[station];
numFound += list.Count;
query = query.Concat(list);
}
// execute query just once
result = query.Skip(request.Start).Take(request.Length).ToList();
}
else {
// no need to do Count()
numFound = ArchiveCache.Count;
// no need to Skip\Take here really, ArchiveCache is list\array
// so you can use indexes which will be faster
result = ArchiveCache.Skip(request.Start).Take(request.Length).ToList();
}
// Number of entries on the current page that will be shown
int numShown = result.Count;
我已经对其进行了测量,在我的机器上,对于我尝试过的所有类型的查询(仅按部分、仅按数据点、按部分和数据点),1 亿个项目的运行时间为 1 毫秒(有时高达 10 毫秒)。
关于c# - 在 C# 中过滤巨大列表的最高效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47348923/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!