SQL缓存策略

时间:2010-02-19 15:58:21

标签: sql sql-server sql-server-2005 optimization caching

我正在处理互动式联系人搜索页面(在您键入或选择条件时,会通过ajax返回联系人)。我希望这个页面非常敏感。

有一套复杂的规则来确定给定联系人可以看到哪些联系人记录;这些规则汇总到用户定义的函数DirectoryContactsByContact(@ContactID)中。我已经大大优化了这个功能,但它仍然有点贵(执行1-2秒),所以为了提高性能我正在考虑这样的事情:

  • 当页面加载时,将此用户的DirectoryContactsByContact缓存为SQL表,例如cache_DirectoryContactsByContact_1
  • 对缓存表执行搜索(每次检查以确保它存在)
  • 过了一会儿(比如30分钟)杀了缓存

如果数据在此期间变得陈旧,那没关系,所以我不关心失效。

临时表不会在请求之间持续,因此我似乎需要将缓存表创建为永久表;但是我需要自己负责清理旧的缓存,乍一看看起来并不重要。

SQL Server中是否有任何机制可以使这更容易?关于替代方法的任何建议?

3 个答案:

答案 0 :(得分:2)

每当页面加载时,如何将函数的结果插入永久表,比如SearchResults。该表将包含以下字段:

  • SearchingContactID
  • DirectoryContactID
  • CREATEDATE

您将搜索此表。然后 - 每天或每当 - 您将有一个流程来浏览此表并删除超过一天左右的任何内容。

答案 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

这很粗糙:没有失效,它可能无法扩展到很多并发用户和/或非常大的数据集。然而,在我的情况下,当用户键入或选择搜索条件时,它会产生接近瞬时的结果,而且开销很小。

相关问题