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)
jato
fonte
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.]

markp-fuso
fonte
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 .

Max Vernon
fonte
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.

Raio
fonte
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