SELECT INTO reserva o nome do objeto # no TempDB antes do tempo de execução?

8

Reunindo um processo rápido para ajudar na depuração, encontrei um que parece ser um erro no compilador.

create proc spFoo
    @param bit
as
begin
    if @param = 0
    begin 
        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

Tentativa acima, retorna o seguinte erro

Msg 2714, Nível 16, Estado 1, Procedimento spFoo, Linha 19
Já existe um objeto chamado '#bar' no banco de dados.

Em um sentido legível por humanos, o proc parece estar bem: apenas uma select intodeclaração será executada, uma vez que estão dentro dos if-elseblocos. Muito bem, o SQL Server não pode confirmar se as instruções são logicamente excluídas uma da outra. Talvez o mais confuso seja o fato de que o erro permanece quando drop table #fooé colocado dentro do bloco if-else (que se supõe que seria dito ao compilador para desalocar o nome do objeto) como abaixo.

create proc spFoo
    @param bit
as
begin
    select top 1 * 
    into #bar
    from [master].dbo.spt_values

    if @param = 0
    begin 
        drop table #bar;

        select * 
        into #bar
        from [master].dbo.spt_values
        -- where number between ...
    end
    else
    begin
        drop table #bar;

        select top 10 * 
        into #bar
        from [master].dbo.spt_values
        order by newid();
    end;
end;

O proc em si está bem. Eu peguei e escrevi as declarações create table #foo( ... )e insert #foo ( ... ), eu estava tentando pular com a select * into sintaxe. Neste ponto, estou apenas tentando entender por que o compilador me cagou com a sintaxe do cara preguiçoso. A única coisa em que consigo pensar é que o comando DDL reserva o nome do objeto IN TEMPDB .

Por que o texto em negrito?

create proc spIck
as
begin
    create table #ack ( col1 int );
    drop table #ack;
    create table #ack ( colA char( 1 ) );
    drop table #ack;
end;

Isso falha com o mesmo código de erro acima. Mas o seguinte ...

create proc spIck
as
begin
    create table ack ( col1 int );
    drop table ack;
    create table ack ( colA char( 1 ) );
    drop table ack;
end;

... consegue. O mesmo segue acima para a tentativa proc original. Assim...

Minha pergunta é esta

Qual é a diferença (e por que está presente) na reserva de nome de objeto para TempDBobjetos em oposição aos bancos de dados do usuário. Nenhuma das referências do Logical Query Processing nem das referências de comando DDL que revi parecem explicar isso.

Peter Vandivier
fonte
11
Esta captura de tela do "Guia do Guru para procedimentos armazenados do SQL Server, XML e HTML" (no Google Livros) parece relevante e indica que tem sido assim desde o 7.0 i.stack.imgur.com/8pDGT.png
Martin Smith
Parece ser a página 6 (para sua informação, para qualquer pessoa que vier mais tarde).
Peter Vandivier

Respostas:

6

Isso não tem nada a ver com reservas de nome de objeto no TempDB ou com o tempo de execução. Isso é simplesmente o analisador que não consegue seguir os caminhos lógicos ou de código que garantem que seu código não possa tentar criar essa tabela duas vezes. Observe que você obtém exatamente o mesmo erro (sem tempo de execução!) Se apenas clicar no botão Analisar ( Ctrl+ F5). Basicamente, se você tiver isso:

IF 1=1 
  CREATE TABLE #foo(id1 INT);
ELSE
  CREATE TABLE #foo(id2 INT);

O analisador vê isso:

  CREATE TABLE #foo(id1 INT);
  CREATE TABLE #foo(id2 INT);

Por que não funciona dessa maneira para tabelas reais , incluindo tabelas de usuários reais criadas no TempDB (observe que também não é específico do banco de dados)? A única resposta que posso sugerir é que o analisador possui um conjunto de regras diferente para as tabelas #temp (também existem muitas outras diferenças). Se você quiser motivos mais específicos, precisará abrir um caso com a Microsoft e verificar se eles fornecerão mais detalhes. Meu palpite é que você será informado: "é assim que funciona".

Mais algumas informações nestas respostas:

Aaron Bertrand
fonte
De fato, " é assim que funciona " é exatamente a resposta que eles têm. Oh, bem ...
Peter Vandivier