Database
 sql >> Base de données >  >> RDS >> Database

Le préfixe sp_ est-il toujours un non-non ?

Dans le monde SQL Server, il existe deux types de personnes :ceux qui aiment que tous leurs objets soient préfixés et ceux qui ne le font pas. Le premier groupe est divisé en deux catégories :ceux qui préfixent les procédures stockées avec sp_ , et ceux qui choisissent d'autres préfixes (tels que usp_ ou proc_ ). Une recommandation de longue date a été d'éviter le sp_ préfixe, à la fois pour des raisons de performances et pour éviter toute ambiguïté ou collision si vous choisissez un nom qui existe déjà dans le catalogue système. Les collisions sont certainement toujours un problème, mais en supposant que vous avez vérifié le nom de votre objet, est-ce toujours un problème de performances ?

Version TL DR :OUI.

Le préfixe sp_ est toujours un non-non. Mais dans cet article, j'expliquerai pourquoi, comment SQL Server 2012 pourrait vous amener à croire que cette mise en garde ne s'applique plus, et quelques autres effets secondaires potentiels du choix de cette convention de dénomination.

Quel est le problème avec sp_ ?

Le sp_ préfixe ne veut pas dire ce que vous pensez qu'il signifie :la plupart des gens pensent sp signifie "procédure stockée" alors qu'en fait cela signifie "spécial". Procédures stockées (ainsi que tables et vues) stockées dans master avec un sp_ préfixe sont accessibles à partir de n'importe quelle base de données sans référence appropriée (en supposant qu'une version locale n'existe pas). Si la procédure est marquée comme objet système (à l'aide de sp_MS_marksystemobject (une procédure système non documentée et non prise en charge qui définit is_ms_shipped à 1), alors la procédure dans master s'exécutera dans le contexte de la base de données appelante. Prenons un exemple simple :

CREATE DATABASE sp_test;
GO
USE sp_test;
GO
CREATE TABLE dbo.foo(id INT);
GO
USE master;
GO
CREATE PROCEDURE dbo.sp_checktable
AS
  SELECT DB_NAME(), name 
    FROM sys.tables WHERE name = N'foo';
GO
USE sp_test;
GO
EXEC dbo.sp_checktable; -- runs but returns 0 results
GO
EXEC master..sp_MS_marksystemobject N'dbo.sp_checktable';
GO
EXEC dbo.sp_checktable; -- runs and returns results
GO

Résultats :

(0 row(s) affected)

sp_test    foo

(1 row(s) affected)

Le problème de performances vient du fait que master peut être vérifié pour une procédure stockée équivalente, selon s'il existe une version locale de la procédure et s'il existe en fait un objet équivalent dans master. Cela peut entraîner une surcharge de métadonnées supplémentaire ainsi qu'un SP:CacheMiss supplémentaire un événement. La question est de savoir si ces frais généraux sont tangibles.

Considérons donc une procédure très simple dans une base de test :

CREATE DATABASE sp_prefix;
GO
USE sp_prefix;
GO
CREATE PROCEDURE dbo.sp_something
AS
BEGIN
  SELECT 'sp_prefix', DB_NAME();
END
GO

Et procédures équivalentes en master :

USE master;
GO
CREATE PROCEDURE dbo.sp_something
AS
BEGIN
  SELECT 'master', DB_NAME();
END
GO
EXEC sp_MS_marksystemobject N'sp_something';

CacheMiss :réalité ou fiction ?

Si nous exécutons un test rapide à partir de notre base de données de test, nous constatons que l'exécution de ces procédures stockées n'invoquera jamais réellement les versions de master, que nous qualifions correctement la procédure de base de données ou de schéma (une idée fausse courante) ou si nous marquons le version principale en tant qu'objet système :

USE sp_prefix;
GO
EXEC sp_prefix.dbo.sp_something;
GO
EXEC dbo.sp_something;
GO
EXEC sp_something;

Résultats :

sp_prefix    sp_prefix
sp_prefix    sp_prefix
sp_prefix    sp_prefix

Exécutons également un Quick Trace® en utilisant SQL Sentry pour observer s'il y a des SP:CacheMiss événements :

Nous voyons CacheMiss événements pour le lot ad hoc qui appelle la procédure stockée (puisque SQL Server ne prend généralement pas la peine de mettre en cache un lot composé principalement d'appels de procédure), mais pas pour la procédure stockée elle-même. Avec et sans le sp_something procédure existante dans master (et lorsqu'elle existe, avec et sans qu'elle soit marquée comme objet système), les appels à sp_something dans la base de données utilisateur, n'appelez jamais "accidentellement" la procédure dans master et ne générez jamais de CacheMiss événements pour la procédure.

C'était sur SQL Server 2012. J'ai répété les mêmes tests ci-dessus sur SQL Server 2008 R2 et j'ai trouvé des résultats légèrement différents :

Ainsi, sur SQL Server 2008 R2, nous voyons un CacheMiss supplémentaire événement qui ne se produit pas dans SQL Server 2012. Cela se produit dans tous les scénarios (pas de maître d'objet équivalent, un objet dans le maître marqué comme objet système et un objet dans le maître non marqué comme objet système). Immédiatement, j'étais curieux de savoir si cet événement supplémentaire aurait un impact notable sur les performances.

Problème de performances :réalité ou fiction ?

J'ai fait une procédure supplémentaire sans le sp_ préfixe pour comparer les performances brutes, CacheMiss à part :

USE sp_prefix;
GO
CREATE PROCEDURE dbo.proc_something
AS
BEGIN
  SELECT 'sp_prefix', DB_NAME();
END
GO

Donc, la seule différence entre sp_something et proc_something . J'ai ensuite créé des procédures wrapper pour les exécuter 1000 fois chacune, en utilisant EXEC sp_prefix.dbo.<procname> , EXEC dbo.<procname> et EXEC <procname> syntaxe, avec des procédures stockées équivalentes vivant dans master et marquées comme objet système, vivant dans master mais pas marquées comme objet système et ne vivant pas du tout dans master.

USE sp_prefix;
GO
CREATE PROCEDURE dbo.wrap_sp_3part
AS
BEGIN
  DECLARE @i INT = 1;
  WHILE @i <= 1000
  BEGIN
    EXEC sp_prefix.dbo.sp_something;
    SET @i += 1;
  END
END
GO
CREATE PROCEDURE dbo.wrap_sp_2part
AS
BEGIN
  DECLARE @i INT = 1;
  WHILE @i <= 1000
  BEGIN
    EXEC dbo.sp_something;
    SET @i += 1;
  END
END
GO
CREATE PROCEDURE dbo.wrap_sp_1part
AS
BEGIN
  DECLARE @i INT = 1;
  WHILE @i <= 1000
  BEGIN
    EXEC sp_something;
    SET @i += 1;
  END
END
GO
-- repeat for proc_something

En mesurant la durée d'exécution de chaque procédure wrapper avec SQL Sentry Plan Explorer, les résultats montrent que l'utilisation de sp_ préfixe a un impact significatif sur la durée moyenne dans presque tous les cas (et certainement en moyenne) :