10

これは「ベストプラクティス」の質問です。私たちはこのトピックについて社内で話し合っており、より多くの聴衆から意見を聞きたいと思っています。

MS SQL Server通常の列と行を持つ従来のテーブルにデータを保存する必要があります。DataTableWebアプリケーションにを返す必要がある場合もあれば、JSON文字列を返す必要がある場合もあります。

現在、テーブルを中間層に戻し、JSON文字列に解析します。これはほとんどの部分でうまく機能しているように見えますが、大きなデータセットでは時間がかかることがあります(データを解析し、テーブルを返さない)。

DataTableまたは文字列を選択的に返すようにストアドプロシージャを修正することを検討していJSONます。@isJson bitSPにパラメータを追加するだけです。

ユーザーがテーブルの代わりに文字列を必要とする場合、SPは次のよ​​うなクエリを実行します。

DECLARE @result varchar(MAX)
SELECT @result = COALESCE(@results ',', '') + '{id:"' + colId + '",name:"' + colName + '"}'
    FROM MyTable
SELECT @result

これにより、次のようなものが生成されます。

{id:"1342",name:"row1"},{id:"3424",name:"row2"}

もちろん、ユーザーは@isJsonパラメーターにfalseを渡すことによってテーブルを取得することもできます。

データストレージは影響を受けず、既存のビューやその他のプロセスも影響を受けないことを明確にしたいと思います。これは、一部のストアドプロシージャの結果のみに対する変更です。

私の質問は次のとおりです。

  1. 大規模なアプリケーションでこれを試した人はいますか?もしそうなら、結果はどうでしたか?
  2. このアプローチでどのような問題が発生しましたか/予想しますか?
  3. この方法でストアドプロシージャを変更したり、中間層で文字列を解析したりする以外に、SQL ServerでテーブルからJSONに移動するためのより高速な方法はありますか?
4

2 に答える 2

8

個人的には、この種の文字列操作に最適な場所は、関数を備え、コンパイル可能な完全に表現力のある言語のプログラムコードであると思います。T-SQLでこれを行うのは良くありません。プログラムコードは、適切なエスケープを行う高速関数を持つことができます。

物事について少し考えてみましょう:

  • アプリケーションのパーツの新しいバージョンをデプロイする場合、この機能を配置するのに最適な場所はどこですか?

  • データベース(およびそのすべてのストアドプロシージャ)を復元する必要がある場合、それは何かに悪影響を及ぼしますか?新しいバージョンのWebフロントエンドをデプロイする場合、データベースに関連付けられているJSON変換によって問題が発生しますか?

  • どのように文字を適切にエスケープしますか?日付を送っていますか?日付文字列はどのような形式になり、もう一方の端で実際のDateオブジェクトにどのように変換されますか(必要な場合)?

  • それが正しく機能していることを証明するために、どのようにユニットテストしますか(そして自動テストで!)?どのように回帰テストしますか?

  • SQLServerUDFは非常に遅くなる可能性があります。遅い関数を使用することに満足していますか、それともSQLコードへのスピードハックのためにReplace(Replace(Replace(Replace(Value, '\', '\\'), '"', '\"'), '''', '\'''), Char(13), '\n')?Unicode\u\xエスケープについてはどうですか?に分割'</script>'してみ'<' + '/script>'ませんか?(これは当てはまらないかもしれませんが、JSONの使用方法によっては当てはまるかもしれません。)T-SQLプロシージャはこれをすべて実行し、さまざまなレコードセットで再利用できますか、それとも毎回それぞれに書き換えますか? JSONを返す必要があるSP?

  • JSONを返す必要があるSPは1つだけかもしれません。今のところ。いつか、もっとあるかもしれません。次に、バグを見つけた場合は、2か所で修正する必要があります。または5つ。以上。

中間層に翻訳を行わせることで物事をより複雑にしているように見えるかもしれませんが、長期的にはより良くなることをお約束します。製品がスケールアウトして超並列になり始めたらどうなるでしょうか。いつでも安価にWebサーバーを追加できますが、データベースサーバーのリソースの飽和状態を簡単に修正することはできません。したがって、DBに必要以上の作業を行わせないでください。これはデータアクセス層であり、プレゼンテーション層ではありません。可能な限り最小限の作業を行うようにします。他のすべてのコードを記述します。あなたはあなたがしたことをうれしく思います。

Webアプリケーションでの文字列処理の速度に関するヒント

  1. Web文字列連結コードがSchlemielthePainter'sAlgorithmの影響を受けていないことを確認してください。JSONの生成時に出力バッファーに直接書き込む(Response.Write)か、適切なStringBuilderオブジェクトを使用するか、JSONの一部を配列に書き込んで後でJoin()します。長くて長い弦に単純なバニラ連結を何度も行わないでください。
  2. オブジェクトの間接参照は可能な限り少なくします。サーバー側の言語はわかりませんが、ASPクラシックの場合は、フィールド名を使用しないでください。変数内の各フィールドへの参照を取得するか、少なくとも整数のフィールドインデックスを使用してください。ループ内の名前に基づいてフィールドを間接参照すると、パフォーマンスが(はるかに)低下します。
  3. ビルド済みのライブラリを使用します。実証済みの真のライブラリを使用できる場合は、自分で作成しないでください。パフォーマンスは自分と同等かそれ以上である必要があり、(最も重要なことですが)テストされ修正されます。
  4. これを行うのに時間を費やす場合は、現在のレコードセットだけでなく、任意のレコードセットの変換を処理できるように抽象化してください。
  5. コンパイルされたコードを使用します。コンパイルされるとき、解釈されるのではなく、常に最速のコードを取得できます。JSON変換ルーチンが本当にボトルネックであることがわかった場合(そして、これを実際に証明する必要があります。推測しないでください)、コードをコンパイルされたものに取り込みます。
  6. 文字列の長さを短くします。これは大きなものではありませんが、可能であれば、多文字ではなく1文字のjson名を使用してください。巨大なレコードセットの場合、これ両端での節約になります。
  7. Gzipで圧縮されていることを確認します。これはサーバー側の改善ではありませんが、完全でなければJSONのパフォーマンスについては言及できませんでした。

JSONで日付を渡す

私がお勧めするのは、別のJSONスキーマを使用することです(JSON自体で、従う仮想レコードセットの構造を定義します)。このスキーマは、後続の「レコードセット」にヘッダーとして送信することも、ページに既にロードされている(ベースのJavaScriptファイルに含まれている)ため、毎回送信する必要はありません。次に、JSON解析コールバック(または最終結果オブジェクトのポストコールバック)で、スキーマで現在の列を探し、必要に応じて変換を行います。ECMAScript 5の厳密モードでは、日付のサポートが向上し、データ形式を変更せずにコードを簡略化できるため、ISO形式の使用を検討できます(単純なオブジェクト検出により、このコードをサポートするすべてのブラウザーで使用できます。それ):

日にち

日付は、ISO形式の日付の解析と出力の両方ができるようになりました。

Dateコンストラクターは、最初にISO形式であるかのように日付を解析しようとし、次に、受け入れる他の入力に移動します。

さらに、日付オブジェクトに、日付をISO形式で出力する新しい.toISOString()メソッドが追加されました。var date = new Date( "2009-05-21T16:06:05.000Z");

print(date.toISOString()); // 2009-05-21T16:06:05.000Z

于 2012-07-16T21:24:15.430 に答える
3

私はあなたがしているようにはしません(続き)

JSON.netを使用してvarcharを返すCLRSQL関数を作成してみてください。

SQL CLR関数の作成方法についてはこちらをご覧ください:http: //msdn.microsoft.com/en-us/library/w2kae45k (v = vs.80).aspx

このようなもの(テストされていないコード)

[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString MyFunctionName(int id) {
    // Put your code here (maybe find the object you want to serialize using the id passed?)
    using (var cn = new SqlConnection("context connection=true") ) {
        //get your data into an object
        var myObject = new {Name = "My Name"};
        return new SqlString(Newtonsoft.Json.JsonConvert.SerializeObject(myObject));
    }
}
于 2012-07-16T20:56:18.227 に答える