In de SQL Server-wereld zijn er twee soorten mensen:zij die graag al hun objecten vooraf laten gaan, en zij die dat niet doen. De eerste groep is verder onderverdeeld in twee categorieën:degenen die opgeslagen procedures voorafgaan met sp_
, en degenen die andere voorvoegsels kiezen (zoals usp_
of proc_
). Een al lang bestaande aanbeveling is om de sp_
. te vermijden prefix, zowel om prestatieredenen als om dubbelzinnigheid of botsingen te voorkomen als u een naam kiest die al in de systeemcatalogus bestaat. Botsingen zijn zeker nog steeds een probleem, maar ervan uitgaande dat u uw objectnaam hebt doorgelicht, is het dan nog steeds een prestatieprobleem?
TL;DR-versie:JA.
Het voorvoegsel sp_ is nog steeds een nee-nee. Maar in dit bericht zal ik uitleggen waarom, hoe SQL Server 2012 u zou kunnen doen geloven dat dit waarschuwende advies niet langer van toepassing is, en enkele andere mogelijke bijwerkingen van het kiezen van deze naamgevingsconventie.
Wat is het probleem met sp_?
De sp_
voorvoegsel betekent niet wat je denkt dat het doet:de meeste mensen denken sp
staat voor "opgeslagen procedure" terwijl het in feite "speciaal" betekent. Opgeslagen procedures (evenals tabellen en views) opgeslagen in master met een sp_
prefix zijn toegankelijk vanuit elke database zonder een juiste verwijzing (ervan uitgaande dat er geen lokale versie bestaat). Als de procedure is gemarkeerd als een systeemobject (met behulp van sp_MS_marksystemobject
(een ongedocumenteerde en niet-ondersteunde systeemprocedure die is_ms_shipped
instelt naar 1), dan wordt de procedure in master uitgevoerd in de context van de aanroepende database. Laten we een eenvoudig voorbeeld bekijken:
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
Resultaten:
(0 row(s) affected) sp_test foo (1 row(s) affected)
Het prestatieprobleem komt van het feit dat master kan worden gecontroleerd op een equivalente opgeslagen procedure, afhankelijk van of er een lokale versie van de procedure is en of er in feite een equivalent object in master is. Dit kan leiden tot extra metadata-overhead en een extra SP:CacheMiss
evenement. De vraag is of deze overhead voelbaar is.
Laten we dus een heel eenvoudige procedure in een testdatabase bekijken:
CREATE DATABASE sp_prefix; GO USE sp_prefix; GO CREATE PROCEDURE dbo.sp_something AS BEGIN SELECT 'sp_prefix', DB_NAME(); END GO
En gelijkwaardige procedures in 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:feit of fictie?
Als we een snelle test uitvoeren vanuit onze testdatabase, zien we dat het uitvoeren van deze opgeslagen procedures nooit de versies van de master zal oproepen, ongeacht of we de procedure correct kwalificeren voor de database of het schema (een veelvoorkomende misvatting) of dat we de masterversie als systeemobject:
USE sp_prefix; GO EXEC sp_prefix.dbo.sp_something; GO EXEC dbo.sp_something; GO EXEC sp_something;
Resultaten:
sp_prefix sp_prefix sp_prefix sp_prefix sp_prefix sp_prefix
Laten we ook een Quick Trace uitvoerenSP:CacheMiss
. zijn evenementen:
We zien CacheMiss
gebeurtenissen voor de ad-hocbatch die de opgeslagen procedure aanroept (aangezien SQL Server over het algemeen niet de moeite neemt om een batch in de cache te plaatsen die voornamelijk uit procedureaanroepen bestaat), maar niet voor de opgeslagen procedure zelf. Zowel met als zonder de sp_something
procedure die in master bestaat (en wanneer deze bestaat, zowel met als zonder dat deze is gemarkeerd als een systeemobject), de aanroepen van sp_something
in de gebruikersdatabase nooit "per ongeluk" de procedure in master aanroepen, en nooit een CacheMiss
genereren gebeurtenissen voor de procedure.
Dit was op SQL Server 2012. Ik herhaalde dezelfde tests hierboven op SQL Server 2008 R2 en vond iets andere resultaten:
Dus op SQL Server 2008 R2 zien we een extra CacheMiss
gebeurtenis die niet voorkomt in SQL Server 2012. Dit gebeurt in alle scenario's (geen equivalent objectmaster, een object in master gemarkeerd als systeemobject en een object in master dat niet is gemarkeerd als systeemobject). Ik was meteen benieuwd of deze extra gebeurtenis een merkbare impact zou hebben op de prestaties.
Prestatieprobleem:feit of fictie?
Ik heb een extra procedure gemaakt zonder de sp_
prefix om onbewerkte prestaties te vergelijken, CacheMiss
terzijde:
USE sp_prefix; GO CREATE PROCEDURE dbo.proc_something AS BEGIN SELECT 'sp_prefix', DB_NAME(); END GO
Dus het enige verschil tussen sp_something
en proc_something
. Ik heb vervolgens wrapper-procedures gemaakt om ze elk 1000 keer uit te voeren, met behulp van EXEC sp_prefix.dbo.<procname>
, EXEC dbo.<procname>
en EXEC <procname>
syntaxis, met equivalente opgeslagen procedures die leven in master en gemarkeerd als een systeemobject, leven in master maar niet gemarkeerd als een systeemobject, en helemaal niet leven in 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
Door de runtime-duur van elke wrapper-procedure te meten met SQL Sentry Plan Explorer, blijkt uit de resultaten dat het gebruik van de sp_
prefix heeft in bijna alle gevallen (en zeker gemiddeld) een significante impact op de gemiddelde duur: