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 / 127639
Accepted
Kenneth Fisher
Kenneth Fisher
Asked: 2016-01-29 10:40:44 +0800 CST2016-01-29 10:40:44 +0800 CST 2016-01-29 10:40:44 +0800 CST

Por que adicionar um TOP 1 piora drasticamente o desempenho?

  • 772

Eu tenho uma consulta bastante simples

SELECT TOP 1 dc.DOCUMENT_ID,
        dc.COPIES,
        dc.REQUESTOR,
        dc.D_ID,
        cj.FILE_NUMBER
FROM DOCUMENT_QUEUE dc
JOIN CORRESPONDENCE_JOURNAL cj
    ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
WHERE dc.QUEUE_DATE <= GETDATE()
  AND dc.PRINT_LOCATION = 2
ORDER BY cj.FILE_NUMBER

Isso está me dando um desempenho horrível (como nunca se preocupou em esperar que terminasse). O plano de consulta tem esta aparência:

insira a descrição da imagem aqui

No entanto, se eu removê- TOP 1lo, obtenho um plano parecido com este e é executado em 1 a 2 segundos:

insira a descrição da imagem aqui

PK correto e indexação abaixo.

O fato de ter TOP 1mudado o plano de consulta não me surpreende, estou apenas um pouco surpreso por torná-lo muito pior.

Observação: li os resultados desta postagem e entendi o conceito de a Row Goaletc. O que estou curioso é como posso alterar a consulta para que ela use o plano melhor. Atualmente, estou despejando os dados em uma tabela temporária e extraindo a primeira linha dela. Eu estou querendo saber se existe um método melhor.

Editar Para as pessoas que estão lendo isso depois do fato, aqui estão algumas informações extras.

  • Document_Queue - PK/CI é D_ID e tem ~ 5k linhas.
  • Correspondence_Journal - PK/CI é FILE_NUMBER, CORRESPONDENCE_ID e tem aproximadamente 1,4 mil linhas.

Quando comecei não havia outros índices. Acabei com um em Correspondence_Journal (Document_Id, File_Number)

sql-server sql-server-2008-r2
  • 6 6 respostas
  • 12138 Views

6 respostas

  • Voted
  1. Daniel Hutmacher
    2016-01-29T11:27:04+08:002016-01-29T11:27:04+08:00

    Desde que você obtenha o plano correto com o ORDER BY, talvez você possa apenas rolar seu próprio TOPoperador?

    SELECT DOCUMENT_ID, COPIES, REQUESTOR, D_ID, FILE_NUMBER
    FROM (
        SELECT dc.DOCUMENT_ID,
               dc.COPIES,
               dc.REQUESTOR,
               dc.D_ID,
               cj.FILE_NUMBER,
               ROW_NUMBER() OVER (ORDER BY cj.FILE_NUMBER) AS _rownum
        FROM DOCUMENT_QUEUE dc
        INNER JOIN CORRESPONDENCE_JOURNAL cj
            ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
        WHERE dc.QUEUE_DATE <= GETDATE()
          AND dc.PRINT_LOCATION = 2
    ) AS sub
    WHERE _rownum=1;
    

    Na minha opinião, o plano de consulta ROW_NUMBER()acima deve ser o mesmo como se você tivesse um arquivo ORDER BY. O plano de consulta agora deve ter um segmento, um projeto de sequência e, finalmente, um operador de filtro, o restante deve se parecer com o seu bom plano.

    • 30
  2. Best Answer
    paparazzo
    2016-01-29T11:18:50+08:002016-01-29T11:18:50+08:00

    Tente forçar um hash join*

    SELECT TOP 1 
           dc.DOCUMENT_ID,
           dc.COPIES,
           dc.REQUESTOR,
           dc.D_ID,
           cj.FILE_NUMBER
    FROM DOCUMENT_QUEUE dc
    INNER HASH JOIN CORRESPONDENCE_JOURNAL cj
            ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
           AND dc.QUEUE_DATE <= GETDATE()
           AND dc.PRINT_LOCATION = 2
    ORDER BY cj.FILE_NUMBER
    

    O otimizador provavelmente pensou que um loop seria melhor com o top 1 e isso faz sentido, mas na realidade não funcionou aqui. Apenas um palpite aqui, mas talvez o custo estimado desse spool esteja fora - ele usa TEMPDB - você pode ter um TEMPDB com baixo desempenho.


    * Tenha cuidado com as dicas de junção , porque elas forçam a ordem de acesso à tabela do plano para corresponder à ordem escrita das tabelas na consulta (como se OPTION (FORCE ORDER)tivesse sido especificada). No link da documentação:

    extrato BOL

    Isso pode não produzir nenhum efeito indesejável no exemplo, mas, em geral, pode muito bem. FORCE ORDER(implícito ou explícito) é uma dica muito poderosa que vai além de impor a ordem; ele evita a aplicação de uma ampla variedade de técnicas de otimizador, incluindo agregações parciais e reordenação.

    Uma dica de OPTION (HASH JOIN) consulta pode ser menos intrusiva em casos adequados, pois isso não implica FORCE ORDER. No entanto, aplica-se a todas as junções na consulta. Outras soluções estão disponíveis.

    • 29
  3. Rob Farley
    2016-01-29T18:41:23+08:002016-01-29T18:41:23+08:00

    Editar: +1 funciona nessa situação porque FILE_NUMBERé uma versão de string preenchida com zeros de um número inteiro. Uma solução melhor aqui para strings é anexar ''(a string vazia), pois anexar um valor pode afetar a ordem ou para números adicionar algo que é uma constante, mas contém uma função não determinística, como sign(rand()+1). A ideia de 'quebrar a classificação' ainda é válida aqui, só que meu método não era o ideal.

    +1

    Não, não quero dizer que estou concordando com nada, quero dizer isso como uma solução. Se você alterar sua consulta para ORDER BY cj.FILE_NUMBER + 1, o TOP 1se comportará de maneira diferente.

    Veja bem, com o objetivo de linha pequena definido para uma consulta ordenada, o sistema tentará consumir os dados em ordem, para evitar ter um operador Sort. Ele também evitará a construção de uma tabela de hash, imaginando que provavelmente não terá muito trabalho para encontrar a primeira linha. No seu caso, isso está errado - pela espessura dessas setas, parece que é necessário consumir muitos dados para encontrar uma única correspondência.

    A espessura dessas setas sugere que sua DOCUMENT_QUEUEmesa (DQ) é muito menor que sua CORRESPONDENCE_JOURNALmesa (CJ). E que o melhor plano seria, na verdade, verificar as linhas DQ até que uma linha CJ fosse encontrada. Na verdade, isso é o que o Query Optimizer (QO) faria se não tivesse esse incômodo ORDER BYlá, que é bem suportado por um índice de cobertura em CJ.

    Portanto, se você descartar ORDER BYcompletamente, espero obter um plano que envolva um loop aninhado, iterando sobre as linhas em DQ, procurando em CJ para garantir que a linha exista. E com TOP 1, isso pararia depois que uma única linha fosse puxada.

    Mas se você realmente precisa da primeira linha em FILE_NUMBERordem, pode induzir o sistema a ignorar esse índice que parece (incorretamente) ser tão útil, fazendo ORDER BY CJ.FILE_NUMBER+1- o que sabemos que manterá a mesma ordem de antes, mas, principalmente, o QO não. O QO se concentrará em obter todo o conjunto, para que um operador Top N Sort possa ser satisfeito. Este método deve produzir um plano que contém um operador Compute Scalar para calcular o valor para ordenação e um operador Top N Sort para obter a primeira linha. Mas à direita deles, você deve ver um belo Nested Loop, fazendo muitas buscas no CJ. E melhor desempenho do que percorrer uma grande tabela de linhas que não correspondem a nada no DQ.

    O Hash Match não é necessariamente horrível, mas se o conjunto de linhas que você está retornando de DQ for muito menor que CJ (como eu esperaria que fosse), então o Hash Match vai escanear muito mais CJ do que precisa.

    Observação: usei +1 em vez de +0 porque o otimizador de consulta provavelmente reconhecerá que +0 não altera nada. Claro, a mesma coisa pode se aplicar ao +1, se não agora, então em algum momento no futuro.

    • 29
  4. Martin Smith
    2016-01-31T07:03:07+08:002016-01-31T07:03:07+08:00

    Eu li os resultados desta postagem e entendi o conceito de uma meta de linha etc. O que estou curioso é como posso alterar a consulta para que ela use o melhor plano

    A adição OPTION (QUERYTRACEON 4138)desativa o efeito das metas de linha apenas para essa consulta, sem ser excessivamente prescritiva sobre o plano final e provavelmente será a maneira mais simples/direta.

    Se adicionar esta dica resultar em um erro de permissão (obrigatório para DBCC TRACEON), você poderá aplicá-la usando um guia de plano:

    Usando QUERYTRACEONem guias de plano por spaghettidba

    ... ou apenas use um procedimento armazenado:

    Quais permissões são QUERYTRACEONnecessárias? por Kendra Little

    • 7
  5. Joe Obbish
    2018-04-09T19:41:16+08:002018-04-09T19:41:16+08:00

    Versões mais recentes do SQL Server oferecem opções diferentes (e indiscutivelmente melhores) para lidar com consultas que obtêm desempenho abaixo do ideal quando o otimizador é capaz de aplicar otimizações de meta de linha. O SQL Server 2016 SP1 introduziu a DISABLE_OPTIMIZER_ROWGOALdica de uso que tem o mesmo efeito que o sinalizador de rastreamento 4138. (Consulte esta postagem de blog para obter um exemplo de como usá-lo.)

    Se você não estiver nessa versão, também pode considerar o uso da OPTIMIZE FORdica de consulta para obter um plano de consulta projetado para retornar todas as linhas em vez de apenas 1. A consulta abaixo retornará os mesmos resultados da pergunta, mas não ser criado com o objetivo de obter apenas 1 linha.

    DECLARE @top INT = 1;
    
    SELECT TOP (@top) dc.DOCUMENT_ID,
            dc.COPIES,
            dc.REQUESTOR,
            dc.D_ID,
            cj.FILE_NUMBER
    FROM DOCUMENT_QUEUE dc
    JOIN CORRESPONDENCE_JOURNAL cj
        ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
    WHERE dc.QUEUE_DATE <= GETDATE()
      AND dc.PRINT_LOCATION = 2
    ORDER BY cj.FILE_NUMBER
    OPTION (OPTIMIZE FOR (@top = 987654321));
    
    • 3
  6. Simon Birch
    2016-02-01T02:54:13+08:002016-02-01T02:54:13+08:00

    Como você está fazendo um TOP(1), recomendo fazer o ORDER BYdeterminístico para começar. No mínimo, isso garantirá que os resultados sejam funcionalmente previsíveis (sempre útil para testes de regressão). Parece que você precisa adicionar DC.D_IDe CJ.CORRESPONDENCE_IDpara isso.

    Ao examinar os planos de consulta, às vezes acho instrutivo simplificar a consulta: possivelmente selecione todas as linhas dc relevantes em uma tabela temporária com antecedência, para eliminar problemas com a estimativa de cardinalidade em QUEUE_DATEe PRINT_LOCATION. Isso deve ser rápido devido à baixa contagem de linhas. Você pode adicionar índices a essa tabela temporária, se necessário, sem alterar a tabela permanente.

    • 2

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