Existe uma maneira de determinar se as consultas do SQL Server estão em execução na memória ou no disco?

13

Hoje me deparei com um conjunto de procedimentos armazenados em um aplicativo que são chamados repetidamente em um processo demorado. Em cada procedimento, encontrei várias instruções de seleção diferentes, algumas dentro de loops; não é de surpreender que essas rotinas usadas atualmente levem alguns minutos para serem executadas, quando a intuição espera que elas sejam concluídas em alguns segundos.

Parece bastante óbvio que o desempenho não foi levado em consideração quando esses procedimentos foram escritos; existem várias instâncias de coisas que "simplesmente não são uma boa idéia".

O processamento de cada linha ao importar dados leva 300 ms por linha, portanto, importações relativamente pequenas estão demorando alguns minutos para serem processadas.

No entanto, as tabelas envolvidas nos procedimentos são em sua maioria bastante pequenas. Penso que, se todas essas tabelas residirem totalmente na memória, talvez não haja muito o que se ganhar com a reescrita de tudo isso.

Estou tentando determinar ... por esse código obviamente ineficiente, que efeito real ele está tendo? Vale a pena consertar?

Portanto, a pergunta é:
- existe uma maneira de determinar quais tabelas estão totalmente afixadas na memória?
- existe uma maneira de ativar o rastreamento para monitorar procedimentos armazenados aninhados para encontrar as partes particularmente caras?

Nota: Isso está no SQL Server 2008 R2

tbone
fonte

Respostas:

12

Você pode usar uma dessas duas consultas para ver o total de leituras lógicas e o total de leituras físicas.

SELECT  DB_NAME(st.dbid) Db,
        OBJECT_NAME(st.objectid, st.dbid) Prc,
        qs.execution_count,
        qs.total_logical_reads,
        qs.total_physical_reads,
        qs.statement_start_offset,
        qs.statement_end_offset,
        st.text
FROM    sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st;

SELECT  DB_NAME(database_id) Db,
        OBJECT_NAME(object_id, database_id) Prc,
        execution_count,
        total_logical_reads,
        total_physical_reads
FROM    sys.dm_exec_procedure_stats ps;

O primeiro divide isso por declaração, o segundo conta em todo o procedimento.

Leituras físicas são leituras no disco, leituras lógicas são na memória. Você pode usar isso para descobrir quais procedimentos ou instruções são os mais caros em seu sistema e tentar ajustá-los.

Lembre-se de que, embora as leituras lógicas sejam significativamente mais baratas que as leituras físicas, elas ainda são caras, portanto, reduzir o número delas (por exemplo, adicionando um índice apropriado) pode tornar suas consultas muito mais rápidas.

Existem muitas colunas adicionais nas DMVs acima que você também pode achar interessante.


Como um índice ajuda a reduzir leituras lógicas?

No SQL Server, todos os dados são organizados em blocos, com tamanho de 8 KB. Esses blocos são chamados de "páginas".

Cada tabela contém páginas "meta" que contêm informações sobre o estrutura da tabela, bem como as páginas "pata". Se nenhum índice existir e você executar uma consulta como o SELECT * FROM tbl WHERE Id = 7SQL Server, precisará procurar esta ou essas linhas na tabela inteira. Por isso, ele lê uma página de cada vez, percorre todas as linhas de cada página para determinar as linhas que se encaixam na WHEREcláusula. Portanto, se a tabela exigir que 1.000.000 de páginas sejam armazenadas, essa consulta terá 1.000.000 de leituras lógicas para executar.

Se você tiver um índice, o SQL Server classificará os dados logicamente nas páginas e estabelecerá uma lista vinculada entre as páginas. Isso permite que consultas em execução ORDER BYsejam executadas sem uma operação de classificação dispendiosa. Mas, mais importante que a classificação, o SQL Server adiciona uma árvore B + à tabela. Uma Árvore B + é uma estrutura comparável ao índice de um livro, onde procurar uma palavra-chave específica permite-me pular diretamente para a página que contém a palavra-chave. O livro típico possui apenas um nível de índice, enquanto uma árvore B + pode ter vários. Pense em um livro grande, onde o próprio índice tem várias páginas. Em um caso como esse, faz sentido adicionar uma camada de índice adicional que nos diz em qual página as palavras de índice começando com Sdevem ser encontradas.

As árvores B + são otimizadas para ter o mínimo de níveis possível, fornecendo a propriedade de que qualquer registro no índice possa ser encontrado lendo uma página por nível de índice. Portanto, assuma a WHERE Id = 7consulta acima quando você tiver um índice classificado por Id. Digamos que o índice tenha 5 níveis. Agora, para encontrar todos os registros que correspondam a essa consulta, preciso ler uma página por nível de índice (ou seja, 5 páginas). Isso é chamado de "Busca de índice". Se houver vários registros adequados à conta, talvez seja necessário seguir o índice classificado por um tempo para recuperar todos eles. Mas vamos supor que haja apenas um registro.

Portanto, sem o índice em execução, essa consulta exigia 1.000.000 leituras, e indes exigia 5 leituras. Embora uma leitura lógica seja uma operação na memória, ainda há um custo substancial - na verdade, é a operação mais cara em uma consulta trivial como a acima. Portanto, reduzir a quantidade de leituras lógicas necessárias por um fator de 200.000 acelerará sua consulta por um fator semelhante.

Portanto, uma leitura lógica não é equivalente a uma varredura de tabela, mas uma varredura de tabela causa leituras muito mais lógicas do que uma busca de índice.

Sebastian Meine
fonte
> "... reduzir o número deles (por exemplo, adicionando um índice apropriado) pode tornar suas consultas muito mais rápidas." Você poderia explicar como a adição de um índice reduzirá (?) Leituras lógicas? A leitura lógica é sinônimo de uma varredura de tabela?
1
Adicionada uma explicação para minha resposta acima.
Sebastian Meine
Obrigado. Mesmo assumindo índices adequados em todas as tabelas envolvidas ... Eu acho que ainda existe uma grande diferença de desempenho entre uma tabela sendo fixada na memória e lida no disco (assuma os mesmos índices nos dois cenários) ... ou em outros Em outras palavras, adicionar índices resultará em menos% de aumento de desempenho em uma máquina com muita RAM do que em uma máquina com menos memória ... correta?
1
o acesso físico ao disco é claramente uma ordem de grandeza mais cara que o acesso à memória. Portanto, tomar medidas para evitá-lo vai muito longe. Você ainda deve examinar primeiro o número de leituras lógicas ao ajustar a consulta. Mantê-los baixos, por sua vez, manterá as leituras físicas baixas. Há também uma grande chance de as páginas não precisarem ser removidas do cache, reduzindo ainda mais as leituras físicas necessárias.
Sebastian Meine
2
Nitpick menor - acho que as páginas têm 8kb :-). Boa resposta.
Onupdatecascade
3
  • existe uma maneira de ativar o rastreamento para monitorar procedimentos armazenados aninhados para encontrar as partes particularmente caras?

Você pode usar o SQL Profiler. Ao iniciar o rastreamento, você deve escolher RPC Concluído, SP Starting, SP StmtStarting e SP StmtCompleted (veja a imagem abaixo)

insira a descrição da imagem aqui

Isso permitirá que você veja todas as consultas executadas dentro dos procedimentos armazenados. Isso permitirá que você veja quantas vezes um procedimento armazenado aninhado é chamado. Quando o rastreamento terminar, você deve salvá-lo. Em seguida, abra-o novamente e, depois disso, você poderá filtrar (com o botão "Filtros de coluna") para encontrar as consultas que causam problemas. (por exemplo: as consultas que levaram mais de x leituras ou que duraram mais de x segundos (duração) ...)

As opções do criador de perfil que mostrei também mostram o plano de execução, o que também ajuda bastante.

Danielle Paquette-Harvey
fonte
1

Parece uma pergunta geral sobre otimização de consultas. Pela sua descrição, eu:

  1. Veja o código para ver se ele processa linha por linha. Se isso acontecer, muitas vezes as ordens de melhoria de magnitude podem ser feitas implementando a mesma lógica usando conjuntos (várias linhas processadas ao mesmo tempo). Em outras palavras, se ele agir como "loop sobre cada linha", altere-o para "processar todas as linhas". O SQL é excelente porque o otimizador pode escolher entre os métodos mais possíveis, potencialmente usar o paralelismo, remover muita sobrecarga proveniente de uma linha por vez.
  2. Certifique-se, a seguir, de que existem índices que suportam o trabalho. Freqüentemente, novamente, ordens de melhoria de magnitude podem ser obtidas com índices corretos versus não. Isso é verdade na memória e com acesso ao disco. Os processos ainda podem levar horas com tudo na RAM, se não houver índices apropriados em um grande conjunto de dados.
  3. Em seguida, com lógica e índices definidos, verificaria se as páginas de dados afetadas cabem na memória. Nesse ponto, se ainda houver muito acesso ao disco, analisar as leituras físicas e a atividade do disco faz sentido, porque todos os grandes ganhos com a otimização são realizados nas duas primeiras etapas.
onupdatecascade
fonte