Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Apakah awalan sp_ masih tidak-tidak?

Di dunia SQL Server, ada dua tipe orang:mereka yang suka semua objeknya diberi awalan, dan mereka yang tidak. Grup sebelumnya dibagi lagi menjadi dua kategori:mereka yang mengawali prosedur tersimpan dengan sp_ , dan mereka yang memilih awalan lain (seperti usp_ atau proc_ ). Rekomendasi lama adalah untuk menghindari sp_ awalan, baik untuk alasan kinerja, dan untuk menghindari ambiguitas atau tabrakan jika Anda memilih nama yang sudah ada di katalog sistem. Tabrakan tentu saja masih menjadi masalah, tetapi dengan asumsi Anda telah memeriksa nama objek Anda, apakah itu masih menjadi masalah kinerja?

Versi TL;DR:YA.

Awalan sp_ tetap tidak boleh. Namun dalam posting ini saya akan menjelaskan mengapa, bagaimana SQL Server 2012 dapat membuat Anda percaya bahwa saran peringatan ini tidak lagi berlaku, dan beberapa efek samping potensial lainnya dari memilih konvensi penamaan ini.

Apa masalahnya dengan sp_?

sp_ awalan tidak berarti apa yang Anda pikirkan:kebanyakan orang berpikir sp singkatan dari "prosedur tersimpan" padahal sebenarnya itu berarti "khusus." Prosedur tersimpan (serta tabel dan tampilan) disimpan di master dengan sp_ awalan dapat diakses dari database mana pun tanpa referensi yang tepat (dengan asumsi versi lokal tidak ada). Jika prosedur ditandai sebagai objek sistem (menggunakan sp_MS_marksystemobject (prosedur sistem tidak berdokumen dan tidak didukung yang menetapkan is_ms_shipped ke 1), maka prosedur di master akan dijalankan dalam konteks database pemanggil. Mari kita lihat contoh sederhana:

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

Hasil:

(0 row(s) affected)

sp_test    foo

(1 row(s) affected)

Masalah kinerja berasal dari fakta bahwa master mungkin diperiksa untuk prosedur tersimpan yang setara, tergantung pada apakah ada versi lokal dari prosedur tersebut, dan apakah sebenarnya ada objek yang setara di master. Ini dapat menyebabkan overhead metadata tambahan serta SP:CacheMiss tambahan peristiwa. Pertanyaannya adalah apakah overhead ini nyata.

Jadi mari kita pertimbangkan prosedur yang sangat sederhana dalam database pengujian:

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

Dan prosedur yang setara di 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 :Fakta atau Fiksi?

Jika kita menjalankan tes cepat dari database pengujian kita, kita melihat bahwa mengeksekusi prosedur tersimpan ini tidak akan pernah benar-benar memanggil versi dari master, terlepas dari apakah kita benar database atau skema-mengkualifikasi prosedur (kesalahpahaman umum) atau jika kita menandai versi master sebagai objek sistem:

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

Hasil:

sp_prefix    sp_prefix
sp_prefix    sp_prefix
sp_prefix    sp_prefix

Mari kita juga menjalankan Jejak Cepat® menggunakan SQL Sentry untuk mengamati apakah ada SP:CacheMiss acara:

Kami melihat CacheMiss kejadian untuk kumpulan ad hoc yang memanggil prosedur tersimpan (karena SQL Server umumnya tidak akan mengganggu cache kumpulan yang terutama terdiri dari panggilan prosedur), tetapi tidak untuk prosedur tersimpan itu sendiri. Baik dengan dan tanpa sp_something prosedur yang ada di master (dan ketika ada, baik dengan dan tanpa ditandai sebagai objek sistem), panggilan ke sp_something di database pengguna jangan pernah "secara tidak sengaja" memanggil prosedur di master, dan jangan pernah membuat CacheMiss peristiwa untuk prosedur.

Ini pada SQL Server 2012. Saya mengulangi tes yang sama di atas pada SQL Server 2008 R2, dan menemukan hasil yang sedikit berbeda:

Jadi pada SQL Server 2008 R2 kita melihat tambahan CacheMiss peristiwa yang tidak terjadi di SQL Server 2012. Ini terjadi di semua skenario (tidak ada master objek yang setara, objek di master ditandai sebagai objek sistem, dan objek di master tidak ditandai sebagai objek sistem). Saya langsung penasaran apakah acara tambahan ini akan berdampak nyata pada kinerja.

Masalah Kinerja:Fakta atau Fiksi?

Saya membuat prosedur tambahan tanpa sp_ awalan untuk membandingkan kinerja mentah, CacheMiss samping:

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

Jadi satu-satunya perbedaan antara sp_something dan proc_something . Saya kemudian membuat prosedur pembungkus untuk mengeksekusinya masing-masing 1000 kali, menggunakan EXEC sp_prefix.dbo.<procname> , EXEC dbo.<procname> dan EXEC <procname> sintaks, dengan prosedur tersimpan setara yang hidup di master dan ditandai sebagai objek sistem, tinggal di master tetapi tidak ditandai sebagai objek sistem, dan tidak hidup di master sama sekali.

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

Mengukur durasi runtime setiap prosedur wrapper dengan SQL Sentry Plan Explorer, hasilnya menunjukkan bahwa menggunakan sp_ awalan memiliki dampak signifikan pada durasi rata-rata di hampir semua kasus (dan tentu saja rata-rata):