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 / 30862
Accepted
Martin Smith
Martin Smith
Asked: 2012-12-21 12:51:39 +0800 CST2012-12-21 12:51:39 +0800 CST 2012-12-21 12:51:39 +0800 CST

Otimizando planos com leitores XML

  • 772

Executando a consulta daqui para retirar os eventos de impasse da sessão padrão de eventos estendidos

SELECT CAST (
    REPLACE (
        REPLACE (
            XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
            '<victim-list>', '<deadlock><victim-list>'),
        '<process-list>', '</victim-list><process-list>')
    AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
    FROM sys.dm_xe_session_targets st
    JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
    WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
    WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';

leva cerca de 20 minutos para ser concluído na minha máquina. As estatísticas relatadas são

Table 'Worktable'. Scan count 0, logical reads 68121, physical reads 0, read-ahead reads 0, 
         lob logical reads 25674576, lob physical reads 0, lob read-ahead reads 4332386.

 SQL Server Execution Times:
   CPU time = 1241269 ms,  elapsed time = 1244082 ms.

Plano Lento XML

Paralelo

Se eu remover a WHEREcláusula, ela será concluída em menos de um segundo, retornando 3.782 linhas.

Da mesma forma, se eu adicionar OPTION (MAXDOP 1)à consulta original que acelera as coisas também, as estatísticas agora mostram muito menos leituras de lob.

Table 'Worktable'. Scan count 0, logical reads 15, physical reads 0, read-ahead reads 0,
                lob logical reads 6767, lob physical reads 0, lob read-ahead reads 6076.

 SQL Server Execution Times:
   CPU time = 639 ms,  elapsed time = 693 ms.

XML do plano mais rápido

Serial

Então minha pergunta é

Alguém pode explicar o que está acontecendo? Por que o plano original é tão catastroficamente pior e existe alguma maneira confiável de evitar o problema?

Adição:

Também descobri que alterar a consulta para INNER HASH JOINmelhorar as coisas até certo ponto (mas ainda leva> 3 minutos), pois os resultados do DMV são tão pequenos que duvido que o próprio tipo Join seja responsável e presumo que algo mais deva ter mudado. Estatísticas para isso

Table 'Worktable'. Scan count 0, logical reads 30294, physical reads 0, read-ahead reads 0, 
          lob logical reads 10741863, lob physical reads 0, lob read-ahead reads 4361042.

 SQL Server Execution Times:
   CPU time = 200914 ms,  elapsed time = 203614 ms.

(E planejar)

Depois de preencher o buffer de anel de eventos estendidos ( DATALENGTHdos XMLquais eram 4.880.045 bytes e continha 1.448 eventos.) e testar uma versão reduzida da consulta original com e sem a MAXDOPdica.

SELECT COUNT(*)
FROM   (SELECT CAST (target_data AS XML) AS TargetData
        FROM   sys.dm_xe_session_targets st
               JOIN sys.dm_xe_sessions s
                 ON s.address = st.event_session_address
        WHERE  [name] = 'system_health') AS Data
       CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE  XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report'

SELECT*
FROM   sys.dm_db_task_space_usage
WHERE  session_id = @@SPID 

Deu os seguintes resultados

+-------------------------------------+------+----------+
|                                     | Fast |   Slow   |
+-------------------------------------+------+----------+
| internal_objects_alloc_page_count   |  616 |  1761272 |
| internal_objects_dealloc_page_count |  616 |  1761272 |
| elapsed time (ms)                   |  428 |   398481 |
| lob logical reads                   | 8390 | 12784196 |
+-------------------------------------+------+----------+

Há uma clara diferença nas alocações de tempdb com a mais rápida mostrando que as 616páginas foram alocadas e desalocadas. Esta é a mesma quantidade de páginas usadas quando o XML também é colocado em uma variável.

Para o plano lento, essas contagens de alocação de página chegam a milhões. A pesquisa dm_db_task_space_usageenquanto a consulta está em execução mostra que parece estar constantemente alocando e desalocando páginas tempdbentre 1.800 e 3.000 páginas alocadas a qualquer momento.

sql-server sql-server-2012
  • 2 2 respostas
  • 15150 Views

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2012-12-22T22:40:02+08:002012-12-22T22:40:02+08:00

    O motivo da diferença de desempenho está em como as expressões escalares são tratadas no mecanismo de execução. Neste caso, a manifestação de interesse é:

    [Expr1000] = CONVERT(xml,DM_XE_SESSION_TARGETS.[target_data],0)
    

    Esse rótulo de expressão é definido por um operador Compute Scalar (nó 11 no plano serial, nó 13 no plano paralelo). Os operadores Compute Scalar são diferentes de outros operadores (SQL Server 2005 em diante) porque as expressões que eles definem não são necessariamente avaliadas na posição em que aparecem no plano de execução visível; a avaliação pode ser adiada até que o resultado do cálculo seja solicitado por um operador posterior.

    Na consulta atual, a target_datastring geralmente é grande, tornando a conversão de string em XMLdispendiosa. Em planos lentos, a string para XMLconversão é executada toda vez que um operador posterior que requer o resultado Expr1000é rebote.

    A religação ocorre no lado interno de uma junção de loops aninhados quando um parâmetro correlacionado (referência externa) é alterado. Expr1000é uma referência externa para a maioria das junções de loops aninhados neste plano de execução. A expressão é referenciada várias vezes por vários leitores XML, ambos Stream Aggregates e por um filtro de inicialização. Dependendo do tamanho do XML, o número de vezes que a string é convertida XMLpode facilmente chegar a milhões.

    As pilhas de chamadas abaixo mostram exemplos da target_datastring sendo convertida para XML( ConvertStringToXMLForES- onde ES é o Serviço de Expressão ):

    Filtro de inicialização

    Pilha de chamada do filtro de inicialização

    Leitor de XML (TVF Stream internamente)

    Pilha de chamada de fluxo de TVF

    Fluxo Agregado

    Pilha de chamada agregada de fluxo

    A conversão da string para XMLcada vez que qualquer um desses operadores é religado explica a diferença de desempenho observada com os planos de loops aninhados. Isso ocorre independentemente de o paralelismo ser usado ou não. Acontece que o otimizador escolhe um hash join quando a MAXDOP 1dica é especificada. Se MAXDOP 1, LOOP JOINfor especificado, o desempenho será ruim, assim como no plano paralelo padrão (onde o otimizador escolhe loops aninhados).

    Quanto o desempenho aumenta com uma junção de hash depende se Expr1000aparece no lado de compilação ou de teste do operador. A consulta a seguir localiza a expressão no lado da sonda:

    SELECT CAST (
        REPLACE (
            REPLACE (
                XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
                '<victim-list>', '<deadlock><victim-list>'),
            '<process-list>', '</victim-list><process-list>')
        AS XML) AS DeadlockGraph
    FROM (SELECT CAST (target_data AS XML) AS TargetData
        FROM sys.dm_xe_sessions s
        INNER HASH JOIN sys.dm_xe_session_targets st ON s.address = st.event_session_address
        WHERE [name] = 'system_health') AS Data
    CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
    WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';
    

    Inverti a ordem escrita das junções da versão mostrada na pergunta, porque as dicas de junção ( INNER HASH JOINacima) também forçam a ordem para toda a consulta, como se FORCE ORDERtivesse sido especificada. A inversão é necessária para garantir que Expr1000apareça no lado da sonda. A parte interessante do plano de execução é:

    dica 1

    Com a expressão definida no lado da sonda, o valor é armazenado em cache:

    Hash Cache

    A avaliação de Expr1000ainda é adiada até que o primeiro operador precise do valor (o filtro de inicialização no rastreamento de pilha acima), mas o valor calculado é armazenado em cache ( CValHashCachedSwitch) e reutilizado para chamadas posteriores pelos leitores de XML e agregados de fluxo. O rastreamento de pilha abaixo mostra um exemplo do valor armazenado em cache sendo reutilizado por um leitor de XML.

    reutilização de cache

    Quando a ordem de junção é forçada de forma que a definição de Expr1000ocorra no lado da construção da junção hash, a situação é diferente:

    SELECT CAST (
        REPLACE (
            REPLACE (
                XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
                '<victim-list>', '<deadlock><victim-list>'),
            '<process-list>', '</victim-list><process-list>')
        AS XML) AS DeadlockGraph
    FROM (SELECT CAST (target_data AS XML) AS TargetData
        FROM sys.dm_xe_session_targets st 
        INNER HASH JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
        WHERE [name] = 'system_health') AS Data
    CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
    WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report'
    

    Hash 2

    Uma junção de hash lê sua entrada de compilação completamente para construir uma tabela de hash antes de iniciar a sondagem de correspondências. Como resultado, temos que armazenar todos os valores, não apenas aquele por thread que está sendo trabalhado do lado da sonda do plano. O hash join, portanto, usa uma tempdbmesa de trabalho para armazenar os XMLdados, e todo acesso ao resultado Expr1000por operadores posteriores requer uma viagem cara para tempdb:

    acesso lento

    O seguinte mostra mais detalhes do caminho de acesso lento:

    Detalhes lentos

    If a merge join is forced the input rows are sorted (a blocking operation, just like the build input to a hash join) resulting in a similar arrangement where slow access via a tempdb sort-optimized worktable is required because of the size of the data.

    Plans that manipulate large data items can be problematic for all sorts of reasons that are not apparent from the execution plan. Using a hash join (with the expression on the correct input) is not a good solution. It relies on undocumented internal behaviour with no guarantees it will work the same way next week, or on a slightly different query.

    A mensagem é que a XMLmanipulação pode ser algo complicado de otimizar hoje. Escrever o XMLem uma variável ou tabela temporária antes de triturar é uma solução alternativa muito mais sólida do que qualquer coisa mostrada acima. Uma maneira de fazer isso é:

    DECLARE @data xml =
            CONVERT
            (
                xml,
                (
                SELECT TOP (1)
                    dxst.target_data
                FROM sys.dm_xe_sessions AS dxs 
                JOIN sys.dm_xe_session_targets AS dxst ON
                    dxst.event_session_address = dxs.[address]
                WHERE 
                    dxs.name = N'system_health'
                    AND dxst.target_name = N'ring_buffer'
                )
            )
    
    SELECT XEventData.XEvent.value('(data/value)[1]', 'varchar(max)')
    FROM @data.nodes ('./RingBufferTarget/event[@name eq "xml_deadlock_report"]') AS XEventData (XEvent)
    WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';
    

    Finalmente, eu só quero adicionar o gráfico muito bom de Martin dos comentários abaixo:

    gráfico de Martin

    • 41
  2. Jonathan Kehayias
    2012-12-21T19:16:22+08:002012-12-21T19:16:22+08:00

    Esse é o código do meu artigo originalmente postado aqui:

    http://www.sqlservercentral.com/articles/deadlock/65658/

    Se você ler os comentários, encontrará algumas alternativas que não têm os problemas de desempenho que você está enfrentando, uma usando uma modificação dessa consulta original e a outra usando uma variável para armazenar o XML antes de processá-lo, o que funciona Melhor. (veja meus comentários na página 2) O XML do DMV pode ser lento para processar, assim como a análise do XML do DMF para o destino do arquivo, que geralmente é melhor realizado lendo os dados em uma tabela temporária primeiro e depois processando-os. XML em SQL é lento em comparação com coisas como .NET ou SQLCLR.

    • 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

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 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

    Como selecionar a primeira linha de cada grupo?

    • 6 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +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