15

からデータを返すときDataReaderは、通常、 の序数参照を使用しDataReaderて関連する列を取得します。

if (dr.HasRows)         
   Console.WriteLine(dr[0].ToString());

また

if (dr.HasRows)         
   Console.WriteLine(dr.GetString(0));

また

if (dr.HasRows)         
   Console.WriteLine((string)dr[0]);

私は常にこれを実行してきました。これは、早い段階で、dr["ColumnName"]またはより洗練された方法でインデックスを作成するとパフォーマンスが低下することを知らされたためです。

ただし、データ エンティティへのすべての参照がますます強く型付けされるようになっている一方で、私はこれに違和感を感じています。上記が をチェックしないことも承知していDBNullます。

からデータを返す最も堅牢な方法は何DataReaderですか?

4

6 に答える 6

25

この状況で双方を議論することは可能です。他の人がすでに指摘しているように、名前を使用すると読みやすくなり、基になるデータベースの列の順序を変更しても壊れません。しかし、序数を使用すると、基になるデータベースの列名を変更しても壊れないという利点があると主張する人もいるかもしれません。ただし、私は前者の引数を好み、列名の読みやすさの引数は、一般に2番目の引数よりも優先されると思います。また、名前に関する追加の議論は、エラーを「自己検出」できるということです。誰かがフィールド名を変更した場合、間違ったフィールドを読み取っているときに動作しているように見えるという微妙なバグよりも、コードが破損する可能性が高くなります。

当たり前のように見えますが、自己検出エラーと通常のパフォーマンスの両方を備えた使用例について言及する価値があるかもしれません。SQLでSELECTリストを明示的に指定する場合、コード内のステートメントが順序を保証するため、序数を使用しても問題はありません。

SELECT name, address, phone from mytable

この場合、データにアクセスするために序数を使用することはかなり安全です。誰かがテーブル内のフィールドを移動するかどうかは関係ありません。また、誰かが名前を変更すると、SQLステートメントの実行時にエラーが発生します。

そして最後のポイント。作成を手伝ったプロバイダーでテストを実行しました。テストでは100万行を読み取り、各レコードの「lastname」フィールドにアクセスしました(値と比較して)。の使用量はrdr[“lastname”]、処理に3301ミリ秒rdr.GetString(1)かかりましたが、2640ミリ秒かかりました(約25%の高速化)。この特定のプロバイダーでは、名前のルックアップは、ソートされたルックアップを使用して名前を序数に変換します。

于 2010-05-24T15:45:39.593 に答える
15

文字列名の検索は、序数の呼び出しよりもはるかにコストがかかりますが、序数をハードコーディングするよりも保守しやすく、「脆弱」ではありません。だからここに私がやっている方法があります。それは両方の長所です。序数の値を覚えたり、列の順序が変わっても気にしたりする必要はありませんが、序数を使用することでパフォーマンス上の利点が得られます。

var dr = command.ExecuteQuery();
if (dr.HasRows)
{
    //Get your ordinals here, before you run through the reader
    int ordinalColumn1 = dr.GetOrdinal("Column1");
    int ordinalColumn2 = dr.GetOrdinal("Column2");
    int ordinalColumn3 = dr.GetOrdinal("Column3");

    while(dr.Read())
    {
        // now access your columns by ordinal inside the Read loop. 
        //This is faster than doing a string column name lookup every time.
        Console.WriteLine("Column1 = " + dr.GetString(ordinalColumn1);
        Console.WriteLine("Column2 = " + dr.GetString(ordinalColumn2);
        Console.WriteLine("Column3 = " + dr.GetString(ordinalColumn3);
    }
}

注: これは、適切な数の行があると予想されるリーダーに対してのみ意味があります。GetOrdinal()呼び出しは余分でありGetString(int ordinalNumber)、ループ内での呼び出しによる節約の合計が呼び出しのコストよりも大きい場合にのみ、自費で支払うことができますGetOrdinal

編集:この質問の2番目の部分を見逃しました。DBNull 値に関しては、その可能性に対処する拡張メソッドを書き始めました。例:dr.GetDatetimeSafely() これらの拡張メソッド内では、期待値が返されると確信するために必要なことは何でもできます。

于 2010-05-22T11:12:11.490 に答える
4

コードを読む方がすっきりしているという理由だけで、私は常に文字列名のアプローチを採用しています。インデックスを列名に精神的に解析しなければならないのは恐ろしいことです。

于 2010-05-21T13:13:16.573 に答える
3

名前によるデータ リーダーのインデックス作成は、少しコストがかかります。これには主に 2 つの理由があります。

  • 一般的な実装では、数値インデックスを使用するデータ構造にフィールド情報を格納します。名前を数値に変換するには、マッピング操作を実行する必要があります。
  • 一部の実装では、名前に対して 2 パスのルックアップが行われます。最初のパスでは、大文字と小文字を区別してフィールド名を一致させようとします。そのパスが失敗すると、大文字と小文字の区別をオフにして 2 番目のパスが開始されます。

ただし、ほとんどの場合、名前でフィールドを検索することによって発生するパフォーマンスの低下は、データベースがコマンドを実行するのにかかる時間よりもはるかに小さくなります。パフォーマンスの低下によって、名前インデックスと数値インデックスのどちらを選択するかを決定しないでください。

わずかなパフォーマンスの低下にもかかわらず、私は通常、2 つの理由から名前のインデックス作成を選択します。

  • コードが読みやすくなります。
  • コードは、結果セットのスキーマの変更に対してより寛容です。

名前のインデックス作成によるパフォーマンスの低下が問題になっていると思われる場合 (コマンドの実行速度は速いが、多くの行が返される可能性があります)、数値インデックスを名前で 1 回検索し、それを保存して、残りの行に使用します。

于 2010-05-21T14:43:32.197 に答える
2

フィールド名をハードコーディングしたためにアプリケーションの再コンパイルが必要になる、基礎となるデータベースからのフィールド名の変更を回避するためだけであれば、インデックス付きフィールドがより良いアプローチだと思います。

フィールドごとに、null を手動で確認する必要があります。

var dr = command.ExecuteQuery();

if (dr.HasRows) {
    var customer = new Customer();
    // I'm assuming that you know each field's position returned from your query.
    // Where comes the importance to write all of your selected fields and not just "*" or "ALL".
    customer.Id = dr[0] == null || dr[0] == DBNull.Value ? null : Convert.ToInt32(dr[0]);
    ...
}

それに加えて、リフレクションを使用して、この「GetData()」メソッドをより汎用的にし、typeof(T) を提供して、適切な型の適切なコンストラクターを取得することができます。各列の順序へのバインドは、回避したい唯一のことですが、この場合は価値があります。

于 2010-05-21T13:19:40.757 に答える
0

序数の問題は、列名を使用する場合とは異なり、列の順序が変更され、DataReader のコンシューマー コードを変更する必要がある場合です。

序数または列名を使用した場合にパフォーマンスが向上するとは思いません。それは、ベスト プラクティスとコーディング標準、およびコードの保守性に関するものです。

于 2010-05-21T13:12:33.820 に答える