使用 C# 在内存中存储数据库信息的最有效方法
本文关键字:信息 有效 方法 数据库 存储 内存 使用 | 更新日期: 2023-09-27 17:56:57
我目前正忙于在 C# 中试验一些东西,以便我可以根据自己的喜好构建一个 Web 服务器。Web服务器将是专门为我也在从事的项目制作的。希望它能比其他 Web 服务器运行得更好。
现在我一直在尝试做的是找到一种有效的方法来将数据库信息存储在应用程序的内存中。
到目前为止,我已经尝试创建一个类似于带有字段的表的类。为表中的每一行创建该类的新实例。然后创建某些类似于索引的字典变量。比如一个用于 Id,一个用于用户名。它正在工作,但与数据库中的表相比,它消耗的内存大约是其 3 倍。我所做的事情的例子:
class User()
{
public int Id;
public string Name;
//other columns, the same way
}
至于字典:
Dictionary<int, User> UserIDIndex = new Dictionary<int, User>();
User NewUser = new User();
NewUser.Name = "Something...";
UserIDIndex.Add(someId, NewUser);
我也尝试过DataTable,但一点也不成功。它消耗的内存至少比类和字典方法多 50%。
我很好奇是否有其他方法,更有效的存储信息的方式?
这一切背后的原因:每秒需要更新和选择大量数据。恐怕直接从数据库中做太多了。所以一开始(启动和某些条件)想在内存中加载一些东西。然后,在某些时候,更新内存中的值。然后,在数据库中更新这些值。我想这也可以用 NodeJS 完成,但它使用的是 1 个内核,我觉得这有点可悲。如果您遇到 CPU 问题,则不是真正的未来证明。
从性能的角度来看,如果分组 SQL 请求的性能明显优于一系列单个请求,则您的方法可能很好。
主要的不便之处是应用程序在崩溃时的健壮性。可能需要实现一些恢复机制。
关于内存,很难通过观察可用的RAM来评估内存需求,因为内存不会立即释放:在需要时根据系统的需求完成。
要计算实际使用的内存,请评估对象的大小并乘以计数。
处理用户输入时,是否评估了平均计算时间有和没有数据库更新?
我建议使用可观察的集合,例如在实体框架核心(EF Core)的幕后使用。(我没有看过幕后,我观察到 .local 为我提供了对内存中副本的访问权限)
Public ObservableCollection<user> users = new ObservableCollection<user>();
由于使用 EF Core 在后台使用相同的结构,因此可以编写一些内容,以便在使用它们之间轻松来回切换。棘手的部分是以这样一种方式定义内容,即使用 EF Core 或 InMemory 实现非常容易。以下示例基于使用 EF Core。在下面的代码中,我创建了一个通用的基础来工作。我包装了 Ef Core 使用的 DbContext。包装器允许我访问驻留在实体框架中的本地内存数据。
现在数据在内存中,您只需将其保存到磁盘即可。由于你有一个 EF Core 选项,因此可以轻松地比较你的环境有和没有选项。为了快速测试,我序列化为文件。从同一文件重新加载以恢复到我保存的状态也很容易。
警告:我的包装器只是将整个数据库加载到内存中,因为它在我的情况下很小。ToList() 是确保将数据加载到 EF Core 中的内存的代码。
查看此链接,了解实体框架核心操作方法
法典:
using Blog.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace Blog
{
public interface IData_Common
{
ObservableCollection<User> Users { get; }
ObservableCollection<Other> Others { get; }
}
public interface IData_InMemoryContext : IData_Common
{
IData_InMemoryContext Create();
}
public class Data_InMemoryContext : IData_InMemoryContext
{
public ObservableCollection<User> Users { get; set; }
public ObservableCollection<Other> Others { get; set; }
public Data_InMemoryContext()
{
Users = new ObservableCollection<User>();
Others = new ObservableCollection<Other>();
}
public IData_InMemoryContext Create()
{
Users = new ObservableCollection<User>();
Others = new ObservableCollection<Other>();
return new Data_InMemoryContext();
}
}
public interface IData_Context
{
DbSet<User> Users { get; set; }
DbSet<Other> Others { get; set; }
IData_Context Create();
}
public class Data_Context : DbContext, IData_Context
{
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Other> Others { get; set; }
public IData_Context Create()
{
return new Data_Context();
}
public Data_Context()
{
//this.Configuration.LazyLoadingEnabled = false;
}
}
// I wrap context so that I can use the InMemoryContext interface
public class WrapData_Context : IData_InMemoryContext
{
private object _Context;
private DbSet<User> _Users;
private DbSet<Other> _Others;
public WrapData_Context(Data_Context DbContext)
{
if (DbContext is null)
{
throw new NullReferenceException("DbContext can't be null");
}
_Context = DbContext;
// Need to make sure the data is accessed so it is loaded to the local ObservableCollections
DbContext.Users.ToList();
_Users = DbContext.Users;
DbContext.Others.ToList();
_Others = DbContext.Others;
}
public IData_InMemoryContext Create()
{
var context = new Data_Context();
return new WrapData_Context(context);
}
// Properties
public ObservableCollection<User> Users => _Users.Local.ToObservableCollection();
public ObservableCollection<Other> Others => _Others.Local.ToObservableCollection();
}
}
示例用法:
Data_Context _c = new Data_Context();
WrapData_Context _context = new WrapData_Context(_c);