Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL缓存策略_Sql_Sql Server_Sql Server 2005_Optimization_Caching - Fatal编程技术网

SQL缓存策略

SQL缓存策略,sql,sql-server,sql-server-2005,optimization,caching,Sql,Sql Server,Sql Server 2005,Optimization,Caching,我正在开发一个交互式联系人搜索页面(当您键入或选择条件时,通过ajax返回联系人)。我希望这一页是非常敏感的 有一套复杂的规则来确定给定联系人可以看到哪些联系人记录;这些规则汇总到用户定义的函数中,DirectoryContactsByContact(@ContactID)。我已经对该函数进行了大量优化,但它仍然有点昂贵(执行时间为1-2秒),因此为了提高性能,我考虑了以下方法: 加载页面时,将此用户的DirectoryContactsByContact缓存为SQL表,例如,cache\u D

我正在开发一个交互式联系人搜索页面(当您键入或选择条件时,通过ajax返回联系人)。我希望这一页是非常敏感的


有一套复杂的规则来确定给定联系人可以看到哪些联系人记录;这些规则汇总到用户定义的函数中,
DirectoryContactsByContact(@ContactID)
。我已经对该函数进行了大量优化,但它仍然有点昂贵(执行时间为1-2秒),因此为了提高性能,我考虑了以下方法:

  • 加载页面时,将此用户的DirectoryContactsByContact缓存为SQL表,例如,
    cache\u DirectoryContactsByContact\u 1
  • 对缓存的表执行搜索(每次检查以确保它存在)
  • 过一会儿(比如30分钟)杀死缓存
如果数据在这段时间内过时,这没关系,所以我不关心失效

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


SQL Server中是否有任何机制可以简化此过程?有其他方法的建议吗?

在页面加载时,将函数的结果插入到一个永久表中,比如SearchResults。此表将包含如下字段:

  • 搜索联系人ID
  • 目录联系人ID
  • 创建日期
您可以搜索此表。然后——每天或任何时候——你都会有一个过程来检查这个表,并从一天左右的时间里删除任何内容

我不想在内存中缓存数据 NET中的内存,因为(a)有 大量数据,以及(b)搜索 涉及全文索引和联接 以及SQL做得很好的其他东西


这是否意味着搜索的数据是“很多”,或者搜索结果是“很多”?DirectoryContactsByContact(@ContactID)的输出有多大?我的假设是,这是一个小的结果集,小到足以在ASP端使用。如果这是真的,那么您应该在ASP中缓存特定@ContactID的搜索结果,并对相同的重复@ContactID恢复该缓存结果,直到它从缓存中过期,然后重新创建它

我不太喜欢将结果缓存为SQL中的表。这种方法将读变为写,从而进一步降低第一次命中的速度。它提供陈旧的数据,需要清理。但最重要的是,根据我的经验,它总是避免了由于数据模型模式设计不当而导致的查询不足的实际问题


您对
DirectoryContactsByContact(@ContactID)
响应时间不能进一步缩短有多大信心?瓶颈在哪里?你是怎么测量的?您是否考虑过可以进行哪些模式更改以更快地获得此结果?

我最终创建了一个基本的通用框架,用于将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)
,则会创建一个名为
\u c\u DirectoryContactsByContact\u 123
的表

以下是清理缓存表的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

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

FWIW我不想将数据缓存在.NET的内存中,因为(a)有很多数据,(b)搜索涉及全文索引和连接以及SQL擅长的其他内容。因此,我肯定要将其缓存为SQL表。
DirectoryContactsByContact(@ContactID)
可能包含超过20万行。但是(b)是一个更大的问题-一旦它被缩小到这个联系人可以看到的范围,仍然需要进行一些复杂的过滤,SQL更适合于这些过滤。DirectoryContactsByContact(@ContactID)强制执行的业务规则太复杂,无法在这个空间中讨论;只要说有很多事情在进行就够了。无论如何,查询缓存表和从冷启动(15毫秒到600毫秒)查询函数之间有大约40倍的差异,我怀疑通过调整查询是否可以挤出这种性能。我明白了。我在你原来的帖子里读到了这句话,但我不得不要求你确认一下。你最好的选择是西尔维亚建议的。这不是个坏主意。但是,如果我要麻烦地运行自己的缓存基础设施,那么(在我的情况下)缓存所有被查询的数据而不仅仅是ContactID是有意义的,这样我就不必在用户键入时进行任何加入或任何工作。