Estou tendo um desempenho ruim em uma instrução de inserção/atualização de linha única em uma tabela quando uma coluna nvarchar(max) tem poucos MB de dados.
Aqui minha estrutura de tabela:
CREATE TABLE [dbo].[tbl_set_Cart](
[ID] [int] NOT NULL,
[AS400_CUSTOMER_COD] [nvarchar](50) NOT NULL,
[AS400_LISTIN] [int] NOT NULL,
[VALUE] [nvarchar](max) NOT NULL,
[DELIVERY_COSTS] [nvarchar](max) NOT NULL,
[ITEMS_COUNT] [int] NOT NULL,
[ITEMS] [nvarchar](max) NOT NULL,
[KIND] [int] NOT NULL,
[CHECKOUT_INFO] [nvarchar](max) NOT NULL,
[ISSUES] [nvarchar](max) NOT NULL,
[LAST_CHECK] [datetime] NOT NULL,
[USER_ID] [int] NOT NULL,
[IMPERSONATED_USER_ID] [int] NOT NULL,
[OVERRIDE_PRICES] [bit] NOT NULL,
[HAS_ISSUE] [bit] NOT NULL,
[IS_CONFIRMED] [bit] NOT NULL,
[IS_COLLECTED] [bit] NOT NULL,
[_METADATA] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_tbl_set_Cart] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Aqui um exemplo de uma declaração de atualização
DECLARE @p0 AS INT = [cart_id];
DECLARE @p1 AS INT = [entry_count];
DECLARE @p2 AS NVARCHAR(MAX) = '..document..' --~8MB;
UPDATE [dbo].[tbl_set_Cart]
SET [ITEMS_COUNT] = @p1, [ITEMS] = @p2
WHERE [ID] = @p0
Executando este comando na mesma máquina do banco de dados (um ambiente de desenvolvimento para que não haja outra carga de trabalho) obtive este desempenho:
Realmente me surpreende que seja tão lento carregar um texto no SQL Server, então o que estou perguntando é se há uma maneira melhor de conseguir isso.
O documento é um grande JSON que não excederá os 10 MB de dados (eu fiz o benchmark relatado acima no pior cenário) e não tenho problemas em convertê-lo em um BLOB ou outras estruturas de dados se o desempenho melhorar. Se for uma ideia melhor, também posso usar um procedimento armazenado para carregar o texto grande.
Meio Ambiente:
Um processador lógico Windows Server 2019 16 2,1 GHz e Microsoft SQL Server Standard (64 bits) versão 15.0.2070.41 com 4 GB de RAM reservada, 16 núcleos licenciados.
(é um ambiente apenas de desenvolvimento e, neste caso, sou o único trabalhando sem nenhum outro programa ou atividade agendada em execução.)
Testei novamente um carrinho diferente (um pouco menor) aqui vezes (estatísticas do cliente) e plano de execução.
link aqui: https://www.brentozar.com/pastetheplan/?id=SJcPhDUFK
Se eu inserir uma nova linha é mais rápido:
link aqui: https://www.brentozar.com/pastetheplan/?id=S1FDjD8KF
Para a instrução insert, usei os dados gerados pelo SQL Server (tarefa -> tabela de scripts -> somente dados)
O que espero alcançar é um tempo de atualização <0,5s
No meu cenário o json geralmente nasce pequeno e depois aumenta dia a dia até o tamanho que estou testando. Posso começar a pensar em armazená-los como arquivo?
Eu pré-aloquei espaço no arquivo de log. E verifique novamente se o modelo de recuperação está definido como simples. O que posso fazer para melhorar ainda mais o desempenho?
Seu plano de atualização lenta mostra uma longa espera em
LOGBUFFER
:Você deve verificar se o arquivo de log do banco de dados está em armazenamento rápido o suficiente para a carga de trabalho.
Também pode haver algum benefício em aumentar a quantidade de RAM disponível para a instância. A
PAGEIOLATCH_EX
espera também é bastante longa em 361ms.Como David Browne sugeriu, você também pode:
COMPRESS
o JSON para mudar parte do IO para a CPU.PAGEIOLATCH
esperas.Eu sugiro que você tente colocar/copiar as informações do json em um arquivo para um diretório "local" (no ou próximo ao servidor db) e, em seguida, use o
OPENROWSET BULK
recursoconsulte https://techcommunity.microsoft.com/t5/sql-server-blog/importing-json-files-into-sql-server-using-openrowset-bulk/ba-p/384480