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

アドホックSQLとストアドプロシージャを作成する方がよいのはいつですか

    SQL Serverはアドホッククエリの実行プランをキャッシュするため、(最初の呼び出しにかかる時間を割り引いて)2つのアプローチは速度の点で同じになります。

    一般に、ストアドプロシージャの使用とは、アプリケーションに必要なコードの一部(T-SQLクエリ)を取得し、ソース管理下にない場所に配置することを意味します( ありますが、通常はそうではありません )そして、あなたの知らないうちに他の人がそれを変更できる場所。

    このような中心的な場所にクエリを配置することはかもしれません 表現するデータにアクセスする必要のあるさまざまなアプリケーションの数に応じて、良いことです。一般に、アプリケーションが使用するクエリをアプリケーションコード自体に常駐させる方がはるかに簡単だと思います。

    1990年代半ば、従来の知識では、SQL Serverのストアドプロシージャはパフォーマンスが重要な状況に移行する方法であり、当時は間違いなくそうでした。ただし、このCWの背後にある理由は、長い間有効ではありませんでした。

    更新: また、ストアドプロシージャの実行可能性をめぐる議論では、プロシージャを防御するためにSQLインジェクションを防止する必要が生じることがよくあります。確かに、文字列の連結を介してアドホッククエリを組み立てることが正しいことだと考える人は誰もいません(ただし、これは、ユーザー入力を連結している場合にのみSQLインジェクション攻撃にさらされます )。明らかに、アドホッククエリはパラメータ化する必要があります。これは、SQLインジェクション攻撃のベッドの下の怪物を防ぐだけでなく、プログラマーとしての生活を一般的に楽にするためです(シングルをいつ使用するかを理解する必要がある場合を除きます)。値を引用符で囲みます)。

    更新2: 私はもっ​​と研究をしました。 このMSDNホワイトペーパー に基づく 、答えは、クエリでの「アドホック」の意味に正確に依存しているようです。たとえば、次のような単純なクエリ:

    SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5
    

    ...予定 実行プランをキャッシュします。さらに、クエリには特定の不適格要素(1つのテーブルからの単純なSELECT以外のほとんどすべて)が含まれていないため、SQL Serverは実際にクエリを「自動パラメーター化」し、リテラル定数「5」をパラメーターに置き換えてキャッシュします。パラメータ化されたバージョンの実行プラン。つまり、 thisを実行すると アドホッククエリ:

    SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 23
    

    ...キャッシュされた実行プランを使用できるようになります。

    残念ながら、自動パラメータ化の不適格なクエリ要素のリストは長いです(たとえば、DISTINCTの使用を忘れてください 、TOPUNIONGROUP BYOR など)、パフォーマンスを期待することはできません。

    次のように、自動パラメータ化されない「超複雑な」クエリがある場合:

    SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5 OR ITEM_COUNT < 23
    

    ...クエリの正確なテキストによって引き続きキャッシュされるため、アプリケーションが同じリテラルの「ハードコードされた」値を使用してこのクエリを繰り返し呼び出すと、最初のクエリの後の各クエリは、キャッシュされた実行プランを再利用します(およびしたがって、ストアドプロシージャと同じくらい高速です。

    リテラル値が変更された場合(たとえば、表示されたデータのフィルタリングや並べ替えなどのユーザーアクションに基づいて)、クエリはキャッシュの恩恵を受けません(最近のクエリと誤って完全に一致する場合を除く)。

    「アドホック」クエリを使用したキャッシュのメリットを享受する方法は、それらをパラメータ化することです。次のようにC#でオンザフライでクエリを作成します:

    int itemCount = 5;
    string query = "DELETE FROM tblSTUFF WHERE ITEM_COUNT > " + 
            itemCount.ToString();
    

    間違っています。正しい方法(ADO.Netを使用)は次のようになります:

    using (SqlConnection conn = new SqlConnection(connStr))
    {
        SqlCommand com = new SqlCommand(conn);
        com.CommandType = CommandType.Text;
        com.CommandText = 
            "DELETE FROM tblSTUFF WHERE ITEM_COUNT > @ITEM_COUNT";
        int itemCount = 5;
        com.Parameters.AddWithValue("@ITEM_COUNT", itemCount);
        com.Prepare();
        com.ExecuteNonQuery();
    }
    

    クエリにはリテラルが含まれておらず、すでに完全にパラメータ化されているため、同じパラメータ化されたステートメントを使用する後続のクエリは、キャッシュされたプランを使用します(異なるパラメータ値で呼び出された場合でも)。ここでのコードは、とにかくストアドプロシージャを呼び出すために使用するコードと実質的に同じであることに注意してください(唯一の違いはCommandTypeとCommandTextです)。したがって、クエリのテキストを「ライブ」にする場所に多少なります。 "(アプリケーションコードまたはストアドプロシージャ内)。

    最後に、「アドホック」クエリとは、さまざまな列、テーブル、フィルタリングパラメータなどを使用して、クエリを動的に構築していることを意味します。たとえば、次のようなものです。

    SELECT ID, DESC FROM tblSTUFF WHERE ITEM_COUNT > 5
    
    SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
        WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
    
    SELECT ID, FIRSTNAME, LASTNAME FROM tblPEEPS 
        WHERE AGE >= 18 AND LASTNAME LIKE '%What the`
        ORDER BY LASTNAME DESC
    

    ...それならあなたはほとんどできません これは、ストアドプロシージャを使用して行います(EXECは使用しません)。 礼儀正しい社会では話されないハック)なので、要点は議論の余地があります。

    更新3: これが唯一の本当に良いパフォーマンス関連です ストアドプロシージャを使用する理由(とにかく、私は考えることができます)。クエリが実行プランのコンパイルプロセスに実際の実行よりも大幅に時間がかかり、クエリの呼び出し頻度が低い場合(たとえば、月次レポートなど)、クエリをストアドプロシージャに配置すると、 SQL Serverに、コンパイルされたプランをキャッシュに保持して、来月頃になるようにします。しかし、それが本当かどうかは私を打ち負かします。



    1. Postgresの単純な「ピボット」テーブル

    2. 1日あたりの過去1週間のレコードを取得します

    3. phpmyadminを使用してストアドプロシージャを作成する方法と、phpを介して使用する方法は?

    4. SQL、結果を連結する方法は?