Database
 sql >> Datenbank >  >> RDS >> Database

Ist das Präfix sp_ immer noch ein No-No?

In der SQL Server-Welt gibt es zwei Arten von Menschen:diejenigen, die es mögen, wenn alle ihre Objekte mit Präfixen versehen werden, und diejenigen, die dies nicht tun. Die erstere Gruppe wird weiter in zwei Kategorien unterteilt:diejenigen, die gespeicherten Prozeduren sp_ voranstellen , und diejenigen, die andere Präfixe wählen (wie usp_ oder proc_ ). Eine langjährige Empfehlung lautet, sp_ zu vermeiden Präfix, sowohl aus Leistungsgründen als auch um Mehrdeutigkeiten oder Kollisionen zu vermeiden, wenn Sie zufällig einen Namen auswählen, der bereits im Systemkatalog vorhanden ist. Kollisionen sind sicherlich immer noch ein Problem, aber vorausgesetzt, Sie haben Ihren Objektnamen überprüft, ist es immer noch ein Leistungsproblem?

TL;DR-Version:JA.

Das Präfix sp_ ist immer noch tabu. Aber in diesem Beitrag werde ich erklären, warum, wie SQL Server 2012 Sie glauben machen könnte, dass dieser Warnhinweis nicht mehr gilt, und einige andere mögliche Nebenwirkungen der Wahl dieser Namenskonvention.

Was ist das Problem mit sp_?

Der sp_ Präfix bedeutet nicht, was Sie denken:Die meisten Leute denken an sp steht für "gespeicherte Prozedur", obwohl es eigentlich "speziell" bedeutet. Gespeicherte Prozeduren (sowie Tabellen und Ansichten), die im Master mit einem sp_ gespeichert sind Präfix sind von jeder Datenbank ohne richtige Referenz zugänglich (vorausgesetzt, es existiert keine lokale Version). Wenn die Prozedur als Systemobjekt markiert ist (mithilfe von sp_MS_marksystemobject (eine undokumentierte und nicht unterstützte Systemprozedur, die is_ms_shipped setzt auf 1), dann wird die Prozedur im Master im Kontext der aufrufenden Datenbank ausgeführt. Schauen wir uns ein einfaches Beispiel an:

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
zurück

Ergebnisse:

(0 row(s) affected)

sp_test    foo

(1 row(s) affected)

Das Leistungsproblem ergibt sich aus der Tatsache, dass der Master möglicherweise auf eine äquivalente gespeicherte Prozedur überprüft wird, je nachdem, ob eine lokale Version der Prozedur vorhanden ist und ob tatsächlich ein äquivalentes Objekt im Master vorhanden ist. Dies kann zu zusätzlichem Metadaten-Overhead sowie zu einem zusätzlichen SP:CacheMiss führen Veranstaltung. Die Frage ist, ob dieser Overhead greifbar ist.

Betrachten wir also eine sehr einfache Prozedur in einer Testdatenbank:

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

Und gleichwertige Verfahren im 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:Tatsache oder Fiktion?

Wenn wir einen Schnelltest von unserer Testdatenbank aus ausführen, sehen wir, dass die Ausführung dieser gespeicherten Prozeduren niemals die Versionen von master tatsächlich aufrufen wird, unabhängig davon, ob wir die Prozedur ordnungsgemäß Datenbank- oder Schema-qualifizieren (ein häufiges Missverständnis) oder ob wir die markieren Masterversion als Systemobjekt:

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

Ergebnisse:

sp_prefix    sp_prefix
sp_prefix    sp_prefix
sp_prefix    sp_prefix

Lassen Sie uns auch einen Quick Trace® ausführen Verwenden von SQL Sentry, um zu beobachten, ob es SP:CacheMiss gibt Veranstaltungen:

Wir sehen CacheMiss Ereignisse für den Ad-hoc-Stapel, der die gespeicherte Prozedur aufruft (da SQL Server sich im Allgemeinen nicht darum kümmert, einen Stapel zwischenzuspeichern, der hauptsächlich aus Prozeduraufrufen besteht), aber nicht für die gespeicherte Prozedur selbst. Sowohl mit als auch ohne sp_something Prozedur, die im Master vorhanden ist (und wenn sie existiert, sowohl mit als auch ohne Markierung als Systemobjekt), die Aufrufe von sp_something Rufen Sie in der Benutzerdatenbank niemals "versehentlich" die Prozedur in master auf und erzeugen Sie niemals CacheMiss Ereignisse für das Verfahren.

Dies war auf SQL Server 2012. Ich habe die gleichen Tests oben auf SQL Server 2008 R2 wiederholt und etwas andere Ergebnisse gefunden:

Auf SQL Server 2008 R2 sehen wir also eine zusätzliche CacheMiss Ereignis, das in SQL Server 2012 nicht auftritt. Dies tritt in allen Szenarios auf (kein äquivalenter Objektmaster, ein Objekt im Master, das als Systemobjekt markiert ist, und ein Objekt im Master, das nicht als Systemobjekt markiert ist). Ich war sofort gespannt, ob dieses zusätzliche Ereignis spürbare Auswirkungen auf die Leistung haben würde.

Leistungsproblem:Tatsache oder Fiktion?

Ich habe eine zusätzliche Prozedur ohne den sp_ gemacht Präfix zum Vergleich der Rohleistung, CacheMiss beiseite:

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

Der einzige Unterschied zwischen sp_something und proc_something . Ich habe dann Wrapper-Prozeduren erstellt, um sie jeweils 1000 Mal auszuführen, indem ich EXEC sp_prefix.dbo.<procname> verwendet habe , EXEC dbo.<procname> und EXEC <procname> Syntax, wobei äquivalente gespeicherte Prozeduren im Master leben und als Systemobjekt markiert sind, im Master leben, aber nicht als Systemobjekt markiert sind und überhaupt nicht im Master leben.

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

Die Messung der Laufzeitdauer jeder Wrapper-Prozedur mit dem SQL Sentry Plan Explorer zeigt, dass die Verwendung von sp_ Präfix hat in fast allen Fällen (und sicherlich im Durchschnitt) einen erheblichen Einfluss auf die durchschnittliche Dauer: