SQL 服务器 INSERT 性能(SQL,Azure SQL 数据库)

SQL Server INSERT Performance (SQL, Azure SQL Database)

我有两个 table,第一个 'A' 包含大约 400k 行和 table 'B' - 12k 行。我需要 select ~350k 行从 table A 插入到 table B.

我在存储过程中执行此操作(因为我需要执行大量其他任务):

INSERT INTO B ("fields")
    SELECT "field" 
    FROM A
    INNER JOIN @TempTable -- this join need for filtering records in table A

Table结构

Table答:

CREATE TABLE [dbo].[A]
(
    [Field1] [uniqueidentifier] NOT NULL,
    [Field2] [int] NOT NULL,
    [Field3] [uniqueidentifier] NOT NULL,
    [Field4] [nvarchar](max) NULL,
    [Field5] [bit] NOT NULL,
    [Field6] [int] NULL,
    [Field7] [tinyint] NULL,

    CONSTRAINT [PK_A] 
        PRIMARY KEY CLUSTERED ([Field1] ASC, [Field2] ASC, [Field3] ASC)
                WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[A] WITH CHECK 
    ADD CONSTRAINT [FK_...] 
        FOREIGN KEY([Field2]) REFERENCES [dbo].[...] ([Id])
GO

ALTER TABLE [dbo].[A] WITH CHECK 
    ADD CONSTRAINT [...] 
        FOREIGN KEY([Field3]) REFERENCES [dbo].[...] ([Id])
GO

ALTER TABLE [dbo].[A] WITH CHECK 
    ADD CONSTRAINT [...] 
        FOREIGN KEY([Field1]) REFERENCES [dbo].[A] ([Id])
GO

Table乙:

CREATE TABLE [dbo].[B]
(
    [Field1] [uniqueidentifier] NOT NULL,
    [Field2] [int] NOT NULL,
    [Field3] [uniqueidentifier] NOT NULL,
    [Field4] [tinyint] NULL,
    [Field5] [nvarchar](max) NULL,
    [Field6] [bit] NOT NULL,
    [Field7] [int] NULL,

    CONSTRAINT [PK_B] 
        PRIMARY KEY CLUSTERED ([Field1] ASC, [Field2] ASC, [Field3] ASC)
                WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[B] WITH CHECK 
    ADD CONSTRAINT [...] 
        FOREIGN KEY([Field2]) REFERENCES [dbo].[...] ([Id])
GO

ALTER TABLE [dbo].[B] WITH CHECK 
    ADD CONSTRAINT [...] 
        FOREIGN KEY([Field3]) REFERENCES [dbo].[...] ([Id])
GO

ALTER TABLE [dbo].[B] WITH CHECK 
    ADD CONSTRAINT [...] 
        FOREIGN KEY([Field1]) REFERENCES [dbo].[...] ([Id])
GO

基础设施:

使用我提到的配置,插入操作需要 1:55 分钟,我尝试只 运行 select 没有插入它只需要 3-5 秒,所以这意味着插入问题。

我已经尝试过的解决方案:

1. 我在插入之前删除了所有索引。这提高了性能,只需要 45 秒,但无论如何应该在插入后创建索引。索引重建需要 ~1 分钟,所以我们得到相同的 ~1:55 分钟。 45秒还是很长的时间。

2. 我尝试使用批次插入(按 5000),这仅减少到 1:35 分钟。

附加信息: 我们不能显着增加“DTU”,因为当应用程序在常规模式下工作时,它不需要超过此资源的 80% (S1 - 20 DTU)

执行计划(带索引): Execution plan with indexes

等待统计(有索引): Wait stats with indexes

执行计划(无索引): Execution plan without indexes

问题:

我找到了一些关于这个问题的信息,以及可能的解决方案:

  1. Table 为 table 'B' 分区,然后使用“分区切换”从非分区 table 'A' 移动数据分区 'B'

  2. 内存中 OLTP。这可以帮助解决这个问题吗?优缺点?

  3. 或者你有你的变体,我在这种情况下如何表现。

谢谢。

查询运行时似乎主要由 IO 等待决定。

这是等待统计数据

PAGEIOLATCH_EX 是等待写入磁盘,PAGEIOLATCH_SH 是等待从磁盘读取,LOG_RATE_GOVERNOR is essentially also an IO wait, waiting to write to the log file. The IO and Log write limits on a 20DTU database are quite small, and the standard tier DTU model provisions only 1-4 IOPS/DTU,所以低于 100 IOPS。

所以你可以

  1. 少写数据

-通过消除列,尤其是 nvarchar(max) 列,如果它很大

- 通过使用页面压缩或聚集列存储索引来压缩数据,或者如果 nvarchar(max) 列很大

,则对 nvarchar(max) 列使用 COMPRESS TSQL 函数

  1. 提供更多资源

-通过扩展到更高的 DTU,或 VCore 配置,或具有弹性扩展的无服务器配置

-通过移动到超大规模,它在每个服务级别提供 100MB/S 的日志吞吐量

-将此数据库移动到弹性池中,以便与其他数据库共享更大的资源池。

Table 分区不会减少写入量。内存中 OLTP 仅在 Premium/Business 关键层中可用,该层已经具有更高的 IOPS。