索引插入期间的多个表假脱机(Eager假脱机)

时间:2016-11-17 20:44:33

标签: sql-server tsql sql-server-2008-r2 query-optimization

我正在执行几百行的简单插入,例如:

INSERT INTO Foo
SELECT * FROM Bar

该表有一些二级索引。禁用这些索引后,查询几乎立即运行。启用二级索引后,查询需要几秒钟才能运行,并且子树成本相对较高。

问题在于,对于每个二级索引,数据库都会执行:

它缓存的地方:

    在destiation表中
  • 所有列(当它只需要它需要的值时)
  • 多次值(而不是一次)

enter image description here

虽然知道为什么 SQL Server(2008 R2 SP2)认为它需要这样做可能很有趣,但我真正需要的是一种在实时服务器中插入100行而不采取的方法六秒钟

真正,非常可怕的部分是每个每个表假脱机,SQL Server缓存每个列的值,时间:

enter image description here

这只是刻录逻辑IO。

  • 如果没有这些有问题的索引更新,则会在一两秒内完成导入60,000行
  • 使用这些索引,完全导入需要几十分钟

重现步骤

当然,我的真实 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

你问的等待时间?

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

IO_COMPLETION中执行6s的4.55秒:

  

在等待I / O操作完成时发生。此等待类型通常表示非数据页I / O.数据页面I / O完成等待显示为PAGEIOLATCH_ *等待。

你说的非冗余索引?

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

没有排序警告

批处理的SQL Server Profiler结果

  • 持续时间:7,401 ms
  • 阅读:233,597
  • 写入:17,077
  • CPU :1,141 ms

没有排序警告。也没有注意位图警告执行警告哈希警告缺少列统计信息< / strong>,缺少加入谓词排序警告用户错误消息

索引全部重建。所有统计数据都已更新。

1 个答案:

答案 0 :(得分:-1)

重叠和冗余索引存在问题。

此qry会有所帮助:T-SQL for finding Redundant Indexes