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 / 245544
Accepted
i-one
i-one
Asked: 2019-08-17 08:44:15 +0800 CST2019-08-17 08:44:15 +0800 CST 2019-08-17 08:44:15 +0800 CST

Junção de varredura constante

  • 772

Na preparação da minha pergunta anterior do Constant Scan, eu estava experimentando VALUESde várias maneiras e me deparei com a coisa sobre a junção VALUESque parece estranha para mim.

A configuração é simples

CREATE TABLE #data ([Id] int);
INSERT INTO #data VALUES (101), (103);

Então há uma consulta

DECLARE @id1 int = 101, @id2 int = 102;

SELECT *
FROM (VALUES (@id1), (@id2)) p([Id])
    FULL HASH JOIN #data d ON d.[Id] = p.[Id];

Não há nada de especial nisso. Ele funciona e produz seu resultado, se você executá-lo. Aqui está o seu plano de execução

Plano de adesão Constant Scan

Removendo uma linha de VALUESno entanto

SELECT *
FROM (VALUES (@id1)) p([Id])
    FULL HASH JOIN #data d ON d.[Id] = p.[Id];

faz com que o otimizador falhe

Msg 8622, Level 16, State 1, Line 1
Processador de consultas não pôde produzir um plano de consulta...

Por quê? Existe uma maneira (além de colocar o parâmetro na tabela temporária) para fazê-lo funcionar usando o algoritmo de hash?

Observação: isso não é um dispositivo real e serve para estudar o comportamento e os recursos do otimizador.


O exemplo acima foi testado em

Microsoft SQL Server 2017 (RTM-CU15-GDR) (KB4505225) - 14.0.3192.2 (X64)

sql-server optimization
  • 1 1 respostas
  • 447 Views

1 respostas

  • Voted
  1. Best Answer
    i-one
    2019-08-17T08:44:15+08:002019-08-17T08:44:15+08:00

    Por quê?

    Dizendo em resumo. Por causa dos HASHtiros de dica para a perna do otimizador e do próprio otimizador para o outro. Ser baleado no otimizador não pode cruzar a linha de chegada.


    Para ilustrar melhor o que está acontecendo, vamos reescrever a consulta problemática para unir duas VALUESe usar o algoritmo de mesclagem

    DECLARE @id1 int = 101, @id3 int = 103;
    
    SELECT *
    FROM (VALUES (@id1)) p([Id])
        FULL MERGE JOIN (VALUES (@id1), (@id3)) d([Id]) ON d.[Id] = p.[Id];
    

    O plano de execução desta consulta é simples. Existe o operador Merge Join com duas entradas Constant Scan.

    Plano de execução

    Esses dois Constant Scans são diferentes do otimizador.

    Propriedades do plano de execução

    O que representa a entrada de linha única tem o nome da coluna prefixado com Expr, enquanto o outro que representa a entrada de várias linhas tem o nome da coluna prefixado com Union. Os dados de Constant Scan de várias linhas são acessados ​​nos predicados Merge Join como um tipo de "por referência" ( [Union1001]), enquanto os dados de Constant Scan de uma única linha são acessados ​​como "por valor" (veja que @id1é substituído em vez de [Expr1000]).

    Essa substituição "por referência"→"por valor" é o resultado do mapeamento escalar realizado nos estágios iniciais de otimização.

    Pode-se ver (usando o sinalizador de rastreamento 8606) que no predicado de junção da Árvore de Entrada é[Union1001] = [Expr1000]

    *** Árvore de entrada: ***
        ...
        LogOp_FullOuterJoin
            ...
            ScaOp_Comp x_cmpEq
                ScaOp_Identifier COL: Union1001
                ScaOp_Identifier COL: Expr1000
        ...
    

    mas então na Árvore Simplificada torna-se[Union1001] = @id1

    *** Árvore simplificada: ***
        LogOp_FullOuterJoin
            ...
            ScaOp_Comp x_cmpEq
                ScaOp_Identifier COL: Union1001
                ScaOp_Identifier COL: @id1
    

    O mapeamento escalar é a parte da lógica de extração de projeção e é realmente executado antes que o estágio de simplificação seja inserido.

    Pode-se ter notado anteriormente que o nó Merge Join possui apenas predicado residual e nenhum predicado de igualdade de junção. Isso ocorre porque o predicado de igualdade de junção foi eliminado pelo mapeamento escalar. O [Union1001] = @id1predicado é de igualdade, mas não pode servir como um predicado de igualdade de junção . Para ser assim, ele deve referenciar colunas de ambas as entradas, mas @id1é variável e não uma coluna.

    Portanto, sendo equijoin ON d.[Id] = p.[Id]originalmente, a consulta se transformou em non-equijoin (que é um caso especial e, por causa disso, a propósito, o otimizador não introduziu a classificação abaixo de Merge Join para as entradas Constant Scan não classificadas). Felizmente, no caso do otimizador de algoritmo de mesclagem, há essa alternativa não equijoin.

    No caso de usar o algoritmo de hash, a alternativa não equijoin não existe e, portanto, a eliminação do predicado de igualdade de junção faz com que o otimizador falhe posteriormente.


    Existe uma maneira (além de colocar o parâmetro na tabela temporária) para fazê-lo funcionar usando o algoritmo de hash?

    Não há sinalizador de rastreamento (*) que impeça o mapeamento escalar, nem alavanca de consulta nem nível de sessão nem inicialização. E não existe uma regra de otimização que possa ser desativada para preveni-la, pois ela não é executada por uma regra.

    Eu só consegui executar a consulta problemática definindo o ponto de interrupção na COptExpr::PexprMapScalarrotina

    insira a descrição da imagem aqui

    e modificando o valor do eaxregistro após a chamada para ScaOp_Identifier::ClassNofazer o SQL Server pensar que o segundo operando de ScaOp_Compnão é identificador.

    Aqui está a árvore simplificada da consulta problemática postada na pergunta

    *** Árvore simplificada: ***
        LogOp_FullOuterJoin
            LogOp_ConstTableGet (1) COL: Expr1000
                ScaOp_Identifier COL: @id1
            LogOp_Get TBL: #data(alias TBL: d)
            ScaOp_Comp x_cmpEq
                ScaOp_Identifier QCOL: [d].Id
                ScaOp_Identifier COL: Expr1000
    *******************
    

    e aqui está seu plano obtido.

    Na verdade, tem pouco sentido, porque o custo do plano obtido é de 0,0210675 unidades, enquanto a execução da consulta sem HASHdica leva ao plano de execução com o Merge Join (observe que não há classificação abaixo do Merge Join novamente)

    Plano de execução sem dica

    custando 0,0088948 unidades.


    (*) Pode existir uma combinação de sinalizadores de rastreamento . Eu acho que não, mas eu não explorei todos os caminhos de código, então não tenho certeza.

    • 7

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

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

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

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