どちらが良いですか:アドホック クエリまたはストアド プロシージャ?[閉まっている]

StackOverflow https://stackoverflow.com/questions/22907

  •  09-06-2019
  •  | 
  •  

質問

何らかの理由で LINQ を使用できないと仮定した場合、クエリをストアド プロシージャに配置する方が良い方法ですか、それとも実行するのと同じくらい良い方法ですか? このために データベース (たとえば、SQL Server) に対するクエリですか?

役に立ちましたか?

解決

主に WinForms クライアント/サーバー アプリを作成した私の経験から、次のような単純な結論に達しました。

ストアド プロシージャを使用します。

  1. あらゆる複雑なデータ作業に。本当にカーソルや一時テーブルが必要な作業を行う場合は、通常、SQL Server 内で行うのが最も速い方法です。
  2. データへのアクセスをロックダウンする必要がある場合。ユーザー (またはロールなど) にテーブルへのアクセス権を与えない場合、データを操作する唯一の方法は、作成した SP を介することになります。

アドホック クエリを使用します。

  1. データ アクセスを制限する必要がない (または別の方法で制限している) 場合の CRUD の場合。
  2. 簡単な検索用。多数の検索条件に対して SP を作成するのは面倒であり、維持するのも困難です。適度に高速な検索クエリを生成できる場合は、それを使用してください。

私のアプリケーションのほとんどでは SP とアドホック SQL の両方を使用してきましたが、SP は最終的に C# と同じコードになり、バージョン管理、テスト、保守が難しくなるため、ますます使用することが少なくなっていることに気づきました。特別な理由がない限り、アドホック SQL を使用することをお勧めします。

他のヒント

SQL Server 以外のことについて話すことはできませんが、パフォーマンスに関する議論は次のとおりです。 ない 6.5 以前を使用している場合を除き、この機能は非常に有効です。SQL Server は約 10 年間、アドホック実行プランをキャッシュしてきました。

ストアド プロシージャは、データベースに対して実行されるアクションをカプセル化するソフトウェア コントラクトを表します。プロシージャ内のコード、さらにはデータベース自体のスキーマさえも、コンパイルおよびデプロイされたコードに影響を与えることなく変更できるため、プロシージャの入力と出力は同じままになります。

アプリケーションにクエリを埋め込むことで、データ モデルと密接に結合することになります。

同じ理由で、データベース内のすべてのテーブルに対する単なる CRUD クエリであるストアド プロシージャを単純に作成することも、依然として密結合であるため、推奨されません。代わりに、手順は大規模で粒度の粗い操作にする必要があります。

セキュリティの観点から、アプリケーションから db_datareader と db_datawriter を禁止し、ストアド プロシージャへのアクセスのみを許可することをお勧めします。

これはデータベースを保守しなければならない人々とユーザーインターフェースを開発する人々の間の基本的な対立だと思います。

データ担当者として、アドホック クエリを通じてアクセスされるデータベースを扱うことは考えていません。効果的な調整や管理が難しいからです。スキーマへの変更がどのような影響を与えるかを知るにはどうすればよいですか?さらに、セキュリティ上の理由から、ユーザーにデータベース テーブルへの直接アクセスを許可すべきではないと思います (これは単に SQL インジェクション攻撃を意味しているのではなく、直接権限を許可せず、すべてのユーザーに次の権限を要求するのが基本的な内部制御であるためでもあります)。アプリ用に設計された proc のみを使用してください。これは詐欺の可能性を防ぐためです。テーブルへの直接挿入、更新、または削除権限を許可する金融システムには、不正行為の大きなリスクがあります。これは悪いことです。)。

データベースはオブジェクト指向ではないため、オブジェクト指向の観点からは優れているように見えるコードも、データベースの観点からは非常に悪い場合があります。

当社の開発者は、すべてのデータベース アクセスが proc 経由であることをうれしく思っています。これにより、コードの新しいブランチを作成して再コンパイルして再コンパイルするよりも、データ中心のバグを修正し、本番環境で proc を実行するだけで済むため、はるかに高速になるからです。本番環境にリロードします。すべてのプロシージャが Subversion にあることを要求しているため、ソース管理はまったく問題になりません。Subversion にない場合は、データベース管理者によって定期的に削除されるため、ソース管理を使用することに抵抗はありません。

ストアド プロシージャは間違いなく最適な方法です。ストアド プロシージャはコンパイルされ、事前に実行計画があり、権限管理を行うことができます。

ストアド プロシージャに関するこのソース管理の問題全体が理解できません。少し規律を持っていれば、間違いなくソース管理できます。

常に、ストアド プロシージャのソースである .sql ファイルから始めてください。コードを作成したら、それをバージョン管理に置きます。次回ストアド プロシージャを編集するときは、データベースではなくソース管理からストアド プロシージャを取得します。これに従えば、コードと同じくらい優れたソース管理が得られます。

ここでOracleのTom Kyte氏の言葉を引用したいと思います...コードを書く場所に関する彼のルールは次のとおりです...少し関係ありませんが、知っておくと良いと思います。

  1. PL/SQL のストアド プロシージャから始めます...
  2. PL/SQL のストアド プロシージャを使用して何かを実行できないと思われる場合は、Java ストアド プロシージャを使用してください。
  3. Java ストアド プロシージャを使用して何かを実行できないと思われる場合は、Pro*c を検討してください。
  4. Pro*C を使用して何かを達成できないと思われる場合は、何を達成する必要があるかを再考した方がよいでしょう。

私たちのアプリケーションには、クエリの内容を提供するコード層があります (ストアド プロシージャの呼び出しである場合もあります)。これにより、次のことが可能になります。

  • すべてのクエリを簡単にバージョン管理下に置くことができます
  • 異なるデータベースサーバーの各クエリに必要な変更を加える
  • コード全体で同じクエリ コードの繰り返しを排除します。

アクセス制御はデータベースではなく中間層に実装されるため、そこにストアド プロシージャは必要ありません。これは、ある意味、アドホック クエリとストアド プロシージャの間の中間道です。

私の答え 別からの 役職:ストアド プロシージャは、 もっと 次の理由により保守可能です。

  • SQL を変更したいときに C# アプリを再コンパイルする必要はありません
  • 結局 SQL コードを再利用することになります。

コードの繰り返しは、 最悪 保守可能なアプリケーションを構築しようとしているときにできることです。

複数の場所で修正が必要な論理エラーが見つかった場合はどうなりますか?コードをコピーして貼り付けた最後の場所を変更することを忘れがちです。

私の意見では、パフォーマンスとセキュリティの向上はさらにプラスです。 安全でない/非効率な SQL ストアド プロシージャを作成することもできます。

別の DB への移植が容易 - 移植するためのプロシージャが不要

すべてのストアド プロシージャをスクリプトアウトして別の DB に作成するのは、それほど難しいことではありません。実際 - それは より簡単に 主キーや外部キーを気にする必要がないため、テーブルをエクスポートするよりも便利です。

どちらにも説得力のある議論があります。ストアド プロシージャはすべて中央リポジトリにありますが、移行が (潜在的に) 難しく、アドホック クエリはコードと同様にデバッグが簡単ですが、クエリ内で見つけるのが難しい場合もあります。コード。

ストアド プロシージャの方が効率的であるという議論は、もはや根拠がありません。リンクテキスト

ストアド プロシージャと動的クエリについて Google で検索すると、どちらの方法でもまともな引数が表示されるため、おそらく自分で決定するのが最善です...

SQL をコードに記述する場合、将来の問題に備えて、ストア プロシージャを可能な限り使用する必要があります。SPROC の作成には、コードでの作成とほぼ同じ時間がかかります。

中程度の負荷では良好に実行されるクエリを考えてみましょう。ただし、フルタイム運用に入ると、不適切に最適化されたクエリがシステムに打撃を与え、システムを停止させます。ほとんどの SQL サーバーでは、SQL サーバーを使用しているのはアプリケーション/サービスだけではありません。あなたのアプリケーションは今、怒っている人たちをたくさん呼び寄せています。

クエリが SPROC にある場合は、フレンドリーな DBA がアプリを再コンパイルしたり破損したりすることなく管理および最適化することもできます。DBA はこの分野の専門家であり、何をすべきか、何をすべきではないかを知っていることを忘れないでください。彼らのより深い知識を活用することは理にかなっています。

編集:誰かが、再コンパイルは怠惰な言い訳だと言いました。そう、アプリを再コンパイルして何千ものデスクトップにデプロイする必要があるときに、どれだけ怠惰に感じるか見てみましょう。これはすべて、アドホック クエリがサーバー時間を食いすぎていると DBA が告げたからです。

誰かが、再コンパイルは怠惰な言い訳だと言いました。そう、アプリを再コンパイルして何千ものデスクトップにデプロイする必要があるときに、どれだけ怠惰に感じるか見てみましょう。これはすべて、アドホック クエリがサーバー時間を食いすぎていると DBA が告げたからです。

1000 台のデスクトップをデータベースに直接接続するのは良いシステム アーキテクチャでしょうか?

ここで考慮すべき点がいくつかあります。 とにかく、ストアド プロシージャが必要なのは誰でしょうか?

これは明らかにユーザー自身のニーズと好みの問題ですが、公開環境でアドホック クエリを使用する場合に考慮すべき非常に重要なことの 1 つはセキュリティです。常にパラメータ化して、次のような典型的な脆弱性に注意してください。 SQLインジェクション攻撃.

ストアド プロシージャは、再コンパイルせずに変更できるため、優れています。できるだけ頻繁に使用するように努めます。

ユーザー入力に基づいて動的に生成されるクエリに対してのみアドホックを使用します。

他の人が述べた理由で Proc を使用し、プロファイラーまたは Proc の一部を使用して Proc を調整する方が簡単です。これにより、SQL サーバーに何が送信されているかを確認するためにアプリを実行するように誰かに指示する必要がなくなります。

アドホック クエリを使用する場合は、パラメータ化されていることを確認してください。

パラメータ化された SQL または SPROC...パフォーマンスの観点からは問題ではありません...どちらでもクエリを最適化できます。

私にとって、SPROC の残りの利点は、sproc を実行するためのログイン権限を付与するだけで、多くの SQL 権限管理を排除できることです...パラメータ化された SQL を使用する場合、接続文字列でのログインにさらに多くの権限が与えられます (ANY と書く)たとえば、アクセス権のあるテーブルの 1 つに対する select ステートメントのようなものです)。

私は依然としてパラメータ化された SQL を好みますが...

アドホック クエリの使用に関する説得力のある議論は見つかりませんでした。特に C#/Java/PHP コードと混同されたもの。

sproc のパフォーマンスに関する議論は議論の余地がありません。上位 3 つの RDBM はクエリ プラン キャッシュを使用しており、しばらくの間そのようになっています。それは文書化されています...それともまだ1995年ですか?

ただし、アプリに SQL を埋め込むのもひどい設計です。コードのメンテナンスは多くの人にとって欠落している概念のようです。

アプリケーションが ORM を使用して最初から開始できる場合 (グリーンフィールド アプリケーションはその中間にあります。)、クラス モデルが DB モデルを駆動するため、それは素晴らしい選択であり、時間を大幅に節約できます。

ORM フレームワークが利用できない場合は、SQL リソース XML ファイルを作成して、必要に応じて SQL 文字列を検索するというハイブリッドなアプローチを採用しています (SQL 文字列はリソース フレームワークによってキャッシュされます)。SQL に軽微な操作が必要な場合は、コード内で行われます。主要な SQL 文字列操作が必要な場合は、アプローチを再考します。

このハイブリッド アプローチは、開発者による管理を容易にし (私のチームはクエリ プランを読むことができるほど聡明なので、少数派かもしれません)、展開は SVN からの簡単なチェックアウトです。また、RDBM の切り替えも簡単になります。SQL リソース ファイルを交換するだけです (もちろん、ORM ツールほど簡単ではありませんが、レガシー システムやサポートされていないデータベースに接続する場合は機能します)。

あなたの目標が何であるかによります。たとえば、項目のリストを取得する必要があり、それがアプリケーションの実行全体で 1 回だけ行われる場合、ストアド プロシージャを使用する価値はおそらくありません。一方、繰り返し実行され、実行に (比較的) 長い時間がかかるクエリは、パフォーマンスが向上するため、データベース ストレージの優れた候補となります。

アプリケーションのほぼ全体がデータベース内に存在する場合、ストアド プロシージャを使用するのは簡単です。データベースがほんの少しだけ重要なデスクトップ アプリケーションを作成している場合は、アドホック クエリの方が良い選択肢になる可能性があります。 すべてのコードを 1 か所に保管します.

@テラピン:変更を加えるためにアプリを再コンパイルする必要がないという事実により、ストアド プロシージャがより良い選択肢になるというあなたの主張は、スターターではないと思います。アドホック クエリではなくストアド プロシージャを選択する理由はあるかもしれませんが、他に説得力のあるものが存在しない場合、コンパイルの問題は本当の理由というよりむしろ怠惰のように思えます。

私の経験では、クエリやストアド プロシージャの 90% は (少なくとも手動で) まったく作成すべきではありません。

データ アクセスは何らかの方法で自動的に生成される必要があります。プロシージャをコンパイル時に静的に生成するか、実行時に動的に生成するかを決定できますが、テーブルに列 (オブジェクトのプロパティ) を追加する場合は、1 つのファイルのみを変更する必要があります。

すべてのデータを保持することを好みます アクセス データ アクセス層が直接 SQL クエリを実行するプログラム コード内のロジック。一方で、データは 管理 トリガー、ストアド プロシージャ、カスタム関数などの形式でデータベースに配置したロジック。データベース化する価値があると私が考えるものの例としては、データ生成があります。顧客の名と姓があると仮定します。ここで、ユーザー インターフェイスには、重要なロジックから派生した DisplayName が必要になります。この世代では、行 (または他のソース データ) が更新されるたびにトリガーによって実行されるストアド プロシージャを作成します。

データ アクセス層はデータベースであり、データとデータ アクセスに関するすべてのものが「ただ単に」そこに含まれるという、やや一般的な誤解があるようです。これは単純に間違っていますが、この考えから派生したデザインをたくさん見かけます。おそらくこれは局地的な現象かもしれません。

ひどいデザインの SP をたくさん見たので、私は SP という考えをやめてしまっただけかもしれません。たとえば、私が参加したあるプロジェクトでは、すべてのテーブルと、発生する可能性のあるすべてのクエリに対して一連の CRUD ストアド プロシージャを使用していました。そうすることで、まったく無意味なレイヤーを追加しただけです。そんなことを考えるだけでも辛いです。

最近はストアドプロシージャをほとんど使用しません。コードでは簡単に実行できない複雑な SQL クエリにのみ使用します。

主な理由の 1 つは、ストアド プロシージャが OR マッパーではうまく機能しないためです。

最近では、何らかの OR マッパーを使用しないビジネス アプリケーション/情報システムを作成するには、十分な理由が必要だと思います。

ストアド プロシージャはコードのブロックとして動作するため、アドホック クエリの代わりに高速に動作します。もう1つは、ストアドプロシージャを提供することです。これは、Adhocクエリではこのようなものはありません。

クエリとストアド プロシージャの結果によっては異なるものもありますが、これは私の個人的な経験です。これを確認するには、キャスト関数と隠蔽関数を使用します。

大規模なプロジェクトでは、パフォーマンスを向上させるためにストアド プロシージャを使用する必要があります。

私のプロジェクトには 420 のプロシージャがありましたが、問題なく動作しました。私はこのプロジェクトに過去 3 年間取り組んでいます。

したがって、どのトランザクションでもプロシージャのみを使用してください。

1000のデスクトップをデータベースに直接接続できる場合、それは良いシステムアーキテクチャですか?

いいえ、明らかにそうではありません。例としては不適切かもしれませんが、私が言いたかった点は明らかだと思います。DBA はデータベース インフラストラクチャを管理しますが、これは彼らの専門知識であり、コードに SQL を詰め込むと、DBA とその専門知識への扉が閉ざされてしまいます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top