У меня есть кросс-серверный запрос, который вставляет большое количество строк из нашей базы данных журнала в наше хранилище данных. Проблема в том, что сейчас работа выполняется более 15 часов. Нужно это резко сократить. Нужен совет по лучшему индексу для этого запроса или можно ли внести какие-либо улучшения в сам запрос. Я думаю об индексе URL-адреса, метке времени для fromDatabase и метке времени идентификатора для toDatabase. Но я не уверен в правильном порядке расположения ключевых столбцов или в том, следует ли использовать включенные и т. Д. Любая помощь приветствуется.

  SELECT @SQL = N'
    INSERT INTO ' + @ToDatabase + '.dbo.Log
        (
        ImportDateTime
        ,ServerSource
        ,DatabaseSource
        ,Id
        ,Type
        ,UserName
        ,AppCode                        
        ,SubscriptionCode
        ,Duration
        ,ServiceNamespace
        ,ServiceName
        ,MethodName
        ,Parameters
        ,[Message]
        ,StackTrace
        ,Url
        ,UrlReferrer
        ,Browser
        ,BrowserVersion
        ,Platform
        ,Timestamp
        ,IpAddress
        ,EriAccountId
        )
        (
            SELECT
            ''' +  CONVERT(VARCHAR(50),@ImportDateTime) + '''
            ,''' +  @ServerSource + '''
            ,''' +  @DatabaseSource + '''
            ,Id
            ,Type
            ,UserName
            ,AppCode
            ,SubscriptionCode
            ,Duration
            ,ServiceNamespace
            ,ServiceName
            ,MethodName
            ,Parameters
            ,Message
            ,StackTrace
            ,Url
            ,UrlReferrer
            ,Browser
            ,BrowserVersion
            ,Platform
            ,Timestamp
            ,IpAddress
            ,EriAccountId

         FROM (
                select
                Id
                ,Type
                ,UserName
                ,AppCode
                ,SubscriptionCode
                ,Duration
                ,ServiceNamespace
                ,ServiceName
                ,MethodName
                ,Parameters
                ,Message
                ,StackTrace
                ,Url
                ,UrlReferrer
                ,Browser
                ,BrowserVersion
                ,Platform
                ,Timestamp
                ,IpAddress
                ,EriAccountId

    from openquery([' + @ServerSource + '],
                    ''select 
                    Id
                    ,Type
                    ,UserName
                    ,AppCode
                    ,SubscriptionCode
                    ,Duration
                    ,ServiceNamespace
                    ,ServiceName
                    ,MethodName
                    ,[Parameters] = CONVERT(NVARCHAR(MAX),[Parameters])
                    ,[Message]
                    ,StackTrace
                    ,Url
                    ,UrlReferrer
                    ,Browser
                    ,BrowserVersion
                    ,Platform
                    ,Timestamp
                    ,IpAddress
                    ,EriAccountId           
                    FROM ' + @FromDatabase + '.dbo.[Log] WITH (NOLOCK)
                    WHERE URL LIKE ''''http://online%'''' AND CONVERT(DATETIME2, TimeStamp) > ''''' + CONVERT(NVARCHAR(50),@AssessorDeploymentTimestamp) + ''''' AND CONVERT(DATETIME2,TimeStamp) > ''''' +  CONVERT(NVARCHAR(50),@DateCollected) + ''''' '') o
                    WHERE NOT EXISTS 
                        (SELECT 1
                        FROM ' + @ToDatabase + '.dbo.Log b 
                        WHERE b.id = o.id
                        AND CONVERT(DATETIME2, b.TimeStamp) > ''' +  CONVERT(NVARCHAR(50),@DateCollected) + '''
                        AND b.ServerSource = ''' +  @ServerSource + '''
                        )

                ) a
        )'
1
Jeff Lohr 16 Ноя 2018 в 18:32

1 ответ

Лучший ответ

Прежде всего, я собираюсь сказать, что вы должны следовать некоторым советам по оптимизации времени выполнения запроса, помимо реализации правильной стратегии индексации.

  • Избегайте функций во внутренних операторах SELECT и JOIN. Функции (даже если они кэшированы) должны выполняться для минимально возможного количества записей, и обычно это происходит при самом внешнем выборе.
  • По возможности избегайте подзапросов, вместо этого выберите JOIN.
  • По возможности избегайте использования нечисловых полей в операторах where, сканирование индекса в поле INT выполняется намного быстрее, чем в VARCHAR.
  • Избегайте использования подсказки WITH (NOLOCK), так как вы также будете читать незафиксированные данные. Это не ускоряет выполнение запроса, и вы получите потенциально грязный набор данных.

При попытке оптимизировать запрос также помните о порядке операций, которые "интерпретатор" запроса использует для его анализа:

  1. ОТ и ПРИСОЕДИНЯЙТЕСЬ К БЛОКУ
  2. ГРУППА ПО И ИМЕТЬ
  3. ГДЕ
  4. ВЫБРАТЬ

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

При этом ИНДЕКС должен быть создан в соответствии с используемым запросом, и вы можете найти полезную подсказку, если протестируете выполнение запроса с включенным планом выполнения, часто SSMS вам очень помогает.

В этом случае я бы добавил индекс в поля URL и TimeStamp в таком порядке.

CREATE CLUSTERED INDEX idx_Log ON yourDatabase.dbo.[log] (URL, Timestamp)
1
Adminorama 20 Ноя 2018 в 16:08