我正在处理互动式联系人搜索页面(在您键入或选择条件时,会通过ajax返回联系人)。我希望这个页面非常敏感。
有一套复杂的规则来确定给定联系人可以看到哪些联系人记录;这些规则汇总到用户定义的函数DirectoryContactsByContact(@ContactID)
中。我已经大大优化了这个功能,但它仍然有点贵(执行1-2秒),所以为了提高性能我正在考虑这样的事情:
cache_DirectoryContactsByContact_1
如果数据在此期间变得陈旧,那没关系,所以我不关心失效。
临时表不会在请求之间持续,因此我似乎需要将缓存表创建为永久表;但是我需要自己负责清理旧的缓存,乍一看看起来并不重要。
SQL Server中是否有任何机制可以使这更容易?关于替代方法的任何建议?
答案 0 :(得分:2)
每当页面加载时,如何将函数的结果插入永久表,比如SearchResults。该表将包含以下字段:
您将搜索此表。然后 - 每天或每当 - 您将有一个流程来浏览此表并删除超过一天左右的任何内容。
答案 1 :(得分:1)
我不想缓存数据 .NET中的内存,因为(a)有一个 大量数据,以及(b)搜索 涉及全文索引和连接 以及SQL做得很好的其他东西。
这是否意味着搜索到的数据“很多”,或者搜索结果是“很多”? DirectoryContactsByContact(@ContactID)
的输出有多大?我的假设是,这是一个小的结果集,小到足以在ASP方面有用。如果这是真的,那么你应该在ASP中为特定的@ContactID缓存搜索结果,并为相同的重复@ContactID重新缓存该缓存结果,直到它从缓存到期,然后重新创建它。
我不喜欢将结果缓存为SQL中的表格。这种方法将读取变为写入,从而进一步减慢了第一次打击。它提供陈旧的数据,需要清理。但最重要的是,根据我的经验,由于数据模型架构设计不当,始终规避了无法查询的真正问题。
您对DirectoryContactsByContact(@ContactID)
响应时间无法进一步降低有多大信心?瓶颈在哪里?你是怎么测量它的?您是否考虑过可以更快地提供架构更改以更快地提供此结果?
答案 2 :(得分:0)
我最终创建了一个基本的通用框架,用于将SQL函数或视图的结果缓存到表中。
Public Sub CreateCacheTable(ByVal SourceView As String, ByVal FieldList As String)
Dim CacheTable As String = GetCacheTableName(SourceView)
If Not TableExists(CacheTable) Then
Dim Sql As String = " Select ~FieldList~ Into ~CacheTable~ From ~SourceView~ ". _
Replace("~CacheTable~", CacheTable). _
Replace("~FieldList~", FieldList). _
Replace("~SourceView~", SourceView)
ExecuteNonQuery(cs, CommandType.Text, Sql)
End If
End Sub
Public Function GetCacheTableName(ByVal SourceView As String)
Dim Result As String = "_c_~SourceView~". _
Replace("~SourceView~", SourceView). _
Replace(".", "_"). _
Replace(",", "_"). _
Replace("[", ""). _
Replace("]", ""). _
Replace("(", ""). _
Replace(")", "")
Return Result
End Function
Public Sub CleanupCacheTables()
ExecuteNonQuery(cs, CommandType.StoredProcedure, "CleanupCacheTables")
End Sub
当页面加载时,我这样做:
CleanupCacheTables()
CreateCacheTable(SourceView, FieldList)
例如,如果SourceView为DirectoryContactsByContact(123)
,则会创建一个名为_c_DirectoryContactsByContact_123
的表。
这是CleanupCacheTables
的SQL:
Create Procedure CleanupCacheTables as
/* Finds all tables starting with _c_ that were created more than 30 minutes ago and drops them */
Declare @TableName nvarchar(255)
Declare CacheTableCursor Cursor for
Select
TableName=name
From SYS.OBJECTS
Where Type_Desc = 'USER_TABLE'
And Left(name,3)= '_c_'
And DateDiff(minute, create_date, GetDate())>30
Open CacheTableCursor
Fetch Next from CacheTableCursor into @TableName
While @@FETCH_STATUS = 0 Begin
Exec ('Drop Table ' + @TableName)
Fetch Next from CacheTableCursor into @TableName
End -- While
Close CacheTableCursor
Deallocate CacheTableCursor
Go
这很粗糙:没有失效,它可能无法扩展到很多并发用户和/或非常大的数据集。然而,在我的情况下,当用户键入或选择搜索条件时,它会产生接近瞬时的结果,而且开销很小。