使用 CROSS APPLY OPENJSON 导致 Azure 挂起

Dar*_*ren 5 performance azure-sql-database cross-apply sql-server-2017

我有一个包含大约 800 万行的表,其架构为:

CREATE TABLE [dbo].[Documents](
    [Id] [uniqueidentifier] NOT NULL,
    [RemoteId] [int] NOT NULL,
    [Json] [nvarchar](max) NULL,
    [WasSuccessful] [bit] NOT NULL,
    [StatusCode] [int] NULL,
    [Created] [datetime2](7) NULL,
 CONSTRAINT [PK_Documents] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[Documents] ADD  CONSTRAINT [DF_Documents_Id]  DEFAULT (newsequentialid()) FOR [Id]
GO

ALTER TABLE [dbo].[Documents] ADD  CONSTRAINT [DF_Documents_Created]  DEFAULT (getdate()) FOR [Created]
GO
Run Code Online (Sandbox Code Playgroud)

json 文件的结构为

{
    "Id": 1,
    "Data": [
        {
            "Id": 99,
            "Name": "Person 1"
        },
        {
            "Id": 100,
            "Name": "Person 2"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试从文档中提取 JSON 数组,并使用以下查询将其插入到新表中:

;WITH CTE (Json) AS 
(
    SELECT TOP 10
        JSON_QUERY([Json], '$.Data')
    FROM 
        Documents
    WHERE 
        ISJSON([Json]) > 0
)
INSERT INTO [dbo].[ParsedDocuments] (Id, Name)
SELECT
    JSON_VALUE([Value], '$.Id') AS [Id],
    JSON_VALUE([Value], '$.Name') AS [Name],
FROM 
    CTE
CROSS APPLY 
    OPENJSON([Json]) as X
Run Code Online (Sandbox Code Playgroud)

我发现的是,如果我提取并查询数据样本,比如 1000 行。一切都按预期工作,数据被插入到目标表中。但是,当我查询主表时,服务器似乎只是挂起并且没有响应。

我怀疑它在插入数据之前试图对所有行运行交叉应用。有什么办法可以提高性能吗?或者允许作业开始将结果“流式传输”到目标表中,而不是尝试将它们批处理?

最后,如您所见,我使用了“TOP 10”结果。然而,我仍然遇到性能挂起。我不确定为什么。

大表的查询计划永远不会生成,当针对数据样本运行时,如何在此处找到查询计划。

Pau*_*ite 7

您甚至无法获得针对大表的查询的估计执行计划这一事实表明编译正在等待该nvarchar(max)列的统计信息创建(或更新)。

当针对较小的样本表运行时,统计信息的创建会很快完成,因此可以快速创建执行计划。

我可以在低功耗 (S0) Azure SQL 数据库上重现您的情况。在稍微不那么贫血的 S3 实例上,由于读取nvarchar(max)列以生成统计信息涉及大量 I/O,编译仍然需要大约 30 秒。需要高级层才能获得良好的 I/O 性能 - 即使是冷 P1 也可以在 3 秒左右的时间内创建这些统计信息。

您可以通过暂时禁用自动统计创建来确认原因:

ALTER DATABASE CURRENT SET AUTO_CREATE_STATISTICS OFF;
Run Code Online (Sandbox Code Playgroud)

然后 SQL 服务器将快速生成一个计划,尽管会出现有关缺少统计信息的警告:

没有统计数据的计划

请务必在测试后重新启用此功能,因为良好的统计信息对于总体执行计划质量至关重要。或者承诺手动创建必要的统计信息。

如果问题是自动刷新过时的统计数据,您可以选择异步更新这些:

ALTER DATABASE CURRENT SET AUTO_UPDATE_STATISTICS_ASYNC ON;
Run Code Online (Sandbox Code Playgroud)

或者,将 Azure SQL 数据库扩展到适合您的工作负载和预算的性能级别。