Quando exatamente vários usuários não conseguem executar simultaneamente um procedimento armazenado com uma tabela temporária?

9

Tenho uma pergunta sobre uma parte da documentação sobre tabelas temporárias que li recentemente no TechNet . O quarto parágrafo da seção Tabelas Temporárias nessa página tem a seguinte redação:

Se uma tabela temporária for criada com uma restrição nomeada e a tabela temporária for criada no escopo de uma transação definida pelo usuário, apenas um usuário por vez poderá executar a instrução que cria a tabela temporária. Por exemplo, se um procedimento armazenado criar uma tabela temporária com uma restrição de chave primária nomeada, o procedimento armazenado não poderá ser executado simultaneamente por vários usuários.

Trabalho em um ambiente em que fazemos uso significativo de alguns procedimentos armazenados que usam tabelas temporárias indexadas e nunca encontramos um problema em que os usuários precisavam esperar que uma execução fosse concluída antes do início da próxima. Espero que continue assim, mas estou preocupado que isso possa se tornar um problema se essa advertência não for entendida adequadamente.

Especificamente, não estou claro sobre os seguintes pontos:

  1. Isso se aplica apenas a tabelas temporárias globais ou também locais? Parece estranho que uma tabela que não esteja visível fora da sessão (como no último caso) impeça a execução simultânea de outra sessão.
  2. O que qualifica como uma "restrição nomeada"? Nem todas as restrições têm nomes (mesmo que sejam geradas pelo sistema)? Isso se refere a restrições com um alias definido pelo usuário? Isso parece um fraseado ruim para mim.
  3. "Múltiplos usuários" realmente significa várias sessões? Esses procedimentos são chamados por meio de nosso aplicativo usando uma conta de serviço única; portanto, 99,9% das chamadas para nossos scripts são feitas no banco de dados por essa conta única (e não estou preocupado com a ligação ocasional que um administrador pode fazer no back-end). Se a conta de serviço puder executar o sproc em várias sessões simultaneamente, esse problema é discutível para meus propósitos.
Wesley Marshall
fonte
11
Você mencionou que suas tabelas temporárias são indexadas, mas a questão é sobre restrições. Índices não são restrições. O que é verdade para um pode ou não ser verdadeiro para o outro. Nesse caso, os nomes de índice podem ser duplicados em um banco de dados, diferentemente das restrições. Os nomes de índice não podem ser duplicados em uma única tabela. Índices nomeados não causarão os problemas denominados restrições.
Shannon Severance
@ Shannon, na verdade, no momento em que escrevi a pergunta, eu confundi esse ponto. Eu acho que o uso prolífico de PRIMARY KEY CLUSTERED vs. PRIMARY KEY que eu vi no código de exemplo e na documentação me levou a acreditar que os índices clusterizados são restrições. E, por extensão, inferir que todos os índices são restrições. Fiz uma leitura leve da tarde mais cedo, o que esclareceu isso para mim.
Wesley Marshall

Respostas:

10

Penso nisso como você não pode ter nomes duplicados tempdb.sys.key_constraints. Aqui está o que há nessa exibição de metadados em um dos meus servidores:

visão inicial

Todos os nomes ímpares que terminam com _6E...eram nomes gerados automaticamente pelo SQL Server. Eles não têm restrições de nome porque eu não lhes dei um nome explicitamente ao criá-las. O SQL Server gera um nome de restrição nos bastidores que, em teoria, evita colisões de nomes.

Se eu tentar criar a tabela a seguir em duas sessões diferentes:

create table #x1 (
ID INT NOT NULL,
CONSTRAINT NAMED_CONSTRAINT_1 PRIMARY KEY (ID)
);

Aquele que executa o segundo lança um erro:

Mensagem 2714, nível 16, estado 5, linha 1

Já existe um objeto chamado 'NAMED_CONSTRAINT_1' no banco de dados.

Msg 1750, Nível 16, Estado 1, Linha 1

Não foi possível criar restrição ou índice. Veja erros anteriores.

Verificando a visualização novamente:

com restrição

Se eu tentar criar a tabela a seguir em duas sessões, não há problema:

create table #y1 (
ID INT NOT NULL,
PRIMARY KEY (ID)
);

Aqui está a exibição de metadados:

com restrições padrão

Apenas para responder suas perguntas diretamente: a parte que você citou se aplica a tabelas temporárias locais e globais, uma restrição nomeada é aquela na qual você deliberadamente nomeia um nome e vários usuários significam várias sessões.

Joe Obbish
fonte
11

Isso se aplica às tabelas temporárias locais.

A diferença entre restrições nomeadas e não nomeadas é esta:

CREATE TABLE #t1 (c1 INT PRIMARY KEY CLUSTERED)

CREATE TABLE #t2 (c1 INT,
                     CONSTRAINT pk_c1 PRIMARY KEY  CLUSTERED(c1) )

Deixar as restrições de nome do sistema torna extremamente improvável que ocorra uma colisão. Neste exemplo, se você abrir duas janelas no SSMS, poderá criar #t1nas duas, mas não #t2.

As tabelas temporárias globais são compartilhadas por todos os usuários, portanto, você precisa lidar com as coisas de maneira diferente. Eles não são "destruídos" até a última sessão ser concluída com eles, portanto, você precisa garantir que, quando os usuários os acessarem, eles possam acessar apenas seus dados. Às vezes, isso é feito pelo SPID, outras vezes, por um valor de hash. Depende de como a tabela temporária global é usada.

Tipicamente para tabelas temporárias globais, procedimentos armazenados irá verificar para ver se eles existem, e só então criá-los se o OBJECT_ID()é NULL.

Múltiplos usuários significa várias sessões. O nome de login não tem nada a ver com isso. Se George executar sp_something @i = 1e Gina executar sp_something @i = 2, não importa se os dois estão conectados como User1, eles terão SPIDs diferentes.

Erik Darling
fonte