何らかの理由で LINQ を使用できないと仮定すると、クエリをストアド プロシージャに配置する方が良い方法ですか、それともデータベースに対してアドホッククエリを実行する方が良い方法ですか (たとえば、引数のために SQL Server を使用します)。
22 に答える
主にWinFormsクライアント/サーバーアプリを作成した私の経験では、これらは私が到達した単純な結論です。
ストアドプロシージャを使用する:
- 複雑なデータ作業に。本当にカーソルまたは一時テーブルを必要とする何かを実行する場合は、通常、SQLServer内で実行するのが最も高速です。
- データへのアクセスをロックダウンする必要がある場合。ユーザー(またはロールなど)にテーブルアクセスを許可しない場合、データを操作する唯一の方法は、作成したSPを使用することです。
アドホッククエリを使用する:
- データアクセスを制限する必要がない(または別の方法で制限している)場合のCRUDの場合。
- 簡単な検索用。多数の検索条件用のSPを作成するのは面倒であり、維持するのは困難です。適度に高速な検索クエリを生成できる場合は、それを使用してください。
ほとんどのアプリケーションでは、SPとアドホックSQLの両方を使用していますが、SPはC#と同じようにコードになり、バージョン管理、テスト、および保守が困難になるため、使用するSPはますます少なくなっています。特別な理由が見つからない限り、アドホックSQLを使用することをお勧めします。
SQL Server 以外について話すことはできませんが、6.5 以前を使用していない限り、SQL Server でのパフォーマンスの議論はあまり有効ではありません。SQL Server は、約 10 年前からアドホック実行プランをキャッシュしてきました。
これは、データベースを維持しなければならない人とユーザー インターフェイスを開発する人との間の基本的な対立だと思います。
データ担当者として、アドホック クエリを介してアクセスされるデータベースを使用することは考えません。効果的なチューニングや管理が難しいからです。スキーマへの変更が与える影響をどのように知ることができますか? さらに、セキュリティ上の理由から、データベース テーブルへの直接アクセスをユーザーに許可するべきではないと思います (単に SQL インジェクション攻撃を意味するのではなく、直接アクセスを許可せず、すべてのユーザーにアプリ用に設計されたプロシージャのみを使用してください。これは、詐欺の可能性を防ぐためです。テーブルへの直接の挿入、更新、または削除の権限を許可する金融システムは、詐欺のリスクが非常に高くなります。これは悪いことです。)
データベースはオブジェクト指向ではなく、オブジェクト指向の観点からは優れているように見えるコードでも、データベースの観点からは非常に悪い場合があります。
私たちの開発者は、コードの新しいブランチを作成して再コンパイルして再コンパイルするよりも、データ中心のバグを修正して本番環境でプロシージャを実行する方がはるかに高速になるため、すべてのデータベース アクセスが proc を介して行われることを喜んでいると語っています。プロダクションにリロードします。すべての proc を subversion にする必要があるため、ソース管理はまったく問題になりません。Subversion にない場合、データベース管理者によって定期的に削除されるため、ソース管理を使用することに抵抗はありません。
ストアドプロシージャは、データベースに対して実行されたアクションをカプセル化するソフトウェアコントラクトを表します。プロシージャ内のコード、およびデータベース自体のスキーマでさえ、コンパイルされてデプロイされたコードに影響を与えることなく変更できるため、プロシージャの入力と出力は同じままです。
アプリケーションにクエリを埋め込むことで、データモデルに緊密に結合できます。
同じ理由で、データベース内のすべてのテーブルに対する単なるCRUDクエリであるストアドプロシージャを単純に作成することもお勧めできません。これは依然として緊密な結合であるためです。代わりに、手順はかさばる、粗い操作である必要があります。
セキュリティの観点から、アプリケーションからdb_datareaderとdb_datawriterを禁止し、ストアドプロシージャへのアクセスのみを許可することをお勧めします。
ストアドプロシージャは間違いなく進むべき道です...それらはコンパイルされ、事前に実行計画があり、それらに対して権利管理を行うことができます。
ストアドプロシージャに関するこのソース管理の問題全体を理解していません。あなただけが少し訓練されていれば、あなたは間違いなくそれらをソース管理することができます。
常に、ストアドプロシージャのソースである.sqlファイルから始めてください。コードを記述したら、バージョン管理に入れます。次にストアドプロシージャを編集するときは、データベースではなくソース管理から取得します。これに従うと、コードと同じくらい優れたソース管理が可能になります。
ここでOracleのTomKyteを引用したいと思います...コードを書く場所に関する彼のルールは次のとおりです...少し無関係ですが、知っておくとよいでしょう。
- PL/SQLのストアドプロシージャから始めます。
- PL / SQLのストアド・プロシージャを使用して何かを実行できないと思われる場合は、Javaのストアド・プロシージャを使用してください。
- Javaストアドプロシージャを使用して何かを実行できないと思われる場合は、Pro*cを検討してください。
- Pro * Cを使用して何かを達成できないと思われる場合は、実行する必要があることを再考することをお勧めします。
このアプリケーションには、クエリの内容を提供するコード層があります (ストアド プロシージャの呼び出しである場合もあります)。これにより、次のことが可能になります。
- すべてのクエリをバージョン管理下に簡単に置く
- 異なるデータベースサーバーの各クエリに必要な変更を行うため
- コード全体で同じクエリ コードの繰り返しをなくす
アクセス制御はデータベースではなく中間層に実装されるため、そこにストアド プロシージャは必要ありません。これはある意味で、アドホック クエリとストアド プロシージャの中間の道です。
SQLをコードに書き込む場合、将来の頭痛の種にすでに設定している場合は、ストアドプロシージャを可能な限り使用する必要があります。SPROCの記述には、コードでの記述とほぼ同じ時間がかかります。
中程度の負荷でうまく実行されるクエリを考えてみてください。しかし、フルタイムの本番環境に入ると、最適化が不十分なクエリがシステムを攻撃し、クロールします。ほとんどのSQLサーバーでは、それを使用しているのはあなただけではありません。あなたのアプリケーションは今あなたのドアにたくさんの怒っている人々を連れてきました。
SPROCにクエリがある場合は、アプリを再コンパイルしたり壊したりすることなく、フレンドリーなDBAが管理および最適化できるようにします。DBAはこの分野の専門家であり、何をすべきか、何をすべきでないかを知っていることを忘れないでください。彼らのより深い知識を活用することは理にかなっています!
編集:誰かが再コンパイルは怠惰な言い訳だと言いました!そうですね、アプリを再コンパイルして数千台のデスクトップにデプロイする必要があるときに、どれほど怠惰に感じるかを見てみましょう。これはすべて、アドホッククエリがサーバー時間を使い果たしているとDBAが言っているためです。
どちらにも説得力のある議論があります - ストアド プロシージャはすべて中央リポジトリに配置されていますが、(潜在的に) 移行が困難であり、アドホック クエリはコードと同様にデバッグが容易ですが、コード。
ストアド プロシージャの方が効率的であるという議論には、もはや根拠がありません。 リンクテキスト
Stored Procedure と Dynamic Query をグーグルで検索すると、どちらの方法でも適切な引数が表示され、おそらく自分で決定するのが最善です...
別の投稿からの私の回答: ストアド プロシージャは、次の理由により保守性が高くなります。
- SQL を変更するたびに C# アプリを再コンパイルする必要はありません
- SQL コードを再利用することになります。
保守可能なアプリケーションを構築しようとしているときに、コードの繰り返しは最悪の行為です。
複数の場所で修正が必要な論理エラーが見つかった場合はどうなりますか? コードをコピーして貼り付けた最後の場所を変更するのを忘れがちです。
私の意見では、パフォーマンスとセキュリティの向上はプラスです。安全でない/非効率的な SQL ストアド プロシージャを作成することはできます。
別の DB への移植が容易 - 移植する proc が不要
すべてのストアド プロシージャをスクリプト化して別の DB に作成するのはそれほど難しくありません。実際、心配する主キー/外部キーがないため、テーブルをエクスポートするよりも簡単です。
ここで考慮すべきいくつかのこと:とにかく、誰がストアドプロシージャを必要としますか?
明らかにそれはあなた自身のニーズと好みの問題ですが、公開環境でアドホッククエリを使用するときに考慮すべき非常に重要なことの1つはセキュリティです。常にそれらをパラメータ化し、SQLインジェクション攻撃のような典型的な脆弱性に注意してください。
再コンパイルは怠惰な言い訳だと誰かが言った! アプリケーションを再コンパイルして何千台ものデスクトップに展開する必要があるときに、どれだけ怠惰に感じるか見てみましょう。これはすべて、DBA が、アドホック クエリがサーバー時間を消費しすぎていると言ったためです。
1000 台のデスクトップをデータベースに直接接続できるシステム アーキテクチャは適切ですか?
パラメータ化されたSQLまたはSPROC...パフォーマンスの観点からは重要ではありません...どちらかをクエリ最適化できます。
私にとって、SPROCの最後の残りの利点は、sprocを実行するためのログイン権限を付与するだけで多くのSQL権限管理を排除できることです...パラメータ化されたSQLを使用する場合、接続文字列を使用したログインにはさらに多くの権限があります(任意の書き込みたとえば、アクセスできるテーブルの1つに対する一種のselectステートメント)。
私はまだパラメータ化されたSQLを好みます...
アドホック クエリを使用するための説得力のある議論は見つかりませんでした。特に、C#/Java/PHP コードと混同されているもの。
他の人が言及した理由のためのProcs。また、プロファイラーまたはprocの一部を使用してprocを調整する方が簡単です。このように、誰かにアプリを実行して SQL サーバーに何が送信されているかを確認するように指示する必要はありません。
アドホック クエリを使用する場合は、パラメータ化されていることを確認してください
ストアド プロシージャは、再コンパイルせずに変更できるので優れています。できるだけ頻繁に使用するようにします。
ユーザー入力に基づいて動的に生成されるクエリにはアドホックのみを使用します。
sproc パフォーマンスの議論は意味がありません - 上位 3 つの RDBM はクエリ プラン キャッシュを使用しており、しばらくの間使用されています。それは文書化されています... それとも1995年はまだですか?
ただし、アプリに SQL を埋め込むのもひどい設計です。コードのメンテナンスは、多くの人にとって欠けている概念のようです。
ORM を使用してゼロからアプリケーションを開始できる場合 (未開発のアプリケーションはほとんどありません)、クラス モデルが DB モデルを駆動し、多くの時間を節約できるため、ORM は優れた選択肢です。
ORM フレームワークが利用できない場合は、SQL リソース XML ファイルを作成して、必要に応じて SQL 文字列を検索するハイブリッド アプローチを採用しました (その後、リソース フレームワークによってキャッシュされます)。SQL にマイナーな操作が必要な場合は、コードで実行します。主要な SQL 文字列操作が必要な場合は、アプローチを再考します。
このハイブリッド アプローチは、開発者による管理を容易にし (私のチームはクエリ プランを読むのに十分頭が良いので、私たちは少数派かもしれません)、展開は SVN から簡単にチェックアウトできます。また、RDBM の切り替えが簡単になります。SQL リソース ファイルを交換するだけです (もちろん、ORM ツールほど簡単ではありませんが、レガシー システムやサポートされていないデータベースへの接続は機能します)。
私の経験では、クエリやストアドプロシージャの90%は(少なくとも手動で)作成するべきではありません。
データアクセスは、何らかの方法で自動的に生成される必要があります。コンパイル時に静的にプロシージャを生成するか、実行時に動的にプロシージャを生成するかを決定できますが、テーブル(オブジェクトのプロパティ)に列を追加する場合は、1つのファイルのみを変更する必要があります。
ストアド プロシージャはコードのブロックとして機能するため、アドホック クエリの代わりに高速に機能します。もう1つのことは、ストアドプロシージャが再コンパイルオプションを提供することです。SQLの最良の部分は、アドホッククエリではこれとは異なり、ストアドプロシージャにこれを使用するだけです。
クエリとストアドプロシージャの結果が異なる場合がありますが、これは私の個人的な経験です。これを確認するには、キャストと変換機能を使用します。
パフォーマンスを向上させるために、大規模なプロジェクトにはストアド プロシージャを使用する必要があります。
私のプロジェクトには420の手順がありましたが、うまくいきました。私はこのプロジェクトで過去 3 年間働いています。
そのため、トランザクションにはプロシージャのみを使用してください。
あなたの目標が何であるかによって異なります。たとえば、アイテムのリストを取得する必要があり、それがアプリケーションの実行中に 1 回だけ発生する場合、ストアド プロシージャを使用する価値はおそらくありません。一方、繰り返し実行され、実行に (比較的) 長い時間がかかるクエリは、パフォーマンスが向上するため、データベース ストレージの優れた候補です。
アプリケーションがほぼ完全にデータベース内に存在する場合、ストアド プロシージャは非常に簡単です。データベースが重要ではないデスクトップ アプリケーションを作成している場合は、すべてのコードを 1 か所に保持できるため、アドホック クエリの方が適している場合があります。
@Terrapin:変更を加えるためにアプリを再コンパイルする必要がないという事実は、ストアドプロシージャをより良いオプションにするというあなたの主張は、初心者ではないと思います。アドホック クエリではなくストアド プロシージャを選択する理由があるかもしれませんが、他に説得力のあるものがなければ、コンパイルの問題は本当の理由ではなく怠惰のように思えます。
私は、すべてのデータアクセスロジックをプログラム コードに保持することを好みます。このプログラム コードでは、データ アクセス レイヤーが直接 SQL クエリを実行します。一方、データ管理ロジックは、トリガー、ストアド プロシージャ、カスタム関数などの形でデータベースに配置しました。データベース化する価値があると私が考えるものの例は、データ生成です - 私たちの顧客が FirstName と LastName を持っていると仮定します。ここで、ユーザー インターフェイスには、重要なロジックから派生した DisplayName が必要です。この生成では、行 (または他のソース データ) が更新されるたびにトリガーによって実行されるストアド プロシージャを作成します。
データアクセスレイヤーはデータベースであり、データとデータアクセスに関するすべてが「理由だけで」そこにあるという、やや一般的な誤解があるようです。これは単純に間違っていますが、このアイデアから派生した多くのデザインを目にします。とはいえ、これは局地的な現象かもしれません。
非常に多くの設計の悪い SP を見た後、私は SP のアイデアをオフにするだけかもしれません。たとえば、私が参加した 1 つのプロジェクトでは、遭遇したすべてのテーブルと考えられるすべてのクエリに対して一連の CRUD ストアド プロシージャを使用しました。そうすることで、彼らは単に別の完全に無意味なレイヤーを追加しました. そんなことを考えるだけでも辛いです。
最近では、ストアド プロシージャを使用することはほとんどありません。コードでは簡単に実行できない複雑な SQL クエリにのみ使用します。
主な理由の 1 つは、ストアド プロシージャが OR マッパーとうまく連携しないためです。
最近では、ある種の OR マッパーを使用しないビジネス アプリケーション/情報システムを作成するには、十分な理由が必要だと思います。
1000 台のデスクトップをデータベースに直接接続できるシステム アーキテクチャは適切ですか?
いいえ、明らかにそうではありません。おそらく悪い例ですが、私が言おうとしていた点は明らかだと思います。DBA はデータベース インフラストラクチャの世話をします。