【发布时间】:2016-02-10 16:51:58
【问题描述】:
我有一个关于应用程序性能的问题:我有很多表,每个表都有数百万条记录。我在不同的标准(由用户在运行时指定)使用连接、where 子句和 orderby 对它们执行 select 语句。我想对我的记录进行分页,但无论我如何处理我的 SQL 语句,我都无法达到直接从内存中获取页面的性能。基本上,当我必须使用一些运行时动态指定标准过滤我的记录时,问题就出现了。我尝试了所有方法,例如将 ROW_NUMBER() 函数与“where RowNo between”子句结合使用,我尝试过 CTE、临时表等。这些 SQL 解决方案只有在我不包含过滤的情况下才能正常运行。还要记住,我希望我的解决方案尽可能通用(想象一下,我的应用程序中有几个列表,这些列表实际上显示了分页的数百万条记录,并且这些记录是用非常复杂的 sql 语句构造的)。
我所有的表都有一个 INT 类型的主键。
所以,我有一个想法:为什么不只为 select 语句创建一个“服务器”。服务器首先从所有表中加载所有记录并将它们存储到一些 HashSets 中,其中每个 T 具有一个 Id 属性,GetHashCode () 返回该 Id,并且实现 Equals 使得只有当 Id 相等时两个记录才“相等”(不要不要尖叫,稍后您会看到为什么我不使用所有记录数据进行散列和比较)。
到目前为止一切顺利,但有一个问题:如何将内存中的集合与数据库记录同步?我的想法是我必须找到一个解决方案,例如我只加载差异变化。因此,我为每个要缓存的表发明了一个变更日志表。在这个变更日志中,我只执行标记脏行(更新或删除)的插入,并记录新插入的 id,所有这些机制都是使用触发器实现的。因此,每当内存选择出现时,我首先检查是否必须同步某些内容(通过查询更改日志)。如果必须应用某些内容,我会加载变更日志,将这些更改应用到内存中,最后我正在清除该变更日志(或者可能还记得我应用的最高变更日志 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 , bool > functors。使用这种机制,我的执行速度比 SQL 快。
我知道 SQL 2012 具有缓存支持,新的即将推出的 SQL 版本将支持更多,但我的客户端有 SQL Server 2005,所以......我无法从这些东西中受益。
我的问题:你怎么看?这是个坏主意?有更好的方法吗?
【问题讨论】:
标签: c# sql sql-server caching memory