推荐的索引和查询改进

Recommended index and query improvement

我有一个跨服务器查询,它将大量行从我们的日志数据库插入到我们的数据仓库。现在的问题是这项工作 运行 超过 15 个小时。需要大幅减少这一点。需要有关此查询的最佳索引的建议,或者是否可以对查询本身进行任何改进。我正在考虑 URL 上的索引、fromDatabase 的时间戳和 toDatabase 的 ID 时间戳。但不确定键列的最佳顺序,或者我是否应该使用 included 等。非常感谢所有帮助。

  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
        )'

首先我要说的是,除了实施正确的索引策略之外,您还应该遵循一些优化查询执行时间的技巧。

  • 避免在内部 SELECT 和 JOIN 语句中使用函数。应该为尽可能少的记录执行函数(即使在缓存时),通常,这发生在最外层 select.
  • 尽可能避免子查询,而是选择 JOIN。
  • 尽可能避免在 where 语句中使用非数字字段,对 INT 字段的索引扫描比 VARCHAR 快得多。
  • 避免使用 WITH(NOLOCK) 提示,因为您还将读取未提交的数据。它不会使查询速度更快,并且您将拥有一个潜在的脏数据集。

尝试优化查询时,还要记住查询 "interpreter" 用来解析它的操作顺序:

  1. 从和加入块
  2. 分组依据
  3. 哪里
  4. SELECT

因此请尝试编写您的查询以减少每个块按此顺序返回的数量或记录。

也就是说,必须根据使用的查询创建一个 INDEX,如果您测试包含执行计划的查询执行,您会发现一个有用的提示,通常 SSMS 对您有很大帮助。

在这种情况下,我会在 URLTimeStamp 字段上添加一个索引,顺序为

CREATE CLUSTERED INDEX idx_Log ON yourDatabase.dbo.[log] (URL, Timestamp)