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 / 339801
Accepted
anakata
anakata
Asked: 2024-05-26 10:35:38 +0800 CST2024-05-26 10:35:38 +0800 CST 2024-05-26 10:35:38 +0800 CST

Execução lenta em procedimento armazenado; rápido quando executado ad hoc

  • 772

Estou lidando com um problema que não consigo resolver. Recebi esse procedimento armazenado que apresenta problemas de velocidade. Demora cerca de 35 segundos. Quando executado adhoc , ele é concluído instantaneamente.

Isso me fez pensar que tinha algo a ver com detecção de parâmetros. Eu tentei reescrever isso para usar variáveis ​​locais, otimizar para desconhecido\variável\etc, com recompilação.

A tabela em que a verificação está acontecendo é enorme, mas mesmo com as estatísticas atualizadas com fullscan, as estimativas ainda estão MUITO erradas. Talvez a consulta pudesse ser reescrita, mas eu gostaria de descobrir isso.

todos os dados do ambiente de teste com nomes alterados de arquivos de texto .sql para consulta sp e ad hoc - deixe-me saber se isso não funcionar

plano ad hoc - https://www.brentozar.com/pastetheplan/?id=Hkvg5Ge40

Parâmetros para ad hoc -

insira a descrição da imagem aqui

Plano SP - https://www.brentozar.com/pastetheplan/?id=S1w49GxER

Parâmetros para SP -

parâmetros para sp


Os parâmetros vêm como:

(sp name)
    @ TransactionDescriptionId VARCHAR(32),
    @ CategoryCode VARCHAR(4000)
AS

DECLARE
    @ CategoryHash VARBINARY(16) = HashBytes('MD5', @CategoryCode);

Os mesmos valores são passados ​​tanto na versão SP quanto na versão ad hoc . Achei que poderia ser devido a algo com o hash sendo criado como uma variável local a partir do parâmetro passado, mas na versão ad hoc está fazendo o mesmo (para mim).

sql-server
  • 1 1 respostas
  • 273 Views

1 respostas

  • Voted
  1. Best Answer
    Erik Darling
    2024-05-26T23:46:59+08:002024-05-26T23:46:59+08:00

    Eh

    Eu tentei reescrever isso para usar variáveis ​​locais, otimizar para desconhecido\variável\etc, com recompilação.

    Os dois primeiros métodos listados aqui são bastante inúteis na maioria das vezes para melhorar o desempenho . Você pode se deparar com uma situação a cada 5 a 10 anos em que eles melhoram uma consulta específica, mas eu manteria essas opções bem baixas na minha lista de coisas para tentar.

    No plano lento, a parte que consome mais tempo fica assim:

    NOZES

    Aparentemente, você tem uma coluna computada na Catalog_Itemstabela que gera o MD5 e ela não é persistente. Você não precisa persistir, mas a razão pela qual você acaba com um operador Filter em uma expressão e não pode aplicar o predicado enquanto verifica a tabela é porque ele precisa ser calculado por linha em tempo de execução .

    Na consulta rápida, você tem CategoryCodeHasho index [IX_Catalog_Items_IdRetailer_CategoryCodeHash], que persiste o valor e o torna pesquisável.

    Quanto ao motivo pelo qual você obteve uma estimativa tão ruim no plano lento, não está claro se o @CategoryHashargumento é um parâmetro ou uma variável local neste contexto, mas...

            <ParameterList>
              <ColumnReference 
    Column="@TransactionDescriptionId" 
    ParameterDataType="varchar(32)" 
    ParameterCompiledValue="'Instacart'" 
    ParameterRuntimeValue="'Instacart'" 
    />
              <ColumnReference 
    Column="@CategoryHash" 
    ParameterDataType="binary(16)" 
    ParameterRuntimeValue="0xD1DC3A8270A6F9394F88847D7F0050CF" 
    />
            </ParameterList>
    

    O fato de @TransactionDescriptionIdpossuir o ParameterCompiledValueatributo e @CategoryHashnão parece indicar que não é um parâmetro detectado. No plano rápido nenhum dos dois tem o ParameterCompiledValueatributo, mas sem a reprodução completa não sei exatamente o que você fez de diferente.

    de qualquer forma

    O otimizador baseado em custos do SQL Server achou a busca + pesquisa mais cara do que a verificação + filtro de índice clusterizado ou nunca chegou ao plano de busca + pesquisa. Muitas pessoas dirão para você "fazer a cobertura do índice" para que todas as colunas necessárias estejam disponíveis no [IX_Catalog_Items_IdRetailer_CategoryCodeHash]índice. Essa é uma opção, é claro, mas você também pode fazer coisas para enganar o otimizador e fazê-lo usar índices estreitos, como usar um self-join .

    SELECT TOP (1)
        ci2.IdItem,
        ci2.IdCatalog,
        ci2.IdRetailer,
        ci2.LastUpdatedFromIdFile,
        ci2.Upc11,
        ci2.Upc12,
        ci2.Gtin,
        ci2.[Description],
        ci2.ShortDescription,
        ci2.CategoryName,
        ci2.SubCategoryName,
        ci2.FineLineCategoryName,
        ci2.SubCategoryCode,
        ci2.Manufacturer
    FROM
    (
        SELECT
            DelegateMerchantDescription = 
                ISNULL(delegateRetailers.TransactionDescriptionId, retailers.TransactionDescriptionId),
            retailers.TransactionDescriptionId,
            retailers.MerchantId
        FROM Retailers AS retailers (NOLOCK)
        LEFT JOIN Retailers AS delegateRetailers (NOLOCK)
          ON delegateRetailers.TransactionDescriptionId = retailers.DelegateCatalogMerchantDescription
        WHERE retailers.TransactionDescriptionId IS NOT NULL
    ) AS delegate
    JOIN Retailers AS r
      ON r.TransactionDescriptionId = delegate.DelegateMerchantDescription
    JOIN Catalog_Items AS ci WITH (NOLOCK)
      ON ci.IdRetailer = r.IdRetailer
    /*This is new*/
    JOIN Catalog_Items AS ci2 WITH (NOLOCK)
    /*I'm not sure what the PK of Catalog_Items is*/  
      ON ci2.primary_key_column = ci.primary_key_column
    WHERE ci.CategoryCodeHash = @CategoryHash
    AND
    (
        delegate.TransactionDescriptionId = @TransactionDescriptionId
    OR  delegate.MerchantId = @TransactionDescriptionId
    );
    

    A ideia é unir uma tabela a si mesma em valores de chave primária, com uma referência à tabela usada para selecionar todas as colunas que deseja exibir, e a outra referência responsável pela união e filtragem e quaisquer outras atividades relacionais.

    contextualmente

    Uma coisa que pode valer a pena considerar por que o plano é diferente seriam as várias opções de SET . Alguns são necessários para que visualizações indexadas, colunas computadas e índices filtrados sejam avaliados durante a otimização:

    A opção NUMERIC_ROUNDABORT deve ser definida como OFF e as seguintes opções devem ser definidas como ON:

    ANSI_NULLS ANSI_PADDING ANSI_WARNINGS ARITHABORT CONCAT_NULL_YIELDS_NULL QUOTED_IDENTIFIER

    O DatabaseContextSettingsIdé diferente para os dois planos:

    NOZES

    vs.

    NOZES

    Você pode ver algumas das configurações aqui:

    SELECT
        procedure_name = p.name,
        sm.uses_ansi_nulls,
        sm.uses_quoted_identifier
    FROM sys.procedures AS p
    JOIN sys.sql_modules AS sm
      ON p.object_id = sm.object_id
    WHERE p.name = 'YourProcedureName';
    

    Você também pode ver se o banco de dados possui algum padrão que vá contra os requisitos de todos os módulos criados sem nenhuma especificação diferente:

    SELECT
        database_name = name,
        is_ansi_null_default_on,
        is_ansi_nulls_on,
        is_ansi_padding_on,
        is_ansi_warnings_on,
        is_arithabort_on,
        is_concat_null_yields_null_on,
        is_numeric_roundabort_on,
        is_quoted_identifier_on,
        is_recursive_triggers_on,
        is_cursor_close_on_commit_on,
        is_local_cursor_default
    FROM sys.databases
    WHERE name = 'YourDatabaseName';
    

    Dependendo do que você vê, você pode tentar recriar o procedimento armazenado com o seguinte:

    SET ANSI_NULLS ON;
    SET ANSI_PADDING ON;
    SET ANSI_WARNINGS ON;
    SET ARITHABORT ON;
    SET CONCAT_NULL_YIELDS_NULL ON;
    SET QUOTED_IDENTIFIER ON;
    SET NUMERIC_ROUNDABORT OFF;
    

    algumas outras coisas

    Para sua consideração geral, embora não seja necessariamente um grande problema para esta consulta específica:

    1. NOLOCKfede e pode retornar dados incorretos/inconsistentes
    2. TOPsem um ORDER BYé uma proposição duvidosa
    3. @Table Variablesforçam modificações para serem executadas em thread único e geralmente não são tão interessantes quando você começa a juntá-las a outras tabelas, pois elas não obtêm estatísticas em nível de coluna, mesmo quando indexadas

    Observe o CouldNotGenerateValidParallelPlanatributo do INSERToperador. Neste caso, porém, ambos os custos do plano são tão baixos que é improvável que se consiga um plano de execução paralelo de qualquer maneira.

    • 10

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