Все еще неправильно начинать имя хранимой процедуры пользователя с 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

Запустите его, затем откройте Profiler (добавьте SP:CacheMissсобытие «Хранимые процедуры ->» ) и снова запустите хранимые процедуры. Предполагается, что вы увидите разницу между двумя хранимыми процедурами: sp_Select1хранимая процедура будет генерировать на одно SP:CacheMissсобытие больше, чем Select1хранимая процедура (статья ссылается на SQL Server 7.0 и SQL Server 2000 ).

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

Вот мне и интересно

  • Могу ли я сделать что-то не так при выполнении примера?
  • Является ли sproc sp_somethingadagium «не называть пользователя » все еще действительным в более новых версиях SQL Server?
  • Если так, есть ли хороший пример, который показывает его действительность в SQL Server 2008 R2?

Большое спасибо за ваши мысли по этому поводу!

РЕДАКТИРОВАТЬ

Я нашел создание хранимых процедур (компонент Database Engine) в msdn для SQL Server 2008 R2, который отвечает на мой второй вопрос:

Мы рекомендуем вам не создавать хранимых процедур, используя sp_ в качестве префикса. SQL Server использует префикс sp_ для обозначения системных хранимых процедур. Выбранное вами имя может конфликтовать с какой-то будущей системной процедурой. [...]

Там ничего не сказано о проблемах производительности, вызванных использованием sp_префикса. Я хотел бы знать, если это все еще так или они исправили это после SQL Server 2000.

marc_s
источник
3
Я уже смотрел на это раньше и обнаружил незначительную разницу в производительности, которую я снизил до чуть больших накладных расходов при разрешении sp_версий (необходимо проверить как в основной, так и в пользовательской базах данных, поскольку это отдает приоритет системным процессам в master-> процессам в пользовательской БД -> не системной Procs in master)
Мартин Смит
4
Какую выгоду вы видите для префикса хранимой процедуры sp_? Это примерно так же полезно, как префикс таблицы с tbl. Зачем сначала использовать мастер поиска системы (даже если он незначителен или не имеет разницы в производительности), чтобы позволить вам использовать это бессмысленное соглашение об именах?
Аарон Бертран
1
@AaronBertrand: честно говоря, я не вижу никакой пользы вообще в предваряя sprocs с sp_, только недостатки, и я никогда бы не префикс их этот путь сам. Но я хочу, чтобы все аргументы, которые я могу выдвинуть, чтобы убедить моих коллег, тоже не делают этого.
1
Да, ТБЛ бесполезен, но я все еще люблю его использовать. Должно быть, мой OCD начинает действовать. Теперь сойди с моей лужайки.
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_приставку.

marc_s
источник
5
Прост в тестировании. CREATE PROC dbo.sp_helptext AS SELECT 1тогда попробуйEXEC dbo.sp_helptext
Мартин Смит
Спасибо за ваш ответ, очень полезное дополнение по распространенности mastersp.
2

Лучшим тестом является написание запроса, который требует полной оптимизации, поскольку это, вероятно, лучшее отражение того, что делает процесс, который вы пишете. Я завернул следующий запрос в SP и повторил ваш тест и получил те же результаты.

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, вы можете получить копию proc, которая была запущена в master вместо базы данных, в которой вы работаете, но быстрый тест покажет, что это не так. Тем не менее, если процедура будет удалена из БД, в которой вы работаете, и копия будет существовать в master, то она будет выполнена, что может быть проблемой, если это старая версия. Если это проблема, я бы не использовал "sp_" в качестве имени процесса.

cfradenburg
источник
Интересные находки, спасибо! Я буду использовать ваш пример в сочетании с примером Аарона, чтобы выполнить еще несколько тестов.
1

Я считаю, что проблема связана с тем, что вы не указываете полное имя объекта. Таким образом, «EXEC sp_something» будет сначала проверять мастер, но «EXEC dbname.dbo.sp_something» никогда не будет идти сначала к мастеру.

Урок, если я помню, состоит в том, чтобы всегда использовать полностью определенное имя.

SQLRockstar
источник
5
Не думайте, что это имеет значение. EXEC MyDB.dbo.sp_helptext 'sp_helptext'все еще использует тот из, masterдаже если есть один в пользовательской базе данных. AFAIK проверяет оба местоположения и будет использовать одно из, masterесли оно существует и помечено как системный объект.
Мартин Смит
1
@MartinSmith 2012 г. Я не мог заставить основную версию быть выполненной (хотя мои тесты там показали, что что- то происходит), если я не удалил локальную копию (в этом случае MyDB.dbo.sp_fooвсе еще выполнялась основная версия). У меня нет 2008/2008 R2 прямо сейчас, чтобы подтвердить, где это поведение изменилось.
Аарон Бертран
@AaronBertrand - Ах, интересно, я сделал свой тест на 2008 R2.
Мартин Смит
Также обратите внимание, что если локальная процедура не найдена, а одна найдена в master, последняя будет выполнена, и для этого не нужно отмечать ее как системный объект. И, по крайней мере, в 2012 году, независимо от того, помечена ли главная копия как системный объект, поведение не меняется - с локальным префиксом db / schema или без него локальная копия всегда выполняется, если ее не существует.
Аарон Бертран
1
К сожалению, я должен был уточнить, что мой комментарий был направлен на предложенный ответ. Комментарий SQLRockstar «EXEC dbname.dbo.sp_something никогда не пойдет мастером первым». это неверно.
Гринстоун Уолкер