Sql server 索引插入期间的多个表假脱机(即时假脱机)
我正在执行几百行的简单插入,例如:Sql server 索引插入期间的多个表假脱机(即时假脱机),sql-server,tsql,sql-server-2008-r2,query-optimization,Sql Server,Tsql,Sql Server 2008 R2,Query Optimization,我正在执行几百行的简单插入,例如: INSERT INTO Foo SELECT * FROM Bar 该表有几个二级索引。禁用这些索引后,查询几乎立即运行。启用辅助索引后,查询运行需要几秒钟,子树成本相对较高 问题在于,对于每个辅助索引,数据库都会执行以下操作: 物理操作: 逻辑操作: 其缓存位置: 目标表中的所有列(当它只需要所需的值时) 多次值(而不是一次) 虽然了解SQL Server(2008 R2 SP2)为什么认为需要这样做可能很有趣,但我真正需要的是一种方法,使在实时
INSERT INTO Foo
SELECT * FROM Bar
该表有几个二级索引。禁用这些索引后,查询几乎立即运行。启用辅助索引后,查询运行需要几秒钟,子树成本相对较高
问题在于,对于每个辅助索引,数据库都会执行以下操作:
- 物理操作:
- 逻辑操作:
- 目标表中的所有列(当它只需要所需的值时)
- 多次值(而不是一次)
- 如果没有这些有问题的索引更新,60000行的完整导入只需一两秒钟
- 有了这些索引,完整的导入几乎需要几十分钟
AuditLog
表包含4M行。但我们可以使用空的AuditLog表以高子树成本复制完全相同的运算符:
CREATE TABLE [dbo].[AuditLog](
[AuditLogID] [int] IDENTITY(216,1) NOT NULL,
[ChangeDate] [datetime] NOT NULL CONSTRAINT [DF_AuditLog_ChangeDate] DEFAULT (getdate()),
[RowGUID] [uniqueidentifier] NOT NULL,
[ChangeType] [varchar](50) NOT NULL,
[TableName] [varchar](128) NOT NULL,
[FieldName] [varchar](128) NOT NULL,
[OldValue] [varchar](max) NULL,
[NewValue] [varchar](max) NULL,
[SystemUser] [varchar](128) NULL CONSTRAINT [DF_AuditLog_SystemUser] DEFAULT (suser_sname()),
[Username] [varchar](128) NOT NULL CONSTRAINT [DF_AuditLog_Username] DEFAULT (user_name()),
[Hostname] [varchar](50) NOT NULL CONSTRAINT [DF_AuditLog_Hostname] DEFAULT (host_name()),
[AppName] [varchar](128) NULL CONSTRAINT [DF_AuditLog_AppName] DEFAULT (app_name()),
[UserGUID] [uniqueidentifier] NULL,
[TagGUID] [uniqueidentifier] NULL,
[Tag] [varchar](max) NULL,
[timestamp] [timestamp] NOT NULL,
CONSTRAINT [PK_AuditLog] PRIMARY KEY CLUSTERED ([AuditLogID] ASC)
)
我们有痛苦指数:
SET ANSI_PADDING OFF
GO
/****** Object: Index [IX_AuditLog_ChangeDate] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_ChangeDate] ON [dbo].[AuditLog]
(
[ChangeDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [IX_AuditLog_FieldName] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_FieldName] ON [dbo].[AuditLog]
(
[FieldName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [IX_AuditLog_LastRowActionByTable] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_LastRowActionByTable] ON [dbo].[AuditLog]
(
[TableName] ASC,
[ChangeType] ASC,
[RowGUID] ASC,
[UserGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
/****** Object: Index [IX_AuditLog_RowGUID] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_RowGUID] ON [dbo].[AuditLog]
(
[RowGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [IX_AuditLog_RowInsertedByUserGUID] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_RowInsertedByUserGUID] ON [dbo].[AuditLog]
(
[ChangeType] ASC,
[RowGUID] ASC,
[UserGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
/****** Object: Index [IX_AuditLog_RowLastModifiedByUserGUID] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_RowLastModifiedByUserGUID] ON [dbo].[AuditLog]
(
[RowGUID] ASC,
[ChangeDate] ASC,
[UserGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [IX_AuditLog_TableName] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_TableName] ON [dbo].[AuditLog]
(
[TableName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
/****** Object: Index [IX_AuditLog_TagGUID] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_TagGUID] ON [dbo].[AuditLog]
(
[TagGUID] ASC,
[RowGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
/****** Object: Index [IX_AuditLog_UserGUID] Script Date: 11/17/2016 2:58:43 PM ******/
CREATE NONCLUSTERED INDEX [IX_AuditLog_UserGUID] ON [dbo].[AuditLog]
(
[ChangeDate] ASC,
[UserGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
然后我们创建插入:
INSERT INTO AuditLog(
RowGUID,
ChangeType,
UserGUID,
TableName,
FieldName,
TagGUID,
Tag)
SELECT
'E5E31EDD-7D39-47FD-BCFF-4B7044AC433D',
'INSERTED',
'4A2FDACD-0209-403B-ADBC-1B8A68E90350', --UserGUID
'Customers', --TableName
'', --FieldName
'7A74267D-64F9-44D7-A1D7-1490A66136BF', --TagGUID
'Contoso'
FROM (
--A dummy derived table that lets us select the above row 100 times
SELECT TOP 400 (a.Number * 256) + b.Number AS Number
FROM (
SELECT number FROM master..spt_values WHERE type = 'P' AND number <= 255) a (Number),
(SELECT number FROM master..spt_values WHERE type = 'P' AND number <= 255) b (Number)
) dt
在以下情况下执行6秒的4.55秒:
在等待I/O操作完成时发生。此等待类型通常表示非数据页I/O。数据页I/O完成等待显示为PAGEIOLATCH_*waitis
你说的非冗余索引?
无排序警告
批处理的SQL Server探查器结果
- 持续时间:7401毫秒
- 阅读:233597
- 写入:17077
- CPU:1141毫秒
所有索引都已重建。所有统计数据都已更新。您有重叠和冗余索引的问题
这个qry会有帮助:这是一个对一个狭窄的。对400行进行假脱机并对其进行6次排序不会在6秒的顺序上产生任何影响。一定还有别的事。你看到了什么样的等待类型?嗯,好吧,它与排序和假脱机等相关,但很难想象,在描述的数据量如此之大的情况下,事情会如此缓慢。假脱机只发生一次,然后重复6次。您在探查器中看到排序警告了吗?您的磁盘显然太忙了,无法完成这样一项平凡的任务。除了SQL Server之外,是否还有其他活动会给他们带来压力?还是并行运行的维护作业?顺便说一句,我在你的索引中看到很多guid。他们的填充因子呢?也许你遇到了页面分割?
| Wait Type | Wait Time (s) | Wait Count |
|----------------|---------------|------------|
| IO_COMPLETION | 4.55 s | 211 |
| WRITELOG | 0.79 s | 37 |
| PAGEIOLATCH_UP | 0.36 s | 1 |
| PAGELATCH_UP | 0.09 s | 2 |
| PAGEIOLATCH_EX | 0.07 s | 4 |
| Index Name | Columns | Index Entry Size |
|---------------------------------------|------------------------------------------|--------------------------|
| IX_AuditLog_ChangeDate | ChangeDate | 12 bytes per entry |
| IX_AuditLog_UserGUID | ChangeDate, UserGUID | 28 bytes per entry |
| IX_AuditLog_FieldName | FieldName | 4 bytes per entry (avg) |
| IX_AuditLog_TableName | TableName | 13 bytes per entry (avg) |
| IX_AuditLog_LastRowActionByTable | TableName, ChangeType, RowGUID, UserGUID | 52 bytes per entry (avg) |
| IX_AuditLog_RowGUID | RowGUID | 20 bytes per entry |
| IX_AuditLog_RowLastModifiedByUserGUID | RowGUID, ChangeDate, UserGUID | 44 bytes per entry |
| IX_AuditLog_RowInsertedByUserGUID | ChangeType, RowGUID, UserGUID | 43 bytes per entry (avg) |
| IX_AuditLog_TagGUID | TagGUID, RowGUID | 36 bytes per entry |