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 / 302480
Accepted
Aleksey Vitsko
Aleksey Vitsko
Asked: 2021-11-12 07:36:25 +0800 CST2021-11-12 07:36:25 +0800 CST 2021-11-12 07:36:25 +0800 CST

A consulta é executada indefinidamente - qual é a causa raiz? (não perguntando como consertar)

  • 772

Eu tenho uma consulta simples com um agrupamento, que funcionou bem, até adicionar mais uma junção:

select 
   [ca].Value,
   [c].cID, 
   [c].Name

from ReportingDB..Table1 [t1]

join MainDB..Companies [c] on
    [t1].CompanyID = [c].cID
    and [c].cID not in (1)

join MainDB..CompanyAttributes [ca] on -- this is the join that causes trouble
    [t1].CompanyID = caCID
    and caAttr = 26

group by [ca].Value, [c].cID, [c].Name

Informações:

Companies tabela é uma tabela de "pesquisa" e tem 2254 linhas, cIDé PK
CompanyAttributestem muitos para um relacionamento Companiese tem 4055 linhas
Table1tem muitos para um relacionamento com a Companiestabela e tem 3.485.150 linhas e

O plano de execução estimado não parece incomum.

  • Quando tento executar a consulta, ela não termina e depois de 1 hora eu a paro, então não consigo ver o que está acontecendo com o plano de execução real
  • Estatísticas de consulta ao vivo fizeram meu SSMS travar
  • Se remover a cláusula "group by", ele começa a buscar linhas sem nenhum problema rapidamente. Ou quando a última junção é removida, também funciona bem - com agrupamento
  • O servidor não está ocupado, tem recursos suficientes e não vejo aumento perceptível da CPU ao iniciar a consulta
  • olhando para sys.dm_exec_requests, wait_type é NULL cpu_timee logical_readscontinua a crescer, para a sessão que executa a consulta

Qual é a causa ROOT da consulta original rodando mais de 1 h sem terminar?


Resolvi o gargalo de desempenho em si (veja minha resposta), mas não entendo o QUE exatamente faz com que a consulta original seja executada por 1 hora e não termine em um servidor decente, as tabelas consultadas não são enormes. Esperaria que a consulta original terminasse em menos de 1 minuto.

sql-server query-performance
  • 3 3 respostas
  • 314 Views

3 respostas

  • Voted
  1. Best Answer
    Paul White
    2021-11-18T04:16:56+08:002021-11-18T04:16:56+08:00

    O principal problema com o plano de execução estimado mostrado é o operador Top acima do Clustered Index Scan da Tabela1. A varredura tem um predicado residual:

    [ReportingDB].[dbo].[Table1].[CompanyID]=[MainDB].[dbo].[CompanyAttributes].[cacID]
    

    O otimizador tenta estimar quantas linhas ele precisará ler da varredura antes de passar no teste. A lógica que ele usa é genérica e não é particularmente sólida na minha opinião. Em particular, se não houver correspondência, a verificação será executada até a conclusão, verificando todas as 3.514.200 linhas.

    Mais precisamente, essa varredura se repetirá para cada linha retornada pela varredura de Atributos da Empresa, multiplicada pelo número de linhas retornadas pela busca em Empresas. É assim que as junções de loops aninhados funcionam.

    O otimizador é super otimista em encontrar correspondências em cada varredura da Tabela1. Isso faz com que esse formato de plano tenha o menor custo estimado das alternativas consideradas. A causa raiz disso é o objetivo de linha introduzido pelo operador Top.

    Se você está curioso sobre de onde veio o Top (não está no texto da consulta), dê uma olhada no meu artigo relacionado Objetivos da linha, Parte 4: O padrão anti-junção anti- .

    Resumindo: o otimizador introduziu um agregado local (parcial) como parte de sua pesquisa de plano. Esse agregado acabou sendo logicamente redundante e foi substituído pelo Top equivalente. Um efeito colateral infeliz do Top é introduzir uma meta de linha, reduzindo significativamente o custo estimado da verificação.

    Um Topo acima de um Scan com um predicado residual (especialmente onde o scan é repetido) é um antipadrão a ser observado.

    • 4
  2. J.D.
    2021-11-16T12:09:31+08:002021-11-16T12:09:31+08:00

    Acredito que o que você está enfrentando é semelhante ao que experimentei recentemente algumas vezes, conforme mencionado na minha pergunta DBA.StackExchange . Não sou de forma alguma um especialista no que está acontecendo, mas tentarei resumir meu entendimento.

    Quando você une duas tabelas, o SQL Engine utiliza estatísticas em seus dados (com base nos campos em seus predicados) para determinar a operação mais eficiente a ser usada ao unir os dados. Muito disso depende das cardinalidades desses predicados, ou seja, quantos dados devem ser retornados por eles.

    Existem três operações principais (tipos de junções internas) que o SQL Engine pode escolher usar, dependendo de quantas linhas ele espera que sua junção retorne: Nested Loop Join , Merge Join e Hash Join . Há também uma métrica interna, comumente chamada de " ponto de inflexão ", que é um corte que o SQL Engine usa (com base nas cardinalidades) para determinar quando usar uma das operações de junção mencionadas anteriormente para atender à sua consulta.

    As junções de loop aninhadas geralmente são mais eficientes ao unir dois conjuntos de dados pequenos, em vez de as junções de hash serem mais eficientes para unir grandes conjuntos de dados. (Há também algumas outras características para quando um tem mais desempenho do que o outro, como se os dados já estiverem classificados no predicado de junção.) De uma perspectiva de linguagens de programação procedurais, pense em loops aninhados como um loop externo que está processando outro loop interno dentro dele e comparando cada valor do loop interno com o valor atual do loop externo, enquanto Hash Joins faz o que o nome indica e faz um hash dos dados dos predicados para fazer uma pesquisa de hash ao ingressar.

    O problema que você pode estar encontrando (se semelhante ao da minha pergunta vinculada acima) é que, por algum motivo, o SQL Engine não acha que seus dados cruzam o limite do ponto de inflexão que garante a atualização de uma operação de junção de loop aninhada para uma Operação de mesclagem ou junção de hash. Eu baseei meu palpite em forçar um Hash Join usando a dica de junção no fato de que você Table1tem quase ~ 3,5 milhões de linhas e seu plano de execução estimado está mostrando uma operação de loops aninhados ao juntá-lo ao CompanyAttributes.

    Presumo que quando você fizer uma das poucas coisas que mencionou que ajudam a melhorar o desempenho, se você analisar o plano de execução real, provavelmente notará que a operação de loops aninhados específica agora é substituída por uma mesclagem ou união de hash.

    A menção de Erik a um problema de " objetivo de linha " me levou a encontrar alguns recursos relevantes que você também pode achar interessantes:

    1. Row Goals Gone Rogue - Bart Duncan - Isso discute um pouco sobre as razões pelas quais um Nested Loop Join pode ser favorecido (para atingir um objetivo de linha) em vez de um Hash Join.

    2. Definindo e identificando metas de linha em planos de execução - Paul White - Aprofunda mais as metas de linha, o que pode acioná-las e discute ainda as causas para que loops aninhados sejam favorecidos em relação a junções de hash.

    Tentarei elaborar e melhorar ainda mais esta resposta quando tiver mais tempo, mas gostaria de finalmente mencionar que as dicas de junção geralmente não são uma solução ideal e devem ser usadas apenas quando não houver outra opção para atravessar o linha de chegada com ajuste de desempenho. Mas eles certamente são úteis na tentativa de depurar a causa de um problema de desempenho, como o que você está enfrentando no momento.

    • 2
  3. Aleksey Vitsko
    2021-11-13T03:55:59+08:002021-11-13T03:55:59+08:00

    Descobertas três maneiras de corrigir esse gargalo de desempenho e a consulta é concluída em 1 segundo após:

    1. basta substituir [c].cID por [t1].CompanyID na cláusula select, não há necessidade de criar índices

    OU

    1. adicione índice não clusterizado em [t1].CompanyID na Tabela1 - como Erik sugeriu. E não há necessidade de substituir colunas na cláusula select

    OU

    1. Alterando sua junção para CompanyAttributes para junção de hash interna MainDB..CompanyAttributes [ca] (obrigado JD)

    O que NÃO entendo é por que a consulta original (e quando não há índice NC) não termina.
    Ok, eu esperaria que ele fizesse uma varredura de índice clusterizado e concluísse em um minuto ou menos, a Tabela1 não é super grande (3,5 M linhas).

    Mas roda 1 hora e não completa. Então, aceitarei outra resposta se alguém puder explicar a causa raiz da consulta original executando mais de 1h e não terminando

    • 1

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