Eu trabalhava para uma empresa onde eles tinham essa solução de data warehouse de terceiros. Obviamente, todos os objetos e tabelas estavam ocultos no banco de dados de suporte, então não tenho uma ideia clara do que exatamente aconteceu dentro de alguns dos procedimentos armazenados. Eu vi esse procedimento armazenado interessante lá e quero replicá-lo em minha própria solução, mas simplesmente não consigo entender como ele funciona. Estou descrevendo o procedimento armazenado abaixo e será muito útil se alguém puder me dar algumas ideias sobre como conseguir isso. Melhor ainda se você puder me sugerir como posso tornar isso ainda melhor.
O procedimento armazenado foi chamado de log do processo. Tinha parâmetros como DBID, ObjectId, Step, Status, Remarks, Reads, Inserts, Updates, Deletes
O que tivemos que fazer foi, dentro de cada procedimento armazenado, temos que executar este procedimento armazenado com Status como 2 (Em andamento) Durante o processo, onde podemos executar este procedimento armazenado várias vezes no final de cada etapa ou seção após aumentar o valor de passo variável. com base nas contagens de linhas das instruções Insert update select e delete, deveríamos registrar valores nas respectivas variáveis de parâmetro do procedimento armazenado. No final, você pode executar o mesmo procedimento armazenado com Status de 3 (Concluído) ou se o procedimento terminou no bloco catch, o status será 4 (Falha) na seção de comentários, podemos copiar as mensagens de erro do SQL.
Para ver todas essas informações, tivemos acesso a um relatório, para o qual obviamente eu não tinha o código-fonte, mas o relatório mostrava a que horas o procedimento armazenado começou, quando terminou, qual era o status quantas atualizações inserções exclui e lê fez. se falhou, qual foi a mensagem de erro?
Já tenho algumas ideias de melhorias para armazenar, quem começou?, quais eram os valores dos parâmetros? Para quem iniciou a parte do procedimento armazenado, estou confuso. A maioria desses procedimentos armazenados é executada como parte de diferentes trabalhos. Todos os nossos trabalhos são executados como um usuário de conta de serviço, mas os trabalhos são iniciados manualmente por vários usuários. Preciso descobrir qual usuário iniciou, pois dentro do procedimento armazenado, como usuário atual, sempre mostrará a conta de serviço. Também para Valores de Parâmetros, existe uma maneira dinâmica melhor de descobrir isso? em vez de definir um valor para uma variável manualmente. Eu esperava usar a saída de INPUTBUFFER, mas ela mostra apenas o nome do parâmetro, não os valores.
Se alguém puder me orientar sobre a estrutura da tabela de back-end e o script para este SP de auditoria, será muito útil. Além disso, mais ideias de melhoria são bem-vindas.
Minha principal confusão: acredito que eles tinham alguma tabela onde estavam armazenados esses valores de stored procedures e se o SP já estiver rodando, eles atualizaram no registro então fazendo um Insert mas como eles identificariam para fazer um insert ao invés de atualizar no cenário onde o procedimento armazenado falhou criticamente e o bloco catch não foi executado.
Aqui está uma estrutura que é pelo menos muito próxima.
Não há nenhuma maneira programática de obter os parâmetros (infelizmente). Você precisa formatá-los em XML para passar.
O Login que inicia um trabalho do SQL Agent parece ser registrado apenas na
message
coluna demsdb.dbo.sysjobhistory
, parastep_id = 0
. Este valor pode ser extraído, mas não durante a execução do trabalho.Você obtém ObjectID para passar de
@@PROCID
.Abaixo está o esquema (2 tabelas) e procedimentos armazenados (3 procs). O conceito é separar o log "init", "em processo" e "concluído (sucesso ou erro)". Isso permite definir certas colunas apenas no momento apropriado (por exemplo, só é necessário definir
DatabaseID
,StartedAt
, etc. no início). Separar o tipo de evento também facilita a lógica específica do evento (sim, pode ter até mesmo em um único procedimento, mas você ainda tem todos os parâmetros de entrada quando precisa apenas de um subconjunto para cada tipo de evento).Um registro de "processo" é atualizado por meio de seu valor IDENTITY (e PK em cluster). Este é outro benefício de ter a separação de "tipo de evento": torna muito mais fácil manipular a captura
SCOPE_IDENTITY()
e passá-lo de volta para ser usado para os outros dois procedimentos armazenados de registro. Se um procedimento armazenado falhar e não for para oCATCH
bloco, não há necessidade de se preocupar em atualizar acidentalmente esse registro de processo, pois na próxima vez que qualquer procedimento armazenado (que está sendo registrado) for iniciado, ele obterá um ID novo/exclusivo atualizar.Limpeza (opcional) e Esquema
Tabelas e Índices
Procedimento armazenado para chamar no início de procedimentos armazenados "logados"
Procedimento armazenado para chamar depois de tudo, mas a etapa final
Procedimento armazenado para chamar após a etapa final e/ou em um bloco CATCH
Procedimento armazenado de demonstração (os parâmetros de entrada são formatados como XML)
A razão para colocar "StepNumber" em uma variável é para que o valor possa ser passado para o
CATCH
bloco. A@StepNumber
variável é incrementada antes de cada operação. Se a operação for bem-sucedida, esse valor é usado para chamar o procedimento armazenado "Log" que captura o número de linhas afetadas por essa etapa e a hora em que foi chamada. Se a operação falhar, esse mesmo@StepNumber
valor é usado para chamar o procedimento armazenado "Stop" que marca o processo como "falha" e transmite a mensagem de erro. Isso torna os dados menos confusos, pois aStep
coluna nos registros com falha será a etapa em que ela estava realmente trabalhando quando ocorreu o erro.NOTAS:
Com relação à obtenção do logon "invocado por" para trabalhos do SQL Server Agent: o
step_id = 0
registro (que é o único local onde essas informações existem) não existe até que o trabalho seja concluído (sucesso ou falha). Portanto, ele não está disponível enquanto o procedimento armazenado está em execução, muito menos no início. Por enquanto, capturamos oMAX(sjh.[instance_id]) FROM msdb.dbo.sysjobhistory sjh
trabalho atualmente em execução para a sessão atual. Mais tarde (ou seja, após a conclusão do trabalho), isso pode ser substituído pelo Login do invocador do trabalho.Eu geralmente não recomendaria adicionar esse tipo de log a procedimentos armazenados que são executados com muita frequência, pois as operações adicionais de leitura e gravação terão um impacto negativo no desempenho.
TERMO ADITIVO
Aqui está uma função de valor de tabela embutida (ITVF) para obter as informações do resultado do trabalho (incluindo o usuário "invocado por" ou agendamento ou qualquer outro) com base no
instance_id
valor que foi capturado naProcessLog.StartedBy
coluna. Oinstance_id
valor retornado no conjunto de resultados é a linha parastep_id = 0
.