Стратегия кеширования SQL - PullRequest
1 голос
/ 19 февраля 2010

Я работаю над интерактивной страницей поиска контактов (контакты возвращаются через ajax при вводе или выборе критериев). Я хочу, чтобы эта страница была очень отзывчивой.

Существует сложный набор правил для определения того, какие записи контактов может видеть данный контакт; эти правила свернуты в пользовательскую функцию DirectoryContactsByContact(@ContactID). Я значительно оптимизировал эту функцию, но она все еще немного дороже (1-2 секунды для выполнения), поэтому для повышения производительности я думаю о чем-то вроде этого:

  • Когда страница загружается, кэшируйте DirectoryContactsByContact для этого пользователя в виде таблицы SQL, например, cache_DirectoryContactsByContact_1
  • Выполнить поиск по кэшированной таблице (проверяя каждый раз, чтобы убедиться, что она существует)
  • Через некоторое время (скажем, 30 минут) убить кеш

Это нормально, если данные устаревают в течение этого периода, поэтому я не обеспокоен аннулированием.

Временные таблицы не действуют между запросами, поэтому мне кажется, что мне нужно создать кеш-таблицу как постоянную таблицу; но тогда я должен был бы сам нести ответственность за очистку старых кешей, что на первый взгляд выглядит нетривиально.

Существуют ли в SQL Server какие-либо механизмы, которые облегчили бы эту задачу? Любой совет по альтернативным подходам?

Ответы [ 3 ]

2 голосов
/ 19 февраля 2010

Как насчет того, чтобы при загрузке страницы вставлять результаты вашей функции в постоянную таблицу, скажем, SearchResults. Эта таблица будет иметь такие поля, как:

  • SearchingContactID
  • DirectoryContactID
  • CreateDate

Вы будете искать по этой таблице. Затем - ежедневно или всякий раз - у вас будет процесс, чтобы просмотреть эту таблицу и удалить все, что было там, больше чем за день или около того.

1 голос
/ 19 февраля 2010

Я не хочу кэшировать данные в памяти в .NET, потому что (а) есть много данных, и (б) поиск включает в себя полнотекстовые индексы и объединения и другие вещи, которые SQL делает хорошо.

Означает ли это, что искомые данные «много» или что результат поиска «много»? Насколько велика производительность DirectoryContactsByContact(@ContactID)? Я предполагаю, что это небольшой набор результатов, достаточно маленький, чтобы быть полезным на стороне ASP. Если это так, то вы должны кэшировать в ASP результаты поиска для определенного @ContactID и повторно использовать этот кэшированный результат для того же повторного @ContactID, пока он не истечет из кэша, а затем заново создать его.

Я не большой поклонник кэширования результатов в виде таблиц в SQL. Этот подход превращает чтение в запись, тем самым еще больше замедляя первое попадание. Он предлагает устаревшие данные, он требует очистки. Но самое главное, исходя из моего опыта, он всегда обходит реальную проблему неэффективных запросов из-за неправильно разработанной схемы модели данных.

Насколько вы уверены, что время отклика DirectoryContactsByContact(@ContactID) не может быть дополнительно уменьшено? Где узкое место? Как вы это измерили? Рассматривали ли вы, какие изменения схемы могут быть сделаны, чтобы быстрее обслуживать этот результат?

0 голосов
/ 20 февраля 2010

Я закончил тем, что создал элементарную инфраструктуру общего назначения для кэширования результатов функции или представления 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.

Вот SQL для CleanupCacheTables:

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

Это грубо: нет аннулирования, и, вероятно, оно не будет масштабироваться для большого количества одновременно работающих пользователей и / или очень больших наборов данных. Тем не менее, в моем случае это приводит к почти мгновенным результатам, когда пользователь вводит или выбирает критерии поиска, с очень небольшими издержками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...