2011-08-24 28 views
19

主にC#を書く開発者として、私はC#コードを書くときにいくつかの良い方法を採用しました。ストアドプロシージャを書くときに、ストアドプロシージャコードにそれらのプラクティスを適用することができません。ストアドプロシージャを構築するベストプラクティス

いくつかの機会に私は悪夢のストアドプロシージャコード、最初の3つまたは4つのテンポラリテーブルを設定し、お互いを主に呼び出すストアドプロシージャのレイヤーを継承しています。実際の作業は完了せず、ほんの数行のコードが必要です。最後に、最終的なストアドプロシージャ、3000-5000行のSQLコードの大きなモンスターが呼び出されます。そのコードには通常、コードの複製、複雑な制御フロー(別名スパゲッティ)、お互いの後ろに積み重ねる方法があります。これは、作業が始まり、終了する場所が明確に分離されていません。除数としてのコメント)。

私はまた、中間の一時テーブルから選択したコメント付きのselectステートメントの使用に気付きました。選択はデバッグの目的でオンに戻すことができますが、返された結果セットの特定の順序を期待する呼び出しコードの前に削除する必要があります。

明らかに私の仲間のチームメイトは、良いSQL文章の練習ができていないことを明らかに示しています。

...(ここでは本当の疑問があります)...モジュール式の保守可能なストアドプロシージャを書くための良いプラクティスは何ですか?

本物のプラクティスと書籍/ブログへの参照はどちらも歓迎します。特定のタスクに役立つツールとツールだけでなく、

、私はアセンブリを使用、私はC#で良いプラクティス

  • モジュール化とカプセル化(一時テーブルを介した手続き通信行くには本当に道保存されている?)
    • を発見していない一部の地域をまとめたクラスますこれを実現するアクセス修飾子で装飾されたメソッド
  • のデバッグ/テスト(デバッグのターゲットを変更するよりも良い?)
    • デバッグツールは?
    • トレースをデバッグしますか?
    • テストフィクスチャ? C#でコードを使用してコード
      • の構造をコード/ロジック/データ/制御フローを強調
    • Iはリファクタリング、それぞれただ一つの論理タスクを行い小さい方法を抜け出します。
  • コードの重複

は、ほとんど私がDBMSとしてSQL Serverが発生したが、他のDBMSの機能を指摘とらわれない答えも回答DBMS:上記の例ではその助けESも歓迎されています。

いくつかの背景:私が遭遇した大規模なストアドプロシージャの大部分は、大規模なテーブルからいくつかのサマリー値を作成するというレポート作成シナリオにあります。しかし、ある例外テーブルにある値の一部を除外する必要がある場合、昨年と比較して、まだ完成していないテーブルの値をいくつか追加してください(製品を変更する醜いコードを想像できますか?年間?)など

+2

SCMでストアドプロシージャを使用できないことと同様に、最も必要で明白な使用法(トリガなど)以外はすべて避けています。ビジネスロジックをビジネスレイヤー(.NET)に保ち、そのためのデータベース(データベース)を使用します。 – gahooa

+0

理想的には、ストアドプロシージャは他のストアドプロシージャを呼び出すべきではありません。それがBL層のためのものです。残念ながら、ネストされたSPコールでいっぱいのデータベースを既に持っているなら、その感情は本当に役に立ちません。現在のモデルをよりメンテナンス可能にする方法や、ベストプラクティスをより良くフォローするためにシステムをリファクタリングする方法に関するアドバイスを探していますか? –

+0

@gahooa大量のコードベースを継承したり、膨大な量のデータを格納しているときなど、ストアドストアでは多かれ少なかれ、.NETでできるだけ多くのものを置いています(これは私のホームアリーナです)。手続き –

答えて

13

多くの複雑なストアドプロシージャを書きます。

ストアドプロシージャで動的SQlを使用しないでください。多くのパラメータを必要とするかもしれないし、そうでないかもしれないサーチプロシージャを実行しているのでなければ(現在、それは現在最良のソリューションの1つです)。 procで動的SQlを使用する必要がある場合は、常にデバッグ入力パラメータがあり、デバッグパラメータが設定されている場合は、作成したSQL文を実行するのではなく作成して出力します。これにより、数時間のデバッグ時間を節約できます!

proc(insert/update/delete)で複数のアクションクエリを実行する場合は、Cacthブロックの試行とトランザクション処理を使用してください。テストパラメータを入力パラメータに追加し、テストパラメータが1に設定されている場合は、常にトランザクション全体をロールバックします。テストモードでロールバックする前に、私はデータベースに行っていると思っていることが、実際に行ったことを確認するために、影響を受けるテーブルの値を返すセクションを通常持っています。あるいは、以下に示すようなチェックをすることもできます。これは@testパラメータを持っていれば、現在コメントされている選択項目の周りに次のコードを入れる(とコメントを外す)のと同じくらい簡単です。

If @test =1 
Begin 
Select * from table1 where field1 = @myfirstparameter 
End 

これで、テストするたびにコメントやコメントを外す必要はありません。

@testまたは@debuigは、常にデフォルト値の0に設定し、リストの最後に配置する必要があります。そうすることで、それらを追加しても、procの既存の呼び出しを壊すことはありません。

挿入/更新/削除を実行しているprocsのロギングおよび/またはエラーロギングテーブルを持つことを検討してください。テーブル変数にステップやエラーを記録すると、ロギングテーブルに挿入されるロールバックの後でも使用できます。複雑なprocのどの部分が失敗したのか、そのエラーが何であったかを知ることは、後で非常に重要なことです。

可能であれば、ストアドプロシージャをネストしないでください。ループ内で複数のレコードを実行する必要がある場合は、格納されているprocをテーブル値のパラメータに置き換え、procを個別のレコード形式ではなくセットベースで実行するように設定します。これは、テーブル値のパラメータに1つのレコードまたは複数のレコードがある場合に機能します。

多くのサブクエリまたは派生テーブルで複雑な選択がある場合は、代わりにCTEを使用することを検討してください。相関ベースのサブクエリまたはカーソルをリファクタリングして、セットベースのコードをよりよく実行します。常に1組のレコードではなく、データのセットで考える。

考えられる状況では、ビューをネストしないでください。パフォーマンスの低下は、保存された開発時間のわずかな量よりもはるかに悪いです。そして、私を信じて、入れ子にされたビューは、変更がビューのチェーンの中で最も遠くにある必要がある場合、メンテナンス時間を節約しません。

すべて格納されprocsの(および他のデータベース・コード)は、ソースコントロールにあるべきです。

テーブル変数は、小さなデータセットのために良いですが、一時テーブル(#または##ステージングないテーブルで始まる本当のものは)大きなデータセットでのパフォーマンスのために改善することができます。一時テーブルを使用している場合は、不要になったときに削除してください。グローバルな一時表を使用しないようにしてください。

パフォーマンスSQLを書く方法を学んでください。通常、SQLより優れたパフォーマンスを発揮するSQLを作成するのは簡単です。これは、一度、その技術を知っていなくても可能です。複雑なストアドプロシージャを書くと、どのテクニックが他のテクニックより優れているか分からないという言い訳はありません。あなたの質問が確実であることを確認する方法を学んでください。カーソル、相関サブクエリ、スカラー関数、行単位で実行される行を避けてください。

+0

REネストされたビュー:ネストされたビューを持つシステムを継承し、SQL Serverのパフォーマンス調査で問題は発生しませんでした。たぶんこれは問題でしたが、MSSQL 2008以降では、クエリプランナーはかなりスマートで効果的にビューをインライン化します。 –

+0

この問題が発生したサーバーは、SQl Server 2008サーバーでした。 Tは、どのように書かれているかに依存するかもしれない。私たちが持っていたもう一つの問題は、見解が馬鹿げて維持することが難しくなり、最終的にはシステムの厳しい限界にぶつかってしまい、ビューがまったく動かなくなってしまったことです。私が言ったところでは、他のビューを呼び出すためにビューを使用するのは悪い習慣です。 – HLGEM

5

一時テーブル経由の通信は、時には巨大なコードの匂いです。このようなプロシージャは、相互に干渉することなくユーザーによって実行されることはよくありません(異なるプロシージャの入出力に対して一時テーブル名を再使用し、再作成されない場合や、2つの異なるテーブルスキーマ)。問題を解決するのは難しいかもしれません。あらゆる機能のように、必要なときに使用し、より良い選択肢は存在しません。実テーブルを一時的に使用することも問題になります。

SQL Serverでデータを互いに渡す(パラメータを超える)ストアドプロシージャは問題があります。現在、テーブル値のパラメータがあり、以前はprocsで行われていたことの多くは、インラインのテーブル値関数または(通常はそれ以上の)複数の値を持つテーブル値関数で処理できるようになりました。

SQL Serverでは、大きな行セットでスカラー関数と複数ステートメントのテーブル値関数を頻繁に使用しないようにしてください。これらは非常にうまく実行されないため、C#で明白に見えるモジュラー手法は実際には適用されません。

Ken Henderson's Guru's Guide to SQL Server Stored Procedures - 2002年に公開されていることをお勧めしますが、依然としてデータベースアプリケーションの設計に関する豊富な有用な情報があります。

+0

多分私は誤解していますが、問題のない複数のユーザーで一時テーブルを実行できます。しかし、おそらくあなたは特別な事件について話していますか? –

+0

@マークSQLDev正しいですか - ローカルの一時テーブルは接続ローカルです - 私は一時テーブル(およびテーブル変数)がデバッグするのが難しいです。もちろん、マテリアライズするものと、オプティマイザに任せるのではなく、いつ決定するのですか。そして、ネーミングが衝突しないようにネーミングを追跡する必要があります。 –

2

これは良い質問です。私はC#で慣れ親しんだベストプラクティスの方法でSQLのように見えます。

共通テーブルExpresionsは、ストアドプロシージャ内のクエリを分離するために素晴らしいですが、あなたは一度だけそれらを使用することができます!それはビューを定義することにつながりますが、カプセル化が失われてしまいます。

1つのストアドプロシージャから結果セットを使用すると、テーブル値関数を作成するために誘惑されるかもしれないので、他に使用することは非常に困難です。これにより、管理者の負担が増え、機能として「もう一度」機能を呼び出すプロシージャとして「二度」を書き込む必要があります。それ以外の場合は、プロシージャであるかどうかに応じてDALとは異なるインタフェースを使用します。

このすべて

は関係が複雑であるときに、データベースといくつかの、孤立し、クエリで(お互いを呼び出すことはありません)、単純なCRUDストアドプロシージャに固執して、時間をかけて、私を起こしています。より多くのBIのもの。他のすべてはBLLにあります。

物理的には、SQL関数または、彼らは周りを公転テーブルで別々のファイルに分離し、ソース管理で管理されています。

SELECT *を避けて列を指定するのは避けてください。これは、テーブルを変更してすべてのprocsに触れないときに実行時の問題からあなたを救います。はい、procsのための再コンパイルがありますが、特にビューが関与している場合は、いくつか見逃してしまいます。さらに、SELECT *はほとんどの場合、実際に必要とするより多くの列を返します。これは帯域幅の無駄です。

+0

SQLのベストプラクティスは、C#で慣れ親しんだものとは決して同じではありません。リレーショナルの世界でC#のベストプラクティスを使用しようとすると、悪い結果をもたらすデータベースの原因の1つになります。データベースは、保守性が向上しないようにパフォーマンスを最大化するように設計されています。 – HLGEM

+0

そして、CTEの代わりに一時テーブルを使用することができます。これは、procで複数回使用する必要がある場合です。 – HLGEM

関連する問題