Ainda errado ao iniciar o nome de um procedimento armazenado pelo usuário com sp_?

33

Um dos meus colegas de trabalho nomeou um procedimento armazenado em nosso banco de dados SQL Server 2008 R2 sp_something. Quando vi isso, pensei imediatamente: "Está errado!" e comecei a pesquisar nos meus favoritos este artigo on-line que explica por que está errado, para que eu pudesse fornecer uma explicação ao meu colega de trabalho.

No artigo (de Brian Moran ), é explicado que atribuir ao procedimento armazenado um prefixo sp_ faz com que o SQL Server procure no banco de dados mestre um plano compilado. Como o sp_sprocarquivo não reside lá, o SQL Server recompilará o procedimento (e precisará de um bloqueio de compilação exclusivo para isso, causando problemas de desempenho).

O exemplo a seguir é fornecido no artigo para mostrar a diferença entre dois procedimentos:

USE tempdb;
GO

CREATE PROCEDURE dbo.Select1 AS SELECT 1;
GO

CREATE PROCEDURE dbo.sp_Select1 AS SELECT 1;
GO

EXEC dbo.sp_Select1;
GO

EXEC dbo.Select1;
GO

Você executa isso, abra o Profiler (adicione o SP:CacheMissevento Stored Procedures -> ) e execute os procedimentos armazenados novamente. Você deve ver uma diferença entre os dois procedimentos armazenados: o sp_Select1procedimento armazenado gerará mais um SP:CacheMissevento que o Select1procedimento armazenado (o artigo faz referência ao SQL Server 7.0 e SQL Server 2000 ).

Quando executo o exemplo no meu ambiente do SQL Server 2008 R2, recebo a mesma quantidade de SP:CacheMisseventos para os dois procedimentos (no tempdb e em outro banco de dados de teste).

Então, eu estou pensando:

  • Posso ter feito algo errado na execução do exemplo?
  • O sproc sp_somethingadágio ' não nomear um usuário ' ainda é válido nas versões mais recentes do SQL Server?
  • Em caso afirmativo, existe um bom exemplo que mostra sua validade no SQL Server 2008 R2?

Muito obrigado por seus pensamentos sobre isso!

EDITAR

Encontrei Criando procedimentos armazenados (mecanismo de banco de dados) no msdn para SQL Server 2008 R2, que responde minha segunda pergunta:

Recomendamos que você não crie procedimentos armazenados usando sp_ como prefixo. O SQL Server usa o prefixo sp_ para designar procedimentos armazenados do sistema. O nome escolhido pode entrar em conflito com algum procedimento futuro do sistema. [...]

Nada é mencionado lá sobre problemas de desempenho causados ​​pelo uso do sp_prefixo. Gostaria de saber se esse ainda é o caso ou se eles o corrigiram após o SQL Server 2000.

marc_s
fonte
3
Eu olhei para isso antes e encontrei uma diferença de desempenho insignificante que eu atribuí a uma sobrecarga um pouco maior de resolver as sp_versões (precisa verificar os bancos de dados mestre e de usuário porque prioriza os procs do sistema em master-> procs no usuário DB -> não sistema procs in master)
Martin Smith
4
Qual o benefício que você vê ao prefixar um procedimento armazenado sp_? Isso é tão útil quanto prefixar uma tabela com tbl. Por que tornar a pesquisa do sistema principal primeiro (mesmo que seja insignificante ou sem diferença de desempenho) para permitir que você use essa convenção de nomenclatura sem sentido?
Aaron Bertrand
1
@AaronBertrand: para ser honesto, eu não vejo nenhuma vantagem em tudo no prefixo sprocs com sp_, apenas desvantagens, e eu nunca iria prefixar-los desta forma mesmo. Mas eu quero todos os argumentos que posso obter para convencer meus colegas de trabalho a não fazerem isso também.
1
Sim, tbl é inútil, mas eu ainda amo usá-lo. Deve ser o meu TOC entrando. Agora saia do meu gramado.
SQLRockstar
1
@ Josien também, seus colegas de trabalho devem apresentar argumentos para tornar um esquema de nomeação mais complicado. Faça com que eles expliquem por que dbo.sp_Author_Renameé melhor que dbo.Author_Rename. Não consigo pensar em nada que faça sentido.
Aaron Bertrand

Respostas:

31

Isso é bastante fácil de se testar. Vamos criar dois procedimentos muito simples:

CREATE PROCEDURE dbo.sp_mystuff
AS
  SELECT 'x';
GO
CREATE PROCEDURE dbo.mystuff
AS
  SELECT 'x';
GO

Agora vamos criar um wrapper que os execute várias vezes, com e sem o prefixo do esquema:

CREATE PROCEDURE dbo.wrapper_sp1
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC sp_mystuff;
      SET @i += 1;
    END
END
GO
CREATE PROCEDURE dbo.wrapper_1
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC mystuff;
      SET @i += 1;
    END
END
GO
CREATE PROCEDURE dbo.wrapper_sp2
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC dbo.sp_mystuff;
      SET @i += 1;
    END
END
GO
CREATE PROCEDURE dbo.wrapper_2
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @i INT = 1;
    WHILE @i <= 1000
    BEGIN
      EXEC dbo.mystuff;
      SET @i += 1;
    END
END
GO

Resultados:

insira a descrição da imagem aqui

Conclusões:

  • usar o prefixo sp_ é mais lento
  • deixar de fora o prefixo do esquema é mais lento

A questão mais importante: por que você deseja usar o prefixo sp_? O que seus colegas esperam ganhar com isso? Isso não deve significar que você precisa provar que isso é pior, mas justificar a adição do mesmo prefixo de três letras a cada procedimento armazenado no sistema. Não vejo o benefício.

Também realizei alguns testes bastante extensos desse padrão na seguinte postagem no blog:

http://www.sqlperformance.com/2012/10/t-sql-queries/sp_prefix

Aaron Bertrand
fonte
Observe que esses resultados estão no SQL Server 2012. Mas você pode executar os mesmos testes em seu ambiente.
Aaron Bertrand
1
"O que seus colegas esperam ganhar com isso" ver também Notação Húngara . Basicamente, é uma coisa dos anos 90 na maior parte. Além disso, no meu trabalho anterior, o padrão era prefixar todos os procedimentos armazenados sp_para que eles pudessem ser diferenciados de outras coisas e sem conflitos de nomes ... Eu não tinha ideia de que esse problema de desempenho existia.
Earlz
Ótimo exemplo, obrigado Aaron. Ainda estou testando no 2008 R2 (e provavelmente testando da maneira errada, porque 'dbo.wrapper_sp1' e 'dbo.wrapper_sp2' parecem significativamente mais rápidos que os outros dois no momento).
12

Recomendamos que você não crie procedimentos armazenados usando sp_ como prefixo. O SQL Server usa o prefixo sp_ para designar procedimentos armazenados do sistema. O nome escolhido pode entrar em conflito com algum procedimento futuro do sistema. [...]

Nada é mencionado lá sobre problemas de desempenho causados ​​pelo uso do prefixo sp_. Gostaria de saber se esse ainda é o caso ou se eles o corrigiram após o SQL Server 2000.

Como mostra o comentário simples de Martin Smith - sim, se você tiver um procedimento armazenado com um sp_prefixo - o executor de consultas do SQL Server sempre fará check-in no masterbanco de dados primeiro para ver se existe um procedimento armazenado (marcado como um procedimento armazenado no sistema) com esse nome.

E, se existir, o procedimento armazenado no sistema do masterbanco de dados sempre prevalecerá e será executado em vez do seu.

Então sim - ele ainda permanece: não use o sp_prefixo.

marc_s
fonte
5
Simples de testar. CREATE PROC dbo.sp_helptext AS SELECT 1então tente #EXEC dbo.sp_helptext
Martin Smith
Obrigado pela sua resposta, adição muito útil sobre a prevalência de mastersp's.
2

Um teste melhor é escrever uma consulta que exija otimização total, pois provavelmente é um reflexo melhor do que o processo que você está escrevendo está fazendo. Embrulhei a consulta a seguir em um SP e repeti seu teste e obtive os mesmos resultados.

select * from Person.BusinessEntity b
inner join Person.BusinessEntityAddress ba on b.BusinessEntityID = ba.BusinessEntityID
inner join Person.Address a on ba.AddressID = a.AddressID

Recebi o mesmo número de eventos de falta e acerto de cache nos dois casos e, nos dois casos, o plano foi adicionado ao cache. Também executei os dois procs várias vezes e não houve diferença consistente no tempo da CPU ou no tempo decorrido relatado pelo dm_exec_query_stats.

A outra preocupação é que, como "sp_" procs podem ser executados a partir do master, você pode obter uma cópia do proc executada no master em vez do DB em que está trabalhando, mas um teste rápido mostrará que não é esse o caso. No entanto, se o proc for retirado do banco de dados em que você está trabalhando e uma cópia existir no master, ela será executada, o que pode ser um problema se for uma versão antiga. Se isso é uma preocupação, eu não usaria "sp_" para nomear o proc.

cfradenburg
fonte
Achados interessantes, obrigado! Usarei seu exemplo em combinação com o exemplo de Aaron para executar mais alguns testes.
1

Acredito que o problema tenha que ser resolvido quando você não especificar o nome completo do objeto. Portanto, "EXEC sp_something" verificará o mestre primeiro, mas "EXEC dbname.dbo.sp_something" nunca irá dominar primeiro.

A lição, se bem me lembro, é sempre usar o nome completo.

SQLRockstar
fonte
5
Não pense que isso faz alguma diferença. EXEC MyDB.dbo.sp_helptext 'sp_helptext'ainda usa o mastermesmo, se houver um no banco de dados do usuário. AFAIK verifica os dois locais e usará o local masterse existir e estiver marcado como um objeto do sistema.
Martin Smith
1
@MartinSmith em 2012 Eu não conseguia coagir a versão mestre a ser executada (embora meus testes mostrem que algo está acontecendo), a menos que eu solte a cópia local (nesse caso, MyDB.dbo.sp_fooainda executei a versão mestre). Não tenho o R2 2008/2008 no momento para confirmar onde esse comportamento foi alterado.
Aaron Bertrand
@AaronBertrand - Ah, interessante eu fiz meu teste no 2008 R2.
Martin Smith
Observe também que, se um procedimento local não for encontrado e um no mestre, o último será executado e não precisará ser marcado como um objeto do sistema para que isso ocorra. E, em 2012, pelo menos, se a cópia principal é ou não marcada como um objeto do sistema, não altera o comportamento - com ou sem prefixo db / schema local, a cópia local é sempre executada, a menos que não exista.
Aaron Bertrand
1
Ops, eu deveria ter esclarecido que meu comentário foi direcionado para a resposta sugerida. O comentário do SQLRockstar "EXEC dbname.dbo.sp_something nunca irá dominar primeiro." está incorreto.
Greenstone Walker