编辑: 本网站的目的:名为 Utopiapimp.com。它是一款名为 utopia-game.com 的游戏的第三方实用程序。该网站目前拥有超过 12,000 名用户,我负责运营该网站。该游戏完全基于文本,并将永远保持这种状态。用户从游戏中复制并粘贴整页文本,并将复制的信息粘贴到我的站点中。我针对粘贴的数据运行一系列正则表达式并将其分解。然后我根据那个粘贴将 5 个值到超过 30 个值的任意位置插入到数据库中。然后我获取这些值并对它们运行查询,以非常简单易懂的方式显示信息。该游戏以团队为基础,每个团队有 25 个用户。所以每个团队都是一个组,每一行都是一个用户信息。用户可以一次更新所有 25 行或仅更新一行。我需要将内容存储到缓存中,因为该站点几乎每分钟执行 1,000 多个查询的速度非常慢。
所以这是交易。假设我有一个包含 100 列和 5000 行的 excel EDIT(Excel 只是一个想象的例子,我实际上并没有使用 excel)。每行都有两个唯一标识符。一个用于它自己的行,一个用于将 25 行组合在一起。该行中大约有 10 列几乎永远不会更改,而其他 90 列将始终更改。我们可以说有些甚至会在几秒钟内发生变化,具体取决于行的更新速度。也可以从组中添加和删除行,但不能从数据库中添加和删除行。这些行取自数据库中的大约 4 个查询,以显示数据库中最新和更新的数据。所以每次更新数据库中的内容时,我也希望更新该行。如果一行或一组在 12 小时左右没有更新,就会从 Cache 中取出。一旦用户通过数据库查询再次调用该组。它们将被放入缓存中。
以上就是我想要的。这就是愿望。
实际上,我仍然拥有所有行,但我将它们存储在缓存中的方式目前已损坏。我将每一行存储在一个类中,该类通过一个巨大的列表存储在服务器缓存中。当我去更新/删除/插入列表或行中的项目时,大部分时间它都有效,但有时它会抛出错误,因为缓存已更改。我希望能够锁定缓存,就像数据库或多或少地锁定一行一样。我有 DateTime 戳记可以在 12 小时后删除内容,但这几乎总是会中断,因为其他用户正在更新组中相同的 25 行,或者只是缓存发生了变化。
这是我如何将项目添加到缓存的示例,这个示例表明我只提取了 10 个左右很少更改的列。此示例全部删除 12 小时后未更新的行:
DateTime dt = DateTime.UtcNow;
if (HttpContext.Current.Cache["GetRows"] != null)
{
List<RowIdentifiers> pis = (List<RowIdentifiers>)HttpContext.Current.Cache["GetRows"];
var ch = (from xx in pis
where xx.groupID == groupID
where xx.rowID== rowID
select xx).ToList();
if (ch.Count() == 0)
{
var ck = GetInGroupNotCached(rowID, groupID, dt); //Pulling the group from the DB
for (int i = 0; i < ck.Count(); i++)
pis.Add(ck[i]);
pis.RemoveAll((x) => x.updateDateTime < dt.AddHours(-12));
HttpContext.Current.Cache["GetRows"] = pis;
return ck;
}
else
return ch;
}
else
{
var pis = GetInGroupNotCached(rowID, groupID, dt);//Pulling the group from the DB
HttpContext.Current.Cache["GetRows"] = pis;
return pis;
}
最后一点,我从缓存中删除了项目,因此缓存实际上并没有变大。
要重新发布问题,这样做的更好方法是什么?也许以及如何锁定缓存?我能比这更好吗?我只是希望它在删除或添加行时停止中断。
编辑:代码 SQLCacheDependency 不适用于 Remus 评论中发布的 LINQ。它适用于全表选择,但我只想从行中选择某些列。我不想选择整行,所以我不能使用 Remus 的想法。
以下代码示例均无效。
var ck = (from xx in db.GetInGroupNotCached
where xx.rowID== rowID
select new {
xx.Item,
xx.AnotherItem,
xx.AnotherItem,
}).CacheSql(db, "Item:" + rowID.ToString()).ToList();
var ck = (from xx in db.GetInGroupNotCached
where xx.rowID== rowID
select new ClassExample {
Item= xx.Item,
AnotherItem= xx.AnotherItem,
AnotherItemm = xx.AnotherItemm,
}).CacheSql(db, "Item:" + rowID.ToString()).ToList();
最佳答案
我真的怀疑您的缓存解决方案是否真的有用。 List<T>
无法编入索引,因此列表中的查找始终是 O(n) 操作。
假设您已经分析了您的应用程序并且知道数据库是您的瓶颈,这就是您可以做的:
在数据库中,您可以为数据创建索引,对它们的查找通常会显示 O(log(n))。您应该为包含静态数据的查询创建覆盖率索引。将频繁更改的数据保留为非索引,因为这会因必要的索引更新而减慢插入和更新的速度。您可以阅读 SQL Server 索引 here .获取 SQL Server Profiler 并检查哪些是最慢的查询以及原因。适当的索引可以让您获得巨大的性能提升(例如,您的 GroupId 上的索引将减少查找时间,从全表扫描 O(n) 到索引查找 O(n/25),假设每组有 25 个人) .
人们经常编写次优 SQL(返回不必要的列、选择 N+1、笛卡尔连接)。你也应该检查一下。
在实现缓存之前,我会确保您的数据库确实是性能问题的罪魁祸首。过早的优化是万恶之源,缓存很难做好。缓存频繁更改的数据并不是缓存的目的。
关于c# - 我应该如何将动态变化的数据存储到服务器缓存中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2594440/