¿Sigue siendo incorrecto iniciar el nombre de un procedimiento almacenado por el usuario con sp_?

33

Uno de mis compañeros de trabajo nombró un procedimiento almacenado en nuestra base de datos SQL Server 2008 R2 sp_something. Cuando vi esto, inmediatamente pensé: "¡Eso está MAL!" y comencé a buscar en mis marcadores este artículo en línea que explica por qué está mal, para que yo pueda darle una explicación a mi compañero de trabajo.

En el artículo (por Brian Moran ) se explica que al dar al procedimiento almacenado un prefijo sp_, SQL Server busca en la base de datos maestra un plan compilado. Debido a que el sp_sprocno reside allí, SQL Server volverá a compilar el procedimiento (y necesita un bloqueo de compilación exclusivo para eso, causando problemas de rendimiento).

El siguiente ejemplo se da en el artículo para mostrar la diferencia entre dos procedimientos:

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

Ejecuta esto, luego abre Profiler (agrega los procedimientos almacenados -> SP:CacheMissevento) y ejecuta los procedimientos almacenados nuevamente. Se supone que ve una diferencia entre los dos procedimientos almacenados: el sp_Select1procedimiento almacenado generará un SP:CacheMissevento más que el Select1procedimiento almacenado (el artículo hace referencia a SQL Server 7.0 y SQL Server 2000 ).

Cuando ejecuto el ejemplo en mi entorno SQL Server 2008 R2, obtengo la misma cantidad de SP:CacheMisseventos para ambos procedimientos (tanto en tempdb como en otra base de datos de prueba).

Entonces me pregunto:

  • ¿Puedo haber hecho algo mal en mi ejecución del ejemplo?
  • ¿ sproc sp_somethingSigue siendo válido el adagio " no nombrar a un usuario " en las versiones más recientes de SQL Server?
  • Si es así, ¿hay algún buen ejemplo que muestre su validez en SQL Server 2008 R2?

Muchas gracias por tus pensamientos sobre esto!

EDITAR

Encontré la creación de procedimientos almacenados (motor de base de datos) en msdn para SQL Server 2008 R2, que responde a mi segunda pregunta:

Recomendamos que no cree ningún procedimiento almacenado utilizando sp_ como prefijo. SQL Server usa el prefijo sp_ para designar procedimientos almacenados del sistema. El nombre que elija puede entrar en conflicto con algún procedimiento futuro del sistema. [...]

Sin embargo, no se menciona nada sobre los problemas de rendimiento causados ​​por el uso del sp_prefijo. Me encantaría saber si ese es el caso o si lo arreglaron después de SQL Server 2000.

marc_s
fuente
3
Miré esto antes y encontré una diferencia de rendimiento insignificante que atribuí a una sobrecarga levemente mayor de resolver las sp_versiones (es necesario verificar en las bases de datos maestra y de usuario porque prioriza los procesos del sistema en master-> procesos en la base de datos de usuario -> no sistema procs in master)
Martin Smith
44
¿Qué beneficio ve para prefijar un procedimiento almacenado sp_? Esto es tan útil como prefijar una tabla con tbl. ¿Por qué primero hacer que el sistema busque maestro (incluso si es insignificante o no tiene una diferencia de rendimiento) para permitirle usar esta convención de nomenclatura sin sentido?
Aaron Bertrand
1
@AaronBertrand: para ser honesto, no veo ningún beneficio en absoluto en el prefijo sprocs con sp_, sólo desventajas, y yo nunca les gustaría prefijo de esta manera a mí mismo. Pero quiero todos los argumentos que pueda obtener para convencer a mis compañeros de trabajo de que tampoco lo hagan.
1
Sí, tbl es inútil, pero todavía me encanta usarlo. Debe ser mi TOC pateando. Ahora sal de mi césped.
SQLRockstar
1
@Josien también, sus compañeros de trabajo deberían venir con argumentos para hacer un esquema de nombres más complicado. Haz que expliquen por qué dbo.sp_Author_Renamees mejor que dbo.Author_Rename. No puedo pensar en una sola cosa que tenga sentido.
Aaron Bertrand

Respuestas:

31

Esto es bastante fácil de probarse a sí mismo. Vamos a crear dos procedimientos muy simples:

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

Ahora construyamos un contenedor que los ejecute varias veces, con y sin el prefijo de 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:

ingrese la descripción de la imagen aquí

Conclusiones:

  • el uso del prefijo sp_ es más lento
  • omitir el prefijo de esquema es más lento

La pregunta más importante: ¿por qué se quiere utilizar el prefijo sp_? Lo que a sus compañeros de trabajo esperan obtener de este modo? Esto no debería ser acerca de usted tener que probar que esto es peor, debe ser por ellos justificar la adición de la misma prefijo de tres letras para cada procedimiento almacenado única en el sistema. No veo el beneficio.

También he realizado algunos bastante extensas pruebas de este patrón en la siguiente entrada en el blog:

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

Aaron Bertrand
fuente
Tenga en cuenta que estos resultados están en SQL Server 2012. Pero puede realizar las mismas pruebas en su entorno.
Aaron Bertrand
1
"¿Qué esperan obtener sus compañeros de trabajo al hacerlo?", Véase también la notación húngara . Básicamente, es algo de los 90 en su mayor parte. Además, en mi trabajo anterior, el estándar era prefijar cada procedimiento almacenado sp_para que pudieran diferenciarse de otras cosas y no tener conflictos de nombres ... No tenía idea de que este problema de rendimiento existiera.
Earlz
Gran ejemplo, gracias Aaron. Todavía lo estoy probando en 2008 R2 (y probablemente lo estoy probando de manera incorrecta, porque 'dbo.wrapper_sp1' y 'dbo.wrapper_sp2' parecen significativamente más rápidos que los otros dos en este momento).
12

Recomendamos que no cree ningún procedimiento almacenado utilizando sp_ como prefijo. SQL Server usa el prefijo sp_ para designar procedimientos almacenados del sistema. El nombre que elija puede entrar en conflicto con algún procedimiento futuro del sistema. [...]

Sin embargo, no se menciona nada sobre los problemas de rendimiento causados ​​por el uso del prefijo sp_. Me encantaría saber si ese es el caso o si lo arreglaron después de SQL Server 2000.

Como muestra el simple comentario de Martin Smith, sí, si tiene un procedimiento almacenado con un sp_prefijo, el ejecutor de consultas de SQL Server siempre verificará masterprimero la base de datos para ver si existe un procedimiento almacenado (marcado como un procedimiento almacenado del sistema) con ese nombre.

Y si existe, ese procedimiento almacenado del sistema de la masterbase de datos siempre prevalece y se ejecutará en lugar del suyo.

Entonces sí, sigue en pie: no use el sp_prefijo.

marc_s
fuente
55
Simple de probar. CREATE PROC dbo.sp_helptext AS SELECT 1luego intenteEXEC dbo.sp_helptext
Martin Smith
Gracias por su respuesta, adición muy útil sobre la prevalencia de mastersp.
2

Una mejor prueba es escribir una consulta que requiera una optimización completa, ya que probablemente sea un mejor reflejo de lo que está haciendo el proceso que está escribiendo. Envuelto la siguiente consulta en un SP y repetí su prueba y obtuve los mismos 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

Obtuve la misma cantidad de eventos de aciertos y errores de caché en ambos casos y en ambos casos el plan se agregó al caché. También ejecuté ambos procesos varias veces y no hubo diferencias consistentes en el tiempo de CPU o el tiempo transcurrido informado por dm_exec_query_stats.

La otra preocupación es que, dado que los procesos "sp_" se pueden ejecutar desde el maestro, puede obtener una copia del proceso que se ejecutó en el maestro en lugar del DB en el que está trabajando, pero una prueba rápida mostrará que ese no es el caso. Sin embargo, si el proceso se elimina del DB en el que está trabajando y existe una copia en el maestro, se ejecutará, lo que podría ser un problema si se trata de una versión anterior. Si esto es un problema, no usaría "sp_" para nombrar el proceso

Cfradenburg
fuente
Hallazgos interesantes, gracias! Usaré su ejemplo en combinación con el ejemplo de Aaron para ejecutar algunas pruebas más.
1

Creo que el problema tiene que ver cuando no especifica el nombre completo del objeto. Por lo tanto, "EXEC sp_something" verificará el maestro primero, pero "EXEC dbname.dbo.sp_something" nunca irá al maestro primero.

La lección, si mal no recuerdo, es usar siempre el nombre completo.

SQLRockstar
fuente
55
No pienses que eso hace la diferencia. EXEC MyDB.dbo.sp_helptext 'sp_helptext'todavía usa el de masterincluso si hay uno en la base de datos del usuario. AFAIK verifica ambas ubicaciones y usará la de mastersi existe y está marcada como un objeto del sistema.
Martin Smith
1
@MartinSmith en 2012 no pude forzar la ejecución de la versión maestra (aunque mis pruebas allí mostraron que algo está sucediendo), a menos que haya descartado la copia local (en cuyo caso MyDB.dbo.sp_fooaún ejecuté la versión maestra). No tengo 2008/2008 R2 en este momento para confirmar dónde cambió este comportamiento.
Aaron Bertrand
@AaronBertrand - Ah, interesante, hice mi prueba en 2008 R2.
Martin Smith
También tenga en cuenta que si no se encuentra un procedimiento local y se encuentra uno en el maestro, este último se ejecutará y no es necesario marcarlo como un objeto del sistema para que esto suceda. Y al menos en 2012, si la copia maestra está marcada o no como un objeto del sistema, no cambia el comportamiento: con o sin el prefijo local db / schema, la copia local siempre se ejecuta a menos que no exista.
Aaron Bertrand
1
Vaya, debería haber aclarado que mi comentario estaba dirigido a la respuesta sugerida. Comentario de SQLRockstar "EXEC dbname.dbo.sp_something nunca irá al maestro primero". Es incorrecto.
Greenstone Walker