AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 285526
Accepted
Michael B
Michael B
Asked: 2021-02-17 19:21:43 +0800 CST2021-02-17 19:21:43 +0800 CST 2021-02-17 19:21:43 +0800 CST

Procedimentos usando TVPs são mais lentos quando o valor numérico de TVP fica maior?

  • 772

Um aplicativo legado tem um trabalho noturno que chama repetidamente algum procedimento de armazenamento usando um TVP e passa em lotes de 10.000 ids que estão em ordem sequencial que ele precisa processar. Agora que os IDs estão na casa dos milhões, parece que esse processo está demorando visivelmente mais. Quase o mesmo número de chamadas em lote está sendo executado todas as noites, mas pelo perfil parecia que o procedimento estava ficando mais lento. Verificamos os culpados usuais, reconstruímos os índices e atualizamos as estatísticas nas tabelas em uso e tentamos fazer uma recompilação no procedimento. Mas nada corrigiu a regressão.

O procedimento faz algum processamento e retorna alguns resultados, cada um com uma cardinalidade de talvez 10.000 linhas. Um dos meus colegas olhou para ele e corrigiu a regressão de desempenho atualizando o procedimento de armazenamento simplesmente adicionando o seguinte ao topo da consulta:

select id into #t from @ids

e substituindo todos os usos de @idspor #t.

Fiquei impressionado com essa correção simples e estava tentando entendê-la mais. Tentei criar uma reprodução muito simples.

create table dbo.ids
(
   id int primary key clustered,
   timestamp
);

create type dbo.tvp as table(id int primary key clustered)

insert into dbo.ids(id)
select row_number() over (order by 1/0)
from string_split(space(1414),' ') a,string_split(space(1414),' ') b
go
create or alter procedure dbo.tvp_proc
(
    @ids dbo.tvp readonly
)
as
begin
    declare @_ int = 0, @r int = 5;
    while(@r > 0)
        select @_ = count(*), @r -= 1
        from dbo.ids i
        where exists (
            select 1
            from @ids t
            where t.id = i.id     
        );
end 
go
create or alter procedure dbo.temp_proc
(
    @ids dbo.tvp readonly
)
as
begin
    select * into #t from @ids
    declare @_ int = 0, @r int = 5;
    while(@r > 0)
        select @_ = count(*), @r -= 1
        from dbo.ids i
        where exists (
            select 1
            from #t t
            where t.id = i.id     
        );
end

E aqui está o meu benchmark simples.

set nocount on;
declare @s nvarchar(4000)=
'declare @ids tvp;
insert into @ids(id)
select @init + row_number() over (order by 1/0)
from string_split(space(99),char(32)) a,string_split(space(99),char(32)) b
declare @s datetime2 = sysutcdatetime()
create table #d(_ int)
insert into #d
exec dbo.tvp_proc @ids
print concat(right(concat(space(10),format(@init,''N0'')),10),char(9),datediff(ms, @s, sysutcdatetime()))',
@params nvarchar(20)=N'@init int'
print 'tvp result'
exec sp_executesql @s,@params,10000000
exec sp_executesql @s,@params,1000000
exec sp_executesql @s,@params,100000
exec sp_executesql @s,@params,10000
select @s=replace(@s,'tvp_proc','temp_proc')
print 'temp table result'
exec sp_executesql @s,@params,10000000
exec sp_executesql @s,@params,1000000
exec sp_executesql @s,@params,100000
exec sp_executesql @s,@params,10000

A execução deste benchmark na minha máquina produz os seguintes resultados:

tvp result
10,000,000  653
 1,000,000  341
   100,000  42
    10,000  12
temp table result
10,000,000  52
 1,000,000  60
   100,000  57
    10,000  59

Os resultados mostram que a abordagem tvp parece desacelerar à medida que os ids internos aumentam, enquanto a tabela temporária permanece bastante consistente. Alguém tem uma idéia de por que referenciar um tvp com valores maiores é mais lento que uma tabela temporária?

sql-server-2016 table-valued-parameters
  • 1 1 respostas
  • 288 Views

1 respostas

  • Voted
  1. Best Answer
    J.D.
    2021-02-17T19:57:48+08:002021-02-17T19:57:48+08:00

    As variáveis ​​de tabela , mesmo quando usadas como parâmetro ( TVP ), recebem estimativas de cardinalidade muito ruins , em oposição às tabelas temporárias , que são estimadas com muito mais precisão. Essa diferença é especialmente perceptível à medida que aumenta a quantidade de dados que estão sendo utilizados em uma TVP vs Temp Table . Se você observar atentamente o número estimado de linhas versus o número real de linhas nos planos de execução de cada implementação, verá que as tabelas temporárias são estimadas com muito mais precisão.

    Você pode ler mais sobre TVPs e suas desvantagens neste post de Jeremiah Peschka . Especificamente a seção Gotchas :

    Primeiro: a variável de tabela que vem como parâmetro com valor de tabela não pode ser alterada. Você está preso a quaisquer valores que apareçam. Nenhuma inserção, atualização ou exclusão pode ser aplicada.

    Segundo: parâmetros com valor de tabela ainda são variáveis ​​de tabela – eles recebem estimativas de cardinalidade terríveis.

    Podemos contornar esses dois problemas com a mesma técnica – copie o conteúdo do TVP em uma tabela temporária.

    Além disso, TVPs usados ​​em procedimentos podem resultar em problemas de sniffing de parâmetros , como este outro post detalha. Esta citação adiciona alguns detalhes às estimativas de cardinalidade que você encontrará com TVPs , independentemente do tamanho da variável de tabela real :

    As variáveis ​​de tabela (a menos que você recompile ou use um sinalizador de rastreamento) exibirão uma estimativa de 1 ou 100 linhas, dependendo de qual versão do Estimador de cardinalidade você usa. A versão antiga adivinha 1 linha, a nova adivinha 100 linhas.

    Este é um bom artigo adicional sobre questões de estimativa de cardinalidade que resultam de Table Variables , de Pinal Dave.


    Uma das principais razões pelas quais ter uma estimativa de cardinalidade ruim , como uma subestimativa nesse caso, é porque isso resultará no provisionamento insuficiente do SQL Engine dos recursos de servidor necessários para processar a consulta e fornecer os dados. Por exemplo, sua consulta provavelmente está solicitando muito menos memória do que precisa para ser processada devido à estimativa de baixa cardinalidade , fazendo com que o SQL Engine pense que há muito menos linhas a serem retornadas do que realmente haverá. Quanto maior for a variável da tabela , maior será a discrepância entre a estimativa e a real .


    Você deve sempre optar por Temp Tables quando possível pelo motivo pelo qual elas têm muito mais benefícios de desempenho do que uma Table Variable e podem fazer quase tudo que uma Table Variable pode fazer e muito mais. Nos casos em que você precisa usar uma variável de tabela , selecioná-la primeiro em uma tabela temporária e usar essa tabela temporária em sua consulta subsequente é o caminho a seguir.

    • 3

relate perguntas

  • Msg 39011 O SQL Server não conseguiu se comunicar com o serviço LaunchPad

  • Cláusula Where para filtrar linhas para o Azure Stretch Database?

  • As tabelas temporais serão incluídas na Standard Edition do SQL Server 2016?

  • Não é possível obter o serviço SQL Server 2016 CTP3 para iniciar no Windows 10

  • Segurança em nível de linha no SQL Server 2016 com um esquema normalizado

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve