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 / 206180
Accepted
Kris Gruttemeyer
Kris Gruttemeyer
Asked: 2018-05-09 10:22:01 +0800 CST2018-05-09 10:22:01 +0800 CST 2018-05-09 10:22:01 +0800 CST

Dados de pré-preparação fazem com que o custo do plano de execução dispare

  • 772

Eu tenho uma consulta problemática que estamos tentando ajustar. Um dos nossos primeiros pensamentos foi pegar uma parte de um plano de execução maior e armazenar esses resultados em uma tabela temporária intermediária e, em seguida, realizar as outras operações.

O que estou observando é que, quando inserimos os dados em uma tabela temporária, o custo do plano de execução aumenta (22 -> 1,1k). Agora, isso tem o benefício de permitir que o plano seja paralelo, o que reduziu o tempo de execução em 20%, mas não vale o uso muito maior de CPU por execução em nosso caso.

Estamos usando o SQL Server 2016 SP2 com o CE legado ativado.

Plano original (custo ~ 20):

Plano de baixo custo

https://www.brentozar.com/pastetheplan/?id=ry-QGnkCM

SQL original:

WITH Object1(Column1, Column2, Column3, Column4, Column5, Column6)
AS
(
    SELECT  Object2.Column1, 
            Object2.Column2, 
            Object3.Column3, 
            Object3.Column4, 
            Object3.Column5, 
            Object3.Column6
    FROM Object4 AS Object5
    INNER JOIN Object6 AS Object2 ON Object2.Column2 = Object5.Column2 AND Object2.Column7 = 0
    INNER JOIN Object7 AS Object8 ON Object8.Column8 = Object2.Column9 AND Object8.Column7 = 0
    INNER JOIN Object9 AS Object3 ON Object3.Column10 = Object8.Column11 AND Object3.Column7 = 0
    INNER JOIN Object10 AS Object11 ON Object2.Column1 = Object11.Column1
    WHERE   Object8.Column12 IS NULL AND
            Object8.Column13 = Object5.Column13 AND 
            Object3.Column3 = Object5.Column3 AND 
            Object11.Column14 = Variable1
)
insert Object12
SELECT  Object13.Column2,
        Object13.Column3,
        MIN(Object13.Column4) AS Column15,
        MAX(Object13.Column4) AS Column16,
        COUNT(DISTINCT (CASE WHEN Object13.Column5 = 1 THEN Object13.Column1 END)) AS Column17,
        COUNT(DISTINCT (CASE WHEN Object13.Column6 = 0 THEN Object13.Column1 END)) AS Column18,
        COUNT(DISTINCT Object13.Column1) AS Column19
FROM Object1 AS Object13
GROUP BY Object13.Column2, Object13.Column3 OPTION (RECOMPILE) 

Novo plano (com a área destacada em azul acima é pré-preparado em uma tabela temporária - Custo ~ 1,1k):

insira a descrição da imagem aqui

https://www.brentozar.com/pastetheplan/?id=rycqG3JRf

Novo SQL:

SELECT  Object1.Column1,
        Object1.Column2,
        MIN(Object2.Column3) AS Column4,
        MAX(Object2.Column3) AS Column5,
        COUNT(DISTINCT (CASE WHEN Object2.Column6 = 1 THEN Object1.Column7 END)) AS Column8,
        COUNT(DISTINCT (CASE WHEN Object2.Column9 = 0 THEN Object1.Column7 END)) AS Column10,
        COUNT(DISTINCT Object1.Column7) AS Column11
from Object3 Object1
join Object4 Object2 on Object2.Column12 = Object1.Column13 and Object2.Column2 = Object1.Column2
where Object2.Column14 = 0
GROUP BY Object1.Column1, Object1.Column2 OPTION (RECOMPILE) 

Alguém pode nos ajudar a entender porque o novo plano teria um custo tão maior? Ficarei feliz em fornecer informações adicionais sobre tabelas/índices abaixo, se necessário.

No caso do plano original, percebemos que ele está fazendo uma inserção em vez de uma seleção. Mesmo assim, o select não deveria (na nossa cabeça) ser muito mais caro.

Este é o plano de execução real. É uma preocupação porque, devido ao custo do plano imensamente mais alto, ele é paralelo. Portanto, usando CPU mais alta. Além disso, estamos curiosos para saber por que o custo do plano aumenta tanto para algo como pré-encenar os dados, o que geralmente o aproxima, se não melhor, do custo original.

A tabela temporária é indexada na segunda consulta como um PK clusterizado composto em Object1.Column13 e Object1.Column2. Isso corresponde às colunas (e ordem) do Object4. Adicionar uma MAXDOPdica é uma opção, mas isso também é um exercício acadêmico de 'por que no mundo o custo sobe tanto'?

Adicionar OPTION (ORDER GROUP)à segunda consulta resulta em nenhuma alteração, mesmos operadores/custos.

NOTAS:

  • Object9 na primeira consulta é o mesmo objeto que Object4 na segunda.
sql-server performance
  • 1 1 respostas
  • 404 Views

1 respostas

  • Voted
  1. Best Answer
    Joe Obbish
    2018-05-09T17:45:08+08:002018-05-09T17:45:08+08:00

    Os custos são baseados em estimativas, mesmo em "planos reais". Você não pode comparar dois planos de consulta lado a lado e concluir que um deles exigirá mais CPU para executar com base apenas no operador ou nos custos totais do plano. Posso criar uma consulta com um custo na casa dos milhões que é executada em um segundo. Também posso criar uma consulta com um custo minúsculo que efetivamente levará uma eternidade para ser executada. Para o seu caso, a primeira consulta tem um custo de apenas 22 unidades do otimizador devido a uma estimativa de cardinalidade ruim após a junção de hash:

    insira a descrição da imagem aqui

    Os operadores em vermelho executam milhões de vezes, mas o otimizador de consulta espera que eles executem apenas alguns milhares de vezes. Os custos, que são baseados em estimativas, não refletem esse trabalho. O operador em azul é um carretel de tabela para o qual o estimador de cardinalidade espera inserir uma única linha. Em vez disso, insere alguns milhões. Como resultado, os operadores em preto (junto com alguns outros não mostrados) são ineficientes e se espalham para o tempdb.

    Com o outro plano, você coloca um número significativo de linhas em tempdb e, como resultado, a estimativa de cardinalidade é mais razoável, embora ainda não seja ideal:

    insira a descrição da imagem aqui

    O otimizador de consulta espera precisar processar muito mais linhas e, como resultado, o plano de consulta tem um custo mais alto. Como regra geral, você pode ver um desempenho aprimorado com estimativas aprimoradas, mas nem sempre funciona como você gostaria. Olhando para o plano com uma tabela temporária, vejo algumas áreas de possível melhoria:

    1. Carregue o CTE completo da consulta original na tabela temporária. Uma consulta com vários agregados distintos pode ser difícil de otimizar. Às vezes, você obtém um plano de consulta em que todos os dados são carregados em um spool (no tempdb) e alguns dos agregados são aplicados separadamente ao spool. Todo esse trabalho é sempre feito em uma zona serial na minha experiência. Se você eliminar todas as junções na consulta, acredito que não obterá essa otimização. Os agregados serão aplicados apenas à tabela temporária. Isso economizará o trabalho de escrever quase os mesmos dados para tempdb e todo o plano deve ser elegível para paralelismo.

    2. Defina a tabela temporária como um heap e grave nela com TABLOCK. Parece que agora você tem um índice clusterizado, o que significa que você não está qualificado para inserção paralela.

    3. Considere tornar a consulta elegível para o modo em lote usando um desses truques . Os agregados do modo de lote podem ser significativamente mais eficientes com vários agregados distintos.

    Eu esperaria que alguma combinação dessas etapas melhorasse significativamente o tempo de execução. Observe que fiz uma análise rápida parcialmente porque os planos anônimos são difíceis de interpretar.

    • 6

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