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 / 87145
Accepted
Jeroen
Jeroen
Asked: 2014-12-30 02:16:21 +0800 CST2014-12-30 02:16:21 +0800 CST 2014-12-30 02:16:21 +0800 CST

Como medir ou encontrar o custo de criar um plano de consulta?

  • 772

Eu tenho um caso típico em que a detecção de parâmetros faz com que um plano de execução "ruim" chegue ao cache do plano, fazendo com que as execuções subsequentes do meu procedimento armazenado sejam muito lentas. Posso "resolver" esse problema com variáveis ​​locais, OPTIMIZE FOR ... UNKNOWN, e OPTION(RECOMPILE). No entanto, também posso mergulhar na consulta e tentar otimizá-la.

Estou tentando determinar se devo : devido ao tempo limitado para corrigir problemas, gostaria de saber o custo de não fazê-lo. A meu ver, se eu continuar com OPTION(RECOMPILE), o efeito líquido é que um plano de consulta é recriado toda vez que a consulta é executada. Então, acho que preciso saber:

Como saber qual é o custo de criar um plano de consultas?

Para responder à minha própria pergunta, pesquisei no Google (por exemplo, com esta consulta ) e examinei a documentação das colunas para o dm_exec_query_statsDMV . Também inspecionei a janela de saída no SSMS para "Plano de consulta real" para encontrar essas informações. Por fim, pesquisei DBA.SE . Nenhum deles levou a uma resposta.

Alguém pode me dizer? É possível encontrar ou medir o tempo necessário para a criação do plano?

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

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2014-12-30T19:56:16+08:002014-12-30T19:56:16+08:00

    Como saber qual é o custo de criar um plano de consultas?

    Você pode ver as propriedades do nó raiz no plano de consulta, por exemplo:

    extrato de propriedades raiz
    (captura de tela do Sentry One Plan Explorer gratuito )

    Essas informações também estão disponíveis consultando o cache do plano, por exemplo, usando uma consulta baseada nos seguintes relacionamentos:

    WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
    SELECT 
        CompileTime = c.value('(QueryPlan/@CompileTime)[1]', 'int'),
        CompileCPU = c.value('(QueryPlan/@CompileCPU)[1]', 'int'),
        CompileMemory = c.value('(QueryPlan/@CompileMemory)[1]', 'int'),
        ST.[text],
        QP.query_plan
    FROM sys.dm_exec_cached_plans AS CP
    CROSS APPLY sys.dm_exec_query_plan(CP.plan_handle) AS QP
    CROSS APPLY sys.dm_exec_sql_text(CP.plan_handle) AS ST
    CROSS APPLY QP.query_plan.nodes('ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS N(c);
    

    fragmento de resultados

    Para um tratamento completo das opções que você tem para lidar com esses tipos de consultas, consulte o artigo atualizado recentemente de Erland Sommarskog .

    • 18
  2. Solomon Rutzky
    2014-12-30T09:31:32+08:002014-12-30T09:31:32+08:00

    Supondo que "custo" seja em termos de tempo (embora não tenha certeza do que mais poderia ser em termos de ;-), então, pelo menos, você deve ser capaz de ter uma noção disso fazendo algo como o seguinte:

    DBCC FREEPROCCACHE WITH NO_INFOMSGS;
    
    SET STATISTICS TIME ON;
    
    EXEC sp_help 'sys.databases'; -- replace with your proc
    
    SET STATISTICS TIME OFF;
    

    O primeiro item informado na aba "Mensagens" deve ser:

    Tempo de análise e compilação do SQL Server:

    Eu executaria isso pelo menos 10 vezes e calcularia a média dos milissegundos de "CPU" e "Decorrido".

    Idealmente, você executaria isso em Produção para obter uma estimativa de tempo real, mas raramente as pessoas têm permissão para limpar o cache do plano em Produção. Felizmente, a partir do SQL Server 2008, tornou-se possível limpar um plano específico do cache. Nesse caso, você pode fazer o seguinte:

    DECLARE @SQL NVARCHAR(MAX) = '';
    ;WITH cte AS
    (
      SELECT DISTINCT stat.plan_handle
      FROM sys.dm_exec_query_stats stat
      CROSS APPLY sys.dm_exec_text_query_plan(stat.plan_handle, 0, -1) qplan
      WHERE qplan.query_plan LIKE N'%sp[_]help%' -- replace "sp[_]help" with proc name
    )
    SELECT @SQL += N'DBCC FREEPROCCACHE ('
                   + CONVERT(NVARCHAR(130), cte.plan_handle, 1)
                   + N');'
                   + NCHAR(13) + NCHAR(10)
    FROM cte;
    PRINT @SQL;
    EXEC (@SQL);
    
    SET STATISTICS TIME ON;
    
    EXEC sp_help 'sys.databases' -- replace with your proc
    
    SET STATISTICS TIME OFF;
    

    No entanto, dependendo da variabilidade dos valores sendo passados ​​para o(s) parâmetro(s) que causa(m) o plano em cache "ruim", há outro método a considerar que é um meio-termo entre OPTION(RECOMPILE)e OPTION(OPTIMIZE FOR UNKNOWN): SQL dinâmico. Sim, eu disse isso. E eu ainda quero dizer SQL dinâmico não parametrizado. Aqui está o porquê.

    Você claramente tem dados que têm uma distribuição desigual, pelo menos em termos de um ou mais valores de parâmetro de entrada. As desvantagens das opções mencionadas são:

    • OPTION(RECOMPILE)irá gerar um plano para cada execução e você nunca poderá se beneficiar de qualquer reutilização do plano, mesmo se os valores dos parâmetros passados ​​novamente forem idênticos à(s) execução(ões) anterior(es). Para procs que são chamados com frequência - uma vez a cada poucos segundos ou com mais frequência - isso o salvará de situações horríveis ocasionais, mas ainda o deixará em uma situação nem sempre tão boa assim.

    • OPTION(OPTIMIZE FOR (@Param = value))gerará um plano baseado naquele valor específico, o que pode ajudar em vários casos, mas ainda deixa você aberto ao problema atual.

    • OPTION(OPTIMIZE FOR UNKNOWN)gerará um plano baseado no que equivale a uma distribuição média, o que ajudará algumas consultas, mas prejudicará outras. Isso deve ser o mesmo que a opção de usar variáveis ​​locais.

    O SQL dinâmico, no entanto, quando feito corretamente , permitirá que os vários valores transmitidos tenham seus próprios planos de consulta separados que são ideais (bem, tanto quanto eles serão). O principal custo aqui é que, à medida que a variedade de valores transmitidos aumenta, o número de planos de execução no cache aumenta e eles ocupam memória. Os custos menores são:

    • necessidade de validar parâmetros de string para evitar SQL Injections

    • possivelmente precisando configurar um certificado e um usuário baseado em certificado para manter a abstração de segurança ideal, já que o SQL dinâmico requer permissões diretas de tabela.

    Então, aqui está como gerenciei essa situação quando tive procs que foram chamados mais de uma vez por segundo e atingiram várias tabelas, cada uma com milhões de linhas. Eu tentei, OPTION(RECOMPILE)mas isso provou ser muito prejudicial para o processo em 99% dos casos que não tinham o problema de detecção de parâmetro / plano de cache ruim. E lembre-se de que um desses procs tinha cerca de 15 consultas e apenas 3 a 5 deles foram convertidos em SQL dinâmico, conforme descrito aqui; O SQL dinâmico não foi usado, a menos que fosse necessário para uma consulta específica.

    1. Se houver vários parâmetros de entrada para o procedimento armazenado, descubra quais são usados ​​com colunas que têm distribuições de dados altamente díspares (e, portanto, causam esse problema) e quais são usados ​​com colunas que têm distribuições mais uniformes (e não devem ser causando este problema).

    2. Construa a string SQL dinâmica usando parâmetros para os parâmetros de entrada proc que estão associados a colunas distribuídas uniformemente. Essa parametrização ajuda a reduzir o consequente aumento de planos de execução no cache relacionados a essa consulta.

    3. Para os parâmetros restantes associados a distribuições muito variadas, eles devem ser concatenados no SQL dinâmico como valores literais. Como uma consulta exclusiva é determinada por qualquer alteração no texto da consulta, ter WHERE StatusID = 1é uma consulta diferente e, portanto, um plano de consulta diferente de ter WHERE StatusID = 2.

    4. Se algum dos parâmetros de entrada do proc que devem ser concatenados no texto da consulta forem strings, eles precisam ser validados para proteção contra SQL Injection (embora isso seja menos provável de acontecer se as strings passadas forem geradas pelo app e não um usuário, mas ainda assim). Pelo menos faça o REPLACE(@Param, '''', '''''')para garantir que as aspas simples se tornem aspas simples de escape.

    5. Se necessário, crie um certificado que será usado para criar um usuário e assine o procedimento armazenado de forma que as permissões diretas da tabela sejam concedidas apenas ao novo usuário baseado em certificado e não a [public]ou a usuários que não deveriam ter tais permissões .

    Processo de exemplo:

    CREATE PROCEDURE MySchema.MyProc
    (
      @Param1 INT,
      @Param2 DATETIME,
      @Param3 NVARCHAR(50)
    )
    AS
    SET NOCOUNT ON;
    
    DECLARE @SQL NVARCHAR(MAX);
    
    SET @SQL = N'
         SELECT  tab.Field1, tab.Field2, ...
         FROM    MySchema.SomeTable tab
         WHERE   tab.Field3 = @P1
         AND     tab.Field8 >= CONVERT(DATETIME, ''' +
      CONVERT(NVARCHAR(50), @Param2, 121) +
      N''')
         AND     tab.Field2 LIKE N''' +
      REPLACE(@Param3, N'''', N'''''') +
      N'%'';';
    
    EXEC sp_executesql
         @SQL,
         N'@P1 INT',
         @P1 = @Param1;
    
    • 4

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