为存储在SQL Server中的数据创建内存中只读缓存

时间:2015-11-09 22:18:18

标签: c# sql sql-server caching memory

我遇到有关应用程序性能的问题:我有很多表,每个表都有数百万条记录。我正在使用连接执行select语句,其中子句和orderby用于不同的标准(由用户在运行时指定)。我希望将我的记录分页,但无论我对SQL语句做什么,我都无法达到直接从内存中获取页面的性能。基本上,当我必须使用一些运行时动态指定标准来过滤我的记录时,问题就出现了。我尝试了所有的东西,比如使用ROW_NUMBER()函数和"其中RowNo在"之间。条款,我已经尝试过CTE,临时表等。只有当我不包含过滤时,这些SQL解决方案才能表现良好。还要记住,我希望我的解决方案尽可能通用(想象一下,我在我的应用程序中有几个列表实际上显示了数百万条记录,并且这些记录是使用非常复杂的sql语句构建的)。

我的所有表都有一个INT类型的主键。

所以,我带来了一个想法:为什么不创建一个"服务器"仅适用于select语句。服务器首先加载来自所有表的所有记录,并将它们存储到一些HashSets中,其中每个T具有Id属性,GetHashCode()返回该Id,并且还实现Equals,使得两个记录等于"只有当Id相等时(不要尖叫,稍后你会看到为什么我没有使用所有记录数据进行散列和比较)。

到目前为止一直很好,但问题是:如何将内存集合与数据库记录同步?我的意思是我必须找到一个解决方案,例如我只加载差异变化。所以我为每个要缓存的表发明了一个changelog表。在此更改日志中,我只执行标记脏行(更新或删除)的插入,并且还记录新插入的ID,所有这些机制都使用触发器实现。因此,每当内存中的选择出现时,我首先检查是否必须同步某些内容(通过interogating changelog)。如果必须应用某些内容,我会加载更改日志,我将这些更改应用于内存中,最后我清除了更改日志(或者可能还记得我应用的最高更改日志ID ...)。

为了能够在O(N)中应用更改日志,其中N是更改日志大小,我使用此算法:

for each log.
identify my in-memory Dictionary <int, T> where the key is the primary key.

if it's a delete log then call dictionary.Remove (id) ( O ( 1 ))
if it's an update log, then call also dictionary.Remove (id) ( O (1))  and move this id into an "to be inserted" collection
if it's an insert log, move this id into a  "to be inserted" collection.

 finally, refresh cache by selecting all data from the corresponding table where Id in ("to be inserted").

对于过滤,我正在将一些表达式树编译成Func&lt; T,List&lt; FilterCriterias&gt;,bool&gt;函子。使用这种机制,我的执行速度比SQL快得多。

我知道SQL 2012具有缓存支持,新版本的SQL版本将支持更多,但我的客户端拥有SQL Server 2005所以...我无法从这些内容中受益。

我的问题:你怎么看?这是一个糟糕的想法?有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

SQL Server的开发人员做得非常好。我认为这是不可能的。

除非你的数据有某种隐式结构可能有助于加快速度并且优化器无法意识到这一点,否则这种“我自己的快速技巧”方法将无济于事 - 通常......

性能问题在出现问题时首先要解决:

  1. 表格结构和关系
  2. 索引和统计信息
  3. SQL语句的质量
  4. 如果设计和查询都很好,即使有数百万行也没问题......

    如果你的查询做了很多计算,或者你需要从棘手的结构中检索数据(带有递归读取的嵌套列表,XML ......)我会去Data-Warehouse-Path并写一些非规范化的表快速选择。当然,您必须处理这样一个事实,即您正在阅读“旧”数据。如果您的数据变化不大,您可以立即触发对非规范化结构的所有更改。但这取决于你的实际情况。

    如果您愿意,可以将一个不符合要求的查询与相关结构详细信息一起发布,并要求进行审核。 Stack-Exchange上有专门的组,例如“Code Review”。如果它不大,你也可以在这里试试......