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 / 244383
Accepted
i-one
i-one
Asked: 2019-08-02 16:28:51 +0800 CST2019-08-02 16:28:51 +0800 CST 2019-08-02 16:28:51 +0800 CST

Spool de varredura constante

  • 772

Eu tenho uma tabela com algumas dezenas de linhas. A configuração simplificada está seguindo

CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);

E eu tenho uma consulta que une essa tabela a um conjunto de linhas construídas com valor de tabela (feitas de variáveis ​​e constantes), como

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

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (@id1, 'A'),
        (@id2, 'B')
    ) p([Id], [Code])
    FULL JOIN #data d ON d.[Id] = p.[Id];

O plano de execução da consulta está mostrando que a decisão do otimizador é usar a FULL LOOP JOINestratégia, o que parece apropriado, pois ambas as entradas possuem poucas linhas. Uma coisa que notei (e não posso concordar), porém, é que as linhas do TVC estão sendo colocadas em spool (veja a área do plano de execução na caixa vermelha).

Spool de varredura constante

Por que o otimizador introduz o spool aqui, qual é a razão para fazê-lo? Não há nada complexo além do carretel. Parece que não é necessário. Como se livrar dele neste caso, quais são as maneiras possíveis?


O plano acima foi obtido em

Microsoft SQL Server 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64)

sql-server execution-plan
  • 2 2 respostas
  • 1144 Views

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2019-08-03T05:46:56+08:002019-08-03T05:46:56+08:00

    Por que o otimizador introduz o spool aqui, qual é a razão para fazê-lo? Não há nada complexo além do carretel.

    A coisa além do spool não é uma simples referência de tabela, que poderia simplesmente ser duplicada quando a alternativa de junção esquerda / anti semijunção é gerada.

    Pode parecer um pouco com uma tabela (Constant Scan), mas para o otimizador* é uma UNION ALLdas linhas separadas na VALUEScláusula.

    A complexidade adicional é suficiente para o otimizador optar por fazer o spool e reproduzir as linhas de origem e não substituir o spool por um simples "obter tabela" posteriormente. Por exemplo, a transformação inicial da junção completa se parece com isso:

    plano antecipado

    Observe os carretéis extras introduzidos pela transformação geral. Os carretéis acima de uma mesa simples são limpos posteriormente pela regra SpoolGetToGet.

    Se o otimizador tivesse uma SpoolConstGetToConstGetregra correspondente, ele poderia funcionar como você deseja, em princípio.

    Como se livrar dele neste caso, quais são as maneiras possíveis?

    Use uma tabela real (temporária ou variável) ou escreva a transformação da junção completa manualmente, por exemplo:

    WITH 
        p([Id], [Code]) AS
        (
            SELECT @id1, 'A'
            UNION ALL
            SELECT @id2, 'B'
        ),
        FullJoin AS
        (
            SELECT
                p.Code,
                d.[Status]
            FROM p
            LEFT JOIN #data d 
                ON d.[Id] = p.[Id]
            UNION ALL
            SELECT
                NULL,
                D.[Status]
            FROM #data AS D
            WHERE NOT EXISTS
            (
                SELECT *
                FROM p
                WHERE p.Id = D.Id
            )
        )
    SELECT
        COALESCE(FullJoin.Code, 'X') AS Code,
        COALESCE(FullJoin.Status, 0) AS [Status]
    FROM FullJoin;
    

    Plano para reescrita manual:

    Plano de reescrita manual

    Este tem um custo estimado de 0,0067201 unidades, em comparação com 0,0203412 unidades do original.


    * Pode ser observado como a LogOp_UnionAllna Árvore Convertida (TF 8605). Na Árvore de Entrada (TF 8606) é um arquivo LogOp_ConstTableGet. A Árvore Convertida mostra a árvore de elementos de expressão do otimizador após análise, normalização, algebrização, associação e algum outro trabalho preparatório. A Árvore de entrada mostra os elementos após a conversão para a forma normal de negação (conversão NNF), colapso da constante de tempo de execução e alguns outros bits e bobs. O NNF convert inclui lógica para recolher uniões lógicas e tabelas comuns, entre outras coisas.

    • 19
  2. Hannah Vernon
    2019-08-03T05:06:05+08:002019-08-03T05:06:05+08:00

    O carretel de tabela está simplesmente criando uma tabela a partir dos dois conjuntos de tuplas presentes na VALUEScláusula.

    Você pode eliminar o spool inserindo esses valores em uma tabela temporária primeiro, assim:

    DROP TABLE IF EXISTS #data;
    CREATE TABLE #data ([Id] int, [Status] int);
    
    INSERT INTO #data
    VALUES (100, 1), (101, 2), (102, 3), (103, 2);
    
    DROP TABLE IF EXISTS #p;
    CREATE TABLE #p
    (
        Id int NOT NULL
        , Code char(1) NOT NULL
    );
    
    DECLARE @id1 int = 101, @id2 int = 105;
    
    INSERT INTO #p (Id, Code)
    VALUES
            (@id1, 'A'),
            (@id2, 'B');
    
    
    SELECT
        COALESCE(p.[Code], 'X') AS [Code],
        COALESCE(d.[Status], 0) AS [Status]
    FROM #p p
        FULL JOIN #data d ON d.[Id] = p.[Id];
    

    Observando o plano de execução de sua consulta, vemos que a lista de saída contém duas colunas que usam o Unionprefixo; esta é uma dica de que o spool está criando uma tabela de uma fonte de união:

    insira a descrição da imagem aqui

    O FULL OUTER JOINSQL Server requer que o SQL Server acesse os valores pduas vezes, uma para cada "lado" da junção. A criação de um spool permite que os loops internos resultantes se unam para acessar os dados em spool.

    Curiosamente, se você substituir o FULL OUTER JOINpor a LEFT JOINe a RIGHT JOINe UNIONos resultados juntos, o SQL Server não usará um spool.

    SELECT
        COALESCE(p.[Code], 'X') AS [Code],
        COALESCE(d.[Status], 0) AS [Status]
    FROM (VALUES
            (101, 'A'),
            (105, 'B')
        ) p([Id], [Code])
        LEFT JOIN #data d ON d.[Id] = p.[Id]
    UNION
    SELECT
        COALESCE(p.[Code], 'X') AS [Code],
        COALESCE(d.[Status], 0) AS [Status]
    FROM (VALUES
            (101, 'A'),
            (105, 'B')
        ) p([Id], [Code])
        RIGHT JOIN #data d ON d.[Id] = p.[Id];
    

    insira a descrição da imagem aqui

    Observe que não estou sugerindo o uso da UNIONconsulta acima; para conjuntos maiores de entrada, pode não ser mais eficiente do que o simples FULL OUTER JOINque você já tem.

    • 3

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