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 / 227747
Accepted
Frederik Vanderhaegen
Frederik Vanderhaegen
Asked: 2019-01-23 01:46:45 +0800 CST2019-01-23 01:46:45 +0800 CST 2019-01-23 01:46:45 +0800 CST

O loop aninhado tem estimativas muito baixas devido a dados distorcidos

  • 772

No SQL Server 2016 SP2, temos uma consulta que tem uma estimativa muito baixa no operador de loop aninhado. Devido à estimativa baixa, essa consulta também é derramada no tempdb.

Se estiver correto, o SQL Server 2014+ usa a estimativa de histograma grosseiro para calcular o número estimado de linhas em uma junção.
Mas quando executo a consulta, o SQL Server usa o vetor de densidade para calcular o número de linhas estimadas.
O SQL Server está usando apenas a estimativa de histograma grosseiro se não houver nenhuma wherecláusula?

Normalmente eu usaria estatísticas filtradas para melhorar as estimativas quando tenho uma tabela com dados distorcidos. Mas neste caso isso não parece funcionar.

Existe uma maneira de melhorar as estimativas no loop aninhado?

Usando o código a seguir, você pode reproduzir os dados:

create table MyTable
(
    id int identity,
    field varchar(50),
    constraint  pk_id primary  key clustered (id)
)
go

create table SkewedTable
(
    id int identity,
    startdate datetime,
    myTableId int,
    remark varchar(50),
    constraint  pk_id primary  key clustered (id)
)

set nocount on

insert into MyTable select top 1000 [name] from master..spt_values
go

insert into SkewedTable select GETDATE(),FLOOR(RAND()*(1000))+1,REPLICATE(N'A',FLOOR(RAND()*(40))+1)
go 1000

insert into SkewedTable select GETDATE(),FLOOR(RAND()*(1000))+1,REPLICATE(N'A',FLOOR(RAND()*(40))+1)
go 

CREATE NONCLUSTERED INDEX [ix_field] ON [dbo].[MyTable]([field] ASC)
go

CREATE NONCLUSTERED INDEX [ix_mytableid] ON [dbo].[SkewedTable]([myTableId] ASC)
go

--95=varchar in sys.messages
set nocount off

;with cte as
( 
    select GETDATE() as startdate ,95 as myTableId, REPLICATE(N'B',FLOOR(RAND()*(40))+1) as remark
    union all
    select * from cte
)
insert into skewedtable select top 40000 * from cte
option(maxrecursion 0)
go

update statistics mytable with fullscan
go

update statistics skewedtable with fullscan
go
sql-server performance
  • 2 2 respostas
  • 688 Views

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2019-01-23T02:31:38+08:002019-01-23T02:31:38+08:00

    Normalmente eu usaria estatísticas filtradas para melhorar as estimativas quando tenho uma tabela com dados distorcidos. Mas neste caso isso não parece funcionar.

    Você deve achar útil a seguinte estatística filtrada:

    CREATE STATISTICS [stats id (field=varchar)]
    ON dbo.MyTable (id)
    WHERE field = 'varchar'
    WITH FULLSCAN;
    

    Isso fornece ao otimizador informações sobre a distribuição de idvalores que correspondem field = 'varchar' a , fornecendo uma estimativa de seletividade muito melhor para a junção:

    Plano de execução real

    O plano de execução acima mostra estimativas exatamente corretas com a estatística filtrada, levando o otimizador a escolher uma junção de hash (por motivos de custo).

    Esta informação de distribuição é muito mais importante do que o método exato usado pelo estimador para combinar os histogramas de junção ( alinhamento fino ou grosseiro ), ou mesmo as suposições gerais (por exemplo, junção simples, contenção de base).

    Se você não puder fazer isso, suas opções são amplamente descritas na resposta à sua pergunta anterior Classificar spills to tempdb devido a varchar(max) . Minha preferência provavelmente seria uma tabela temporária intermediária.

    • 7
  2. Randi Vertongen
    2019-01-23T03:28:00+08:002019-01-23T03:28:00+08:00

    Concordo completamente com o índice filtrado, esta resposta é adicionada para expandir a outra opção que @PaulWhite mencionou, para usar uma tabela temporária intermediária e, consequentemente, se livrar do SORToperador

    Você pode adicionar um índice ou alterar o índice existente:

    CREATE INDEX IX_SkewedTable_MytableId_startdate
    ON SkewedTable(myTableId,startdate)
    INCLUDE(remark);
    

    Insira os valores em uma tabela temporária intermediária

    CREATE TABLE  #temp2(param int);
    INSERT INTO  #temp2(param)
    SELECT t.id 
    FROM mytable t 
    WHERE t.field = 'varchar';
    

    insira a descrição da imagem aqui

    Adicionar um índice na tabela temporária

    CREATE INDEX IX_ID on #temp2(param);
    

    E, em seguida, use um CTE para remover o operador de classificação do plano de consulta

    ;WITH CTE AS
    (
    select TOP(999999999999)
    s.myTableId,s.id,s.remark from 
    SkewedTable s
    order by startdate
    )
    SELECT s.id , s.remark
    from CTE  s
    INNER JOIN #temp2 
    on s.myTableId = #temp2.param
    OPTION(RECOMPILE)
    

    Conforme mencionado por @Forrest para diminuir a classificação aqui

    Resultado:

    insira a descrição da imagem aqui

    O que remove o operador de classificação.

    • 0

relate perguntas

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

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