sql >> データベース >  >> RDS >> Database

sp_プレフィックスはまだノーノーですか?

    SQL Serverの世界には、すべてのオブジェクトにプレフィックスを付けるのが好きな人とそうでない人の2種類があります。前者のグループはさらに2つのカテゴリに分類されます。ストアドプロシージャの前にsp_を付けるグループです。 、および他のプレフィックス(usp_など)を選択するユーザー またはproc_ )。長年の推奨事項は、sp_を回避することでした。 パフォーマンス上の理由と、システムカタログにすでに存在する名前を選択した場合のあいまいさや衝突を避けるために、プレフィックスを付けます。衝突は確かにまだ問題ですが、オブジェクト名を精査したとすると、それでもパフォーマンスの問題ですか?

    TL; DRバージョン:はい。

    sp_プレフィックスはまだノーノーです。 ただし、この投稿では、SQL Server 2012で、この警告のアドバイスが適用されなくなったと思われる理由と、この命名規則を選択した場合のその他の潜在的な副作用について説明します。

    sp_の問題は何ですか?

    sp_ プレフィックスは、あなたが思っていることを意味するものではありません。ほとんどの人は、spと考えています。 実際には「特別」を意味する場合は、「ストアドプロシージャ」の略です。 sp_を使用してマスターに格納されたストアドプロシージャ(およびテーブルとビュー) プレフィックスは、適切な参照なしで任意のデータベースからアクセスできます(ローカルバージョンが存在しない場合)。プロシージャがシステムオブジェクトとしてマークされている場合(sp_MS_marksystemobjectを使用) (is_ms_shippedを設定する文書化されていないサポートされていないシステムプロシージャ 1)の場合、masterのプロシージャは、呼び出し元のデータベースのコンテキストで実行されます。簡単な例を見てみましょう:

    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

    結果:

    (0 row(s) affected)
    
    sp_test    foo
    
    (1 row(s) affected)

    パフォーマンスの問題は、プロシージャのローカルバージョンが存在するかどうか、およびマスターに同等のオブジェクトが実際に存在するかどうかに応じて、マスターが同等のストアドプロシージャをチェックする可能性があるという事実に起因します。これにより、追加のメタデータオーバーヘッドと、追加のSP:CacheMissが発生する可能性があります。 イベント。問題は、このオーバーヘッドが具体的かどうかです。

    それでは、テストデータベースでの非常に簡単な手順を考えてみましょう。

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

    そしてマスターでの同等の手順:

    USE master;
    GO
    CREATE PROCEDURE dbo.sp_something
    AS
    BEGIN
      SELECT 'master', DB_NAME();
    END
    GO
    EXEC sp_MS_marksystemobject N'sp_something';

    CacheMiss:事実かフィクションか?

    テストデータベースからクイックテストを実行すると、これらのストアドプロシージャを実行しても、プロシージャを適切にデータベースまたはスキーマで修飾するか(一般的な誤解)、またはマークを付けるかどうかに関係なく、マスターからバージョンが実際に呼び出されることはありません。システムオブジェクトとしてのマスターバージョン:

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

    結果:

    sp_prefix    sp_prefix
    sp_prefix    sp_prefix
    sp_prefix    sp_prefix
    

    クイックトレース®も実行してみましょう SQL Sentryを使用して、SP:CacheMissがあるかどうかを確認します イベント:

    CacheMissが表示されます ストアドプロシージャを呼び出すアドホックバッチのイベント(SQL Serverは通常、主にプロシージャ呼び出しで構成されるバッチをキャッシュしないため)が、ストアドプロシージャ自体のイベントではありません。 sp_somethingがある場合とない場合の両方 マスターに存在するプロシージャ(および存在する場合は、システムオブジェクトとしてマークされている場合とされていない場合の両方)、sp_somethingの呼び出し ユーザーデータベースでは、マスターのプロシージャを「誤って」呼び出したり、CacheMissを生成したりすることはありません。 手順のイベント。

    これはSQLServer2012で行われました。SQLServer2008R2で上記と同じテストを繰り返したところ、わずかに異なる結果が見つかりました。

    したがって、SQL Server 2008 R2では、追加のCacheMissが表示されます。 SQL Server 2012では発生しないイベント。これはすべてのシナリオで発生します(同等のオブジェクトマスターがない、マスター内のオブジェクトがシステムオブジェクトとしてマークされている、マスター内のオブジェクトがシステムオブジェクトとしてマークされていない)。すぐに、この追加のイベントがパフォーマンスに顕著な影響を与えるかどうかに興味がありました。

    パフォーマンスの問題:事実かフィクションか?

    sp_なしで追加の手順を実行しました 生のパフォーマンスを比較するためのプレフィックス、CacheMiss さておき:

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

    したがって、sp_somethingの唯一の違いは およびproc_something 。次に、EXEC sp_prefix.dbo.<procname>を使用して、ラッパープロシージャを作成し、それぞれ1000回実行しました。 、EXEC dbo.<procname> およびEXEC <procname> 構文。同等のストアドプロシージャがマスターに存在し、システムオブジェクトとしてマークされ、マスターに存在するがシステムオブジェクトとしてマークされておらず、マスターにまったく存在しない。

    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

    SQL Sentry Plan Explorerを使用して各ラッパープロシージャの実行時間を測定すると、結果はsp_を使用していることを示しています。 プレフィックスは、ほとんどすべての場合(そして確かに平均して)の平均期間に大きな影響を与えます:

    <!-target =_blank href ="http://www.sqldat.com/article/uploadfiles/202205/2022051415101638.png">

    また、SQL Server 2012のパフォーマンスは、SQL Sevrer2008R2のパフォーマンスよりもはるかに優れていることがわかります。他の変数に違いはありません。両方のインスタンスは同じホスト上にあり、どちらもメモリやその他のあらゆる種類のプレッシャーにさらされていません。これは、追加のCacheMissの組み合わせである可能性があります イベントと、バージョン間でデータベースエンジンに加えられた機能強化から得られる透過的な改善。

    別の副作用:あいまいさ

    作成したオブジェクトを参照するストアドプロシージャを作成する場合は、dbo.sp_helptextと言います。 、そしてこの名前がシステムプロシージャ名と衝突することに気づかなかった(または気にしなかった)場合、誰かがストアドプロシージャをレビューしているときに、あいまいさが生じる可能性があります。彼らはおそらく、あなたがたまたまその名前を共有するために作成した別のプロシージャではなく、システムプロシージャを意味していると想定します。

    sp_のプレフィックスが付いたストアドプロシージャを参照するストアドプロシージャを作成すると、もう1つの興味深いことが起こります。 それはたまたまマスターにも存在します。すぐにはなじみがない可能性がある(したがって、私が説明しているシナリオを代表する可能性が高い)既存の手順を選択してみましょう:sp_resyncuniquetable

    CREATE PROCEDURE dbo.test1
    AS
    BEGIN
      EXEC dbo.sp_resyncuniquetable;
    END
    GO

    Management Studioでは、マスターにその名前の有効なプロシージャがあるため、IntelliSenseはストアドプロシージャ名に無効なアンダースコアを付けません。したがって、下に波線が表示されていなくても、プロシージャはすでに存在していると見なすことができます(また、masterのプロシージャをエラーなしで実行できると仮定すると、QA /テストにも合格する可能性があります)。再同期プロシージャに別の名前を選択した場合は、proc_resyncuniquetableとしましょう。 、このあいまいさの可能性はまったくありません(誰かがマスターでそのプロシージャを手動で作成しない限り、これは発生する可能性があります)。プロシージャがまだ存在しない場合でも、呼び出し元は正常に作成されますが(名前解決が延期されているため)、次の警告が表示されます:

    The module 'test1' depends on the missing object 'dbo.proc_resyncuniquetable'. The module will 
    still be created; however, it cannot run successfully until the object exists.

    このシナリオでは、もう1つのあいまいさの原因が発生する可能性があります。次の一連のイベントは完全にもっともらしいです:

    1. プロシージャの初期バージョン、たとえばsp_fooを作成します 。
    2. デプロイヤが誤ってマスターにバージョンを作成します(おそらく気付くか、気付かないかもしれませんが、どちらの場合もクリーンアップされません)。
    3. デプロイヤー(または他の誰か)が、今回は適切なデータベースにプロシージャを作成します。
    4. 時間の経過とともに、your_database.dbo.sp_fooに複数の変更を加えます。 。
    5. sp_fooを置き換えます sp_superfooを使用 、sp_fooを削除します ユーザーデータベースから。
    6. 新しいストアドプロシージャを参照するようにアプリケーションを更新する場合、さまざまな理由で1つか2つの置換を見逃す可能性があります。

    したがって、このシナリオでは、アプリケーションは引き続きsp_fooを呼び出しています。 、そして、ローカルコピーを削除したとしても、マスターで同等であると見なすものが見つかるため、失敗することはありません。マスターのこのストアドプロシージャは、sp_superfooと同等ではないだけではありません。 、最新バージョンのsp_fooと同等ではありません 。

    「手順が見つかりません」は、「手順が存在しませんが、それを呼び出すコードは機能し、期待される結果を完全に返さない」よりもトラブルシューティングがはるかに簡単な問題です。

    結論

    SQL Server 2012で動作が少し変更されたとしても、sp_を使用するべきではないと私はまだ考えています。 マスターでストアドプロシージャを作成し、それをシステムオブジェクトとしてマークすることを意図していない限り、いつでもプレフィックスを付けることができます。そうしないと、これらのパフォーマンスの問題と、複数の面での潜在的なあいまいさにさらされます。

    個人的には、ストアドプロシージャにプレフィックスを付ける必要はまったくないと思いますが、他にどのような種類のオブジェクトが可能かを尋ねる以外に、それを納得させる具体的な証拠はありません。ビュー、関数、またはテーブルを実行することはできません…

    私がよく提案するように、あなたが一貫している限り、私はあなたの命名規則が何であるかを本当に気にしません。ただし、sp_のような潜在的に有害なプレフィックスは避けるべきだと思います。 。


    1. 複数の外部キーを使用してテーブルを作成し、混乱しないようにする方法

    2. MariaDBでのELT()のしくみ

    3. 自動車教習所の予約システムのデータベースモデル。パート1

    4. OracleDatabaseで有効なタイムゾーンのリストを返す方法