Acabei de começar a usar OPENJSON
com o SQL Server 2016 SP1.
Eu tenho esta frase:
select c.Serial as Parent,
(Select co.Serial, agc.Position
from AggregationChildren agc, Aggregation ag, Code co
where agc.AggregationId = a.AggregationId
and co.CodeId = agc.AggregationChildrenId for json path) as children
from Aggregation a, Code c
where c.CodeId = a.AggregationId for json path
Para gerar este JSON:
{"Parent":"4244287599479491","Children":
[{"Serial":"8915753733724633","Position":"1"},
{"Serial":"1247782815710855","Position":"2"},
...]}
Mas é muito muito lento.
Meu problema é com o Children
array porque não sei como obtê-lo.
Existe uma maneira de fazer isso mais rápido?
Estas são as tabelas:
CREATE TABLE [dbo].[Code] (
[CodeId] INT IDENTITY (1, 1) NOT NULL,
[Serial] NVARCHAR (20) NOT NULL,
[ ... ],
CONSTRAINT [PK_CODE] PRIMARY KEY CLUSTERED ([CodeId] ASC),
[ ... ]
)
CREATE TABLE [dbo].[Aggregation] (
[AggregationId] INT NOT NULL,
[ ... ],
CONSTRAINT [PK_AGGREGATIONS] PRIMARY KEY CLUSTERED ([AggregationId] ASC),
CONSTRAINT [FK_Aggregation_Code]
FOREIGN KEY ([AggregationId])
REFERENCES [dbo].[Code] ([CodeId])
)
CREATE TABLE [dbo].[AggregationChildren] (
[AggregationChildrenId] INT NOT NULL,
[AggregationId] INT NOT NULL,
[Position] INT NOT NULL,
CONSTRAINT [PK_AGGREGATION_CHILDS] PRIMARY KEY CLUSTERED ([AggregationChildrenId] ASC),
CONSTRAINT [FK_AggregationChildren_Code]
FOREIGN KEY ([AggregationChildrenId])
REFERENCES [dbo].[Code] ([CodeId]),
CONSTRAINT [FK_AggregationChildren_Aggregation]
FOREIGN KEY ([AggregationId])
REFERENCES [dbo].[Aggregation] ([AggregationId]) ON DELETE CASCADE
)
A Serial
coluna é uma, nvarchar(20)
pois os valores podem ser qualquer combinação de alfanuméricos, embora meu exemplo mostre apenas números.
Tive dificuldade em analisar sua consulta, porém acredito que isso retorne o mesmo resultado e seja muito mais rápido:
O plano para a consulta acima se parece com:
O plano para sua consulta se parece com:
Se adicionarmos o seguinte índice, podemos tornar a primeira variante ainda mais rápida:
Claramente, você precisaria avaliar isso em relação à sua carga de trabalho, no entanto.
Eu criei uma configuração de exemplo completa minimamente viável para usar para testes:
Eu reformulei as cláusulas de restrição para mais gentis com meu cérebro; essencialmente, o código acima é o mesmo que o DDL em sua pergunta.
Isso preenche as três tabelas com dados suficientes para fazer comparações significativas:
Estas são as contagens de linhas para cada tabela:
Minha versão da consulta:
Para comparar a saída de ambas as consultas, criei duas funções definidas pelo usuário, como em:
Agora, posso comparar a saída de ambas as consultas por meio de:
O resultado é:
Os resultados NÃO coincidem. A saída da minha consulta contém menos nós filho do que sua consulta. Vou voltar à prancheta e simplificar o banco de testes para ver onde está a disparidade.
O testbed simplificado consiste em 10 linhas na
Code
tabela, 2 linhas naAggregation
tabela (pai) e 8 linhas naAggregationChildren
tabela (filho):Contagens de linhas:
O padrão previsto deve ser dois arrays json pai, cada um com 4 arrays filhos.
Meus resultados:
Sua pergunta:
Sua consulta tem muitos filhos; minha consulta retorna o número previsto de filhos, e retorna os
Position
valores corretos, porém está retornando osSerial
valores incorretos.O "bug" na minha consulta aparece na consulta interna. A consulta incorreta é:
A versão correta é:
A consulta corrigida agora se parece com:
E retorna o seguinte resultado: