Все ще неправильно починати ім'я користувальницької процедури, що зберігається, з sp_?


33

Один з моїх колег назвав збережену процедуру в нашій базі даних SQL Server 2008 R2 sp_something. Побачивши це, я одразу подумав: "Це НЕПРАВНО!" і почав шукати мої закладки для цієї інтернет-статті, яка пояснює, чому це неправильно, щоб я міг надати своєму колезі пояснення.

У статті ( Брайан Моран ) пояснюється, що надання збереженій процедурі префікса sp_ змушує SQL Server переглянути основну базу даних для складеного плану. Оскільки там sp_sprocне проживає, SQL Server перекомпілює процедуру (і для цього потрібен ексклюзивний замок компіляції, що спричинить проблеми з продуктивністю).

У статті наведено наступний приклад, щоб показати різницю між двома процедурами:

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

Ви запускаєте це, потім відкриваєте Профілер (додайте Збережені процедури -> SP:CacheMissподія) та запускайте збережені процедури заново. Ви повинні побачити різницю між двома збереженими процедурами: sp_Select1збережена процедура генерує ще одну SP:CacheMissподію, ніж Select1збережена процедура (статті посилаються на SQL Server 7.0 та SQL Server 2000. )

Коли я запускаю приклад у моєму середовищі SQL Server 2008 R2, я отримую однакову кількість SP:CacheMissподій для обох процедур (і в tempdb, і в іншій тестовій базі даних).

Тож мені цікаво:

  • Чи можу я зробити щось не так у виконанні прикладу?
  • Чи sproc sp_somethingадагіум "не називати користувача " все ще дійсний у нових версіях SQL Server?
  • Якщо так, чи є хороший приклад, який показує його дійсність у SQL Server 2008 R2?

Дякую за ваші думки з цього приводу!

EDIT

Я знайшов Створення збережених процедур (Engine Database Engine) у msdn для SQL Server 2008 R2, який відповідає на моє друге питання:

Ми рекомендуємо не створювати жодних збережених процедур, використовуючи sp_ як префікс. SQL Server використовує префікс sp_ для позначення системних збережених процедур. Ім'я, яке ви вибрали, може суперечити деякій майбутній системній процедурі. [...]

Там нічого не згадується про проблеми з продуктивністю, викликані використанням sp_префікса. Я хотів би дізнатися, чи все ще так, чи вони виправили це після SQL Server 2000.


3
Я раніше це переглянув і виявив незначну різницю в продуктивності, яку я знизив до дещо більших витрат на розв'язання sp_версій (потрібно перевірити як у базовій, так і в базі даних користувачів, оскільки це визначає пріоритет системних програм у master-> програмах у користувальницькій БД -> не в системі procs in master)
Мартін Сміт

4
Яку перевагу ви бачите для префіксації збереженої процедури sp_? Це приблизно так само корисно, як і префіксація таблиці tbl. Навіщо спочатку змусити майстра пошуку системи (навіть якщо це незначна різниця в продуктивності або немає), щоб дозволити вам використовувати цю безглузду конвенцію іменування?
Аарон Бертран

1
@AaronBertrand: чесно кажучи, я не бачу ніякої користі взагалі в випереджаючи sprocs з sp_, тільки недоліки, і я ніколи б не префікс їх цей шлях сам. Але я хочу, щоб усі аргументи, які я можу отримати, переконали своїх колег теж не робити цього.

1
Так, tbl марний, але я все одно люблю його використовувати. Повинно бути моїм ОКР, що б'ється. Тепер зійди з моєї газону.
SQLRockstar

1
@Josien також, ваші колеги повинні прийти з аргументами щодо ускладнення схеми іменування. Попросіть їх пояснити, чому dbo.sp_Author_Renameкраще, ніж dbo.Author_Rename. Я не можу придумати жодної речі, яка має сенс.
Аарон Бертран

Відповіді:


31

Це досить легко перевірити на собі. Створимо дві дуже прості процедури:

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

Тепер давайте побудуємо обгортку, яка виконує їх кілька разів, з префіксом схеми та без:

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

Результати:

введіть тут опис зображення

Висновки:

  • використання префікса sp_ повільніше
  • префікс схеми повільніше

Більш важливе питання: чому ви хочете використовувати префікс sp_? Що ваші співробітники очікують отримати від цього? Це не повинно стосуватися того, що вам доведеться доводити, що це гірше, а саме про їх виправдання додавати один і той же трибуквенний префікс до кожної збереженої процедури в системі. Я не бачу вигоди.

Також я провів досить обширне тестування цього зразка в наступній публікації блогу:

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


Зауважте, ці результати є на SQL Server 2012. Але ви можете виконувати ті самі тести у вашому оточенні.
Аарон Бертран

1
"Що ви очікуєте від вашої співпраці від цього", див. Також Угорська нотація . В основному, це здебільшого справа 90-х. Крім того, на моїй минулій роботі стандарт був приєднувати кожну збережену процедуру, sp_щоб їх можна було відрізнити від інших речей і не було конфліктів імен ... Я не мав уявлення, що з цим існує проблема продуктивності.
Граф

Чудовий приклад, дякую Аарону. Я все ще тестую його на 2008 R2 (і, ймовірно, тестую його неправильно, тому що 'dbo.wrapper_sp1' і 'dbo.wrapper_sp2' здаються значно швидшими, ніж інші два зараз).

12

Ми рекомендуємо не створювати жодних збережених процедур, використовуючи sp_ як префікс. SQL Server використовує префікс sp_ для позначення системних збережених процедур. Ім'я, яке ви вибрали, може суперечити деякій майбутній системній процедурі. [...]

Там нічого не згадується про проблеми з продуктивністю, викликані використанням префікса sp_. Я хотів би дізнатися, чи все ж таки це так, чи вони виправили це після SQL Server 2000.

Як показує простий коментар Мартіна Сміта - так, якщо у вас є збережена процедура з sp_префіксом - виконавець запитів SQL Server спочатку завжди перевірятиме в masterбазі даних, щоб побачити, чи існує збережена процедура (позначена як системна збережена процедура) цим ім'ям.

І якщо вона існує, ця системно збережена процедура з masterбази даних завжди переважає і буде виконуватися замість вашої власної.

Так що так - це все ще стоїть: не використовувати в sp_приставку.


5
Простий для тестування. CREATE PROC dbo.sp_helptext AS SELECT 1потім спробуйтеEXEC dbo.sp_helptext
Мартін Сміт

Дякуємо за вашу відповідь, дуже корисне доповнення щодо поширеності masterСП.

2

Кращим тестом є написання запиту, який потребує повної оптимізації, оскільки це, швидше за все, краще відображення того, що робиться процесом, який ти пишеш. Я завернув наступний запит у СП та повторив тест і отримав ті самі результати.

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

Я отримав однакову кількість пропущених кеш-подій і подій в обох випадках, і в обох випадках план був доданий до кешу. Я також запускав обидва програми кілька разів, і не було послідовної різниці в процесі процесора або минулому часу, повідомленому dm_exec_query_stats.

Інша стурбованість полягає в тому, що оскільки «sp_» програми можуть бути виконані від master, ви можете отримати копію протоколу, який був запущений у master замість БД, в якій ви працюєте, але швидкий тест покаже, що це не так. Однак якщо Proc випадає з БД, в якій ви працюєте, і копія існує в master, то вона буде виконана, що може бути проблемою, якщо це стара версія. Якщо це питання, я б не використовував "sp_", щоб назвати прок.


Цікаві знахідки, дякую! Я буду використовувати ваш приклад у поєднанні з прикладом Аарона, щоб провести ще кілька тестів.

1

Я вважаю, що це має бути зроблено, коли ви не вказуєте повністю кваліфіковану назву об'єкта. Так, "EXEC sp_something" спочатку перевірить майстер, але "EXEC dbname.dbo.sp_something" ніколи не перейде до майстра спочатку.

Якщо я пригадую, урок - завжди використовувати цілком кваліфіковану назву.


5
Не думайте, що це має значення. EXEC MyDB.dbo.sp_helptext 'sp_helptext'як і раніше використовується той, masterнавіть якщо він є в базі даних користувачів. AFAIK перевіряє обидва місця та використовуватиме його, masterякщо воно існує та позначене як системний об'єкт.
Мартін Сміт

1
@MartinSmith 2012 року я не зміг примусити виконати головну версію (хоча мої тести там показали, що щось відбувається), якщо я не скинув локальну копію (у цьому випадку MyDB.dbo.sp_fooвсе-таки виконується головна версія). Зараз у мене немає 2008/2008 R2, щоб підтвердити, де ця поведінка змінилася.
Аарон Бертран

@AaronBertrand - Ах, цікаво, я зробив тест на R2 2008 року.
Мартін Сміт

Також зауважте, що якщо локальна процедура не знайдена і одна знайдена в майстрі, остання буде виконана, і не потрібно позначати її як системний об'єкт, щоб це відбулося. І хоча б у 2012 році, незалежно від того, незалежна від того, чи головна копія позначена системним об'єктом, не змінюється поведінка - з місцевим префіксом db / schema або без нього, локальна копія завжди виконується, якщо вона не існує.
Аарон Бертран

1
На жаль, я мав би уточнити, що мій коментар був спрямований на запропоновану відповідь. Коментар SQLRockstar "EXEC dbname.dbo.sp_something ніколи не перейде до майстра спочатку". невірно.
Greenstone Walker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.