Usando SPID em tabelas de banco de dados (em vez de variável de tabela)


8

Banco de dados transacional usado para reservar itens ...

Nosso fornecedor foi solicitado a substituir #temptables por @tablevariables (devido a bloqueios pesados ​​de compilação), mas eles foram substituídos por uma tabela real que adiciona o SPID como uma coluna para garantir que o procedimento armazenado atue apenas nas linhas aplicáveis.

Você vê algum risco nesse método de operação? Antes de todas as transações serem isoladas dentro de sua própria transação ... Preocupei-me que possamos acabar bloqueando muito essa tabela, mas a opinião deles é que o SQL usa bloqueio no nível de linha e isso não criará mais bloqueios.

Versão do SQL Server: 2016 Enterprise - 13.0.5216.0


CREATE TABLE dbo.qryTransactions (
    ID int IDENTITY (0,1) NOT NULL CONSTRAINT pk_qryTransactions PRIMARY KEY CLUSTERED,
    spid int NOT NULL,
    OrderID int,
    ItemID int,
    TimeTransactionStart datetime,
    TimeTransactionEnd datetime,
...other fields
    )

CREATE INDEX idx_qryTransactions_spidID ON qryTransactions (spid, ID) INCLUDE (ItemID, OrderID, TimeTransactionStart, TimeTransactionEnd)

11
Depende. Quantas sessões estão usando a tabela simultaneamente, quão ativas são as sessões mencionadas, quantos registros estão dentro da tabela, os registros nesta nova tabela são eliminados ou permanecem etc.? 5 sessões, não é grande coisa. 500 sessões, é bem provável que você encontre o bloqueio que não veria com tabelas / variáveis ​​temporárias locais para cada sessão.
— John Eisbrener 17/07/19

Qual versão do servidor sql você está usando?
— Anthony Genovese

2016 Enterprise - 13.0.5216.0
— outjet

Os registros por sessão que atingem a tabela serão de 1 a 50 ... eles serão limpos, de modo que a tabela em si provavelmente não terá mais de 1.000 linhas ao mesmo tempo ... sessões simultâneas provavelmente em torno de 50 ....
— outjet

11
Se você for forçado a seguir esse caminho (tente evitá-lo), eu pensaria seriamente em particionar no valor spid, certificando-me de que a escalação de bloqueios na tabela esteja definida como AUTO. Então, pelo menos, a limpeza dos dados de um spid específico pode ser feita em uma operação de comutação e truncamento.
— Jonathan Fite

Respostas:


5

Um pouco mais desmedido do que pode caber em um bloco de comentários ... e deseja destacar um comentário que o OP fez em resposta à resposta de Ray:

  • proc pai (Common_InsertOrders_1) cria uma tabela temporária
  • um proc filho (InsertOrders) consulta a tabela temporária
  • bloqueios de compilação estão sendo vistos para o processo filho (InsertOrders)

Fazendo uma ligeira tangente por um minuto ... o que aconteceria com esse cenário é o Sybase ASE ...

  • cada tabela temporária recebe um ID de objeto exclusivo (com certeza, o ID do objeto pode ser reutilizado em algum momento, mas isso é raro e certamente não acontecerá em sessões simultâneas)
  • O Sybase ASE normalmente forçará uma recompilação em cada execução do processo filho devido à alteração no ID do objeto da tabela temporária
  • O Sybase ASE também forçará uma recompilação do processo filho se perceber que a estrutura da tabela temporária foi alterada (por exemplo, número diferente de colunas, nomes / tipos de dados / tipos de dados diferentes / nulidade) entre invocações de processos armazenadas
  • versões mais recentes do Sybase ASE têm uma configuração que (efetivamente) diz ao compilador para ignorar alterações nos IDs de objeto da tabela temporária, eliminando assim a recompilação do processo filho (NOTA: as recompilações ainda ocorrerão se a estrutura da tabela for alterada)

Voltar ao problema do OP (bloqueios de compilação no processo filho) ...

  • existe uma chance de que alguns vestígios do comportamento do Sybase ASE ainda possam residir no SQL Server (a partir de quando os dois produtos eram ervilhas em um pod)?
  • existem configurações do SQL Server que poderiam reduzir (eliminar?) as recompilações do processo filho (se devido a alterações na identificação do objeto)?
  • o OP pode verificar se o processo pai está criando a tabela temporária com a mesma estrutura exata / DDL a cada vez?

Quanto à idéia de usar uma única tabela permanente com @@ SPID para diferenciar linhas entre sessões ... esteve lá, viu que ... eca ; questões recorrentes:

  • como / quando limpar linhas órfãs
  • a reutilização do @@ SPID pelo mecanismo de banco de dados pode levar a problemas de precisão dos dados se existirem dados órfãos (ou durante a limpeza de dados órfãos, por exemplo, excluir onde @@ SPID = 10, mas houver uma nova sessão / atual / ativa com @ @ SPID = 10 => a limpeza exclui muitos dados)
  • potencial para escalação de bloqueios de bloqueios de linha a bloqueios de página / tabela
  • se a tabela tiver índices, o bloqueio potencial (b) ao atualizar os índices
  • dependendo do banco de dados em que a tabela reside, você poderá observar muito mais atividades para gravar no dispositivo de log (no Sybase ASE, é possível, efetivamente, desativar o log no tempdb)
  • até mesmo bloqueios no nível de linha (exclusivos) podem bloquear outras sessões (depende do nível de isolamento e se uma sessão pode ou não varrer / ignorar os bloqueios exclusivos)

Eu gostaria de voltar e (re) investigar o problema raiz (bloqueios de recompilação no processo filho) e ver se há uma maneira de reduzir (eliminar?) Os bloqueios de compilação mencionados. [Infelizmente, meu conhecimento do SQL Server sobre esses problemas é ... NULL ... por isso estaria interessado na entrada de alguns especialistas em compiladores do SQL Server.]


11
Concordo, acho que é preciso gastar mais tempo investigando os bloqueios de compilação. Isso tem alguns pontos a serem investigados. support.microsoft.com/en-us/help/263889/…
— Jonathan Fite

8

Parece-me que usar algo @@SPIDassim está pedindo problemas.

Os IDs de sessão são reutilizados com freqüência; assim que uma conexão do usuário se desconectar, esse ID da sessão estará disponível para ser usado novamente e provavelmente será usado pela próxima sessão que tentar se conectar.

Para fazê-lo funcionar pelo menos de maneira semi-confiável, você precisaria de um gatilho de logon que limpe as linhas anteriores da tabela com a mesma @@SPID. Se você fizer isso, provavelmente verá muitos bloqueios na tabela usando a @@SPIDcoluna.

O SQL Server realmente usa o bloqueio de linhas, mas também o bloqueio de páginas e o bloqueio de tabelas. Obviamente, você pode mitigar isso por meio de uma boa indexação, mas isso ainda parece um anti-padrão para mim.

Se o procedimento armazenado for o único método usado para acessar as tabelas afetadas, você poderá investigar usando um bloqueio de aplicativo, sp_getapplockpara essencialmente serializar o acesso às partes relevantes. Os documentos para sp_getapplock estão aqui . Erik Darling tem um post interessante sobre isso aqui .


4

Sim, eu vejo riscos. É ingênuo contar com o SQL usando o Bloqueio de linhas. Por exemplo, tenho certeza de que inserções e exclusões usarão bloqueios de página pelo menos. O SQL Engine escolhe o tipo de bloqueio com base em vários fatores e nenhum desses fatores inclui "a opinião deles". Soluções gerais, como alterar tabelas temporárias por variáveis ​​de tabela, geralmente também são más idéias. As variáveis ​​de tabela são muito úteis em algumas situações, mas elas têm limitações e problemas de desempenho. Prefiro tabelas temporárias na maioria das circunstâncias. Especialmente quando a tabela conterá mais de algumas dezenas de linhas. Eu exigiria que o fornecedor explicasse por que o sistema experimentou "bloqueios pesados ​​de compilação" e como isso prejudicou o desempenho. Lembre-se, sempre que você olhar, encontrará "bloqueios pesados" de algum tipo. Isso não significa necessariamente que os bloqueios sejam um problema. Max ' Os comentários de s sobre @@ SPID também são importantes. Além disso, o modelo de transação e o processamento de erros podem ser grandes problemas. Se o seu sistema tiver conflitos ou problemas de qualidade de dados de entrada, o processamento de erros padrão poderá resultar no encerramento da sessão sem que a tabela qryTransactions seja redefinida corretamente. OMI, a abordagem da solução errada para o problema original.


Obrigado pela resposta - para os seus pontos: nossos rastreamentos mostram LCK pesado espera por um bloqueio de compilação no procedimento armazenado InsertOrders. Existe um procedimento pai Common_InsertOrders_1 que declara a tabela temporária #qryTransactions e, em seguida, o procedimento aninhado InsertOrders_2 consulta a tabela temporária. Além disso, descobrimos também há recompilação frequente devido ao fim de 6 modificação de uma tabela temporário vazio, qualquer procedimento armazenado que referenciar tabela temporária terá de ser recompilados
— outjet

Há muitas razões pelas quais um procedimento ou instrução será recompilado. MarkP mencionou vários deles que se aplicam no SyBase e tenho certeza que o SQL Server é semelhante. A contagem de linhas da tabela temporária é um bom exemplo e a recompilação não é necessariamente uma coisa ruim. As estatísticas da tabela podem alterar substancialmente o plano de consulta ideal e é necessária uma recompilação para determinar isso. Mas quero reiterar. SEMPRE haverá um bloqueio superior e isso não significa que o bloqueio seja um problema. A menos que você veja outras evidências de um problema de desempenho, não se preocupe.
— Raio
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.