推荐的索引和查询改进
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" 用来解析它的操作顺序:
- 从和加入块
- 分组依据
- 哪里
- SELECT
因此请尝试编写您的查询以减少每个块按此顺序返回的数量或记录。
也就是说,必须根据使用的查询创建一个 INDEX,如果您测试包含执行计划的查询执行,您会发现一个有用的提示,通常 SSMS 对您有很大帮助。
在这种情况下,我会在 URL 和 TimeStamp 字段上添加一个索引,顺序为
CREATE CLUSTERED INDEX idx_Log ON yourDatabase.dbo.[log] (URL, Timestamp)
我有一个跨服务器查询,它将大量行从我们的日志数据库插入到我们的数据仓库。现在的问题是这项工作 运行 超过 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" 用来解析它的操作顺序:
- 从和加入块
- 分组依据
- 哪里
- SELECT
因此请尝试编写您的查询以减少每个块按此顺序返回的数量或记录。
也就是说,必须根据使用的查询创建一个 INDEX,如果您测试包含执行计划的查询执行,您会发现一个有用的提示,通常 SSMS 对您有很大帮助。
在这种情况下,我会在 URL 和 TimeStamp 字段上添加一个索引,顺序为
CREATE CLUSTERED INDEX idx_Log ON yourDatabase.dbo.[log] (URL, Timestamp)