2012-07-16 4 views
10

これは「ベストプラクティス」の問題です。私たちはこの話題について内部的な議論をしており、より多くの読者から意見を得たいと考えています。SQLを使用してJSON文字列を返す

通常の列と行を使用して従来のMS SQL Serverテーブルにデータを保存する必要があります。私は時々ウェブアプリケーションにDataTableを返す必要があり、それ以外の時にはJSON文字列を返す必要があります。

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

DataTableまたはJSON文字列を選択的に返すようにストアドプロシージャを改訂することを検討しています。私は単に@isJson bitパラメータをSPに追加します。

ユーザーではなく、テーブルの列を望んでいた場合、SPはこのようなクエリを実行しますが:もちろん

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

、ユーザー缶:

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

これは、次のようなものを作成しますまた、@isJsonパラメーターにfalseを渡してテーブルを取得します。

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

私の質問は以下のとおりです。

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

中間層の詳細を教えてください。何がそんなに長くかかりますか?コンパイルされたコードですか?レコードセットをJSONに変換するアプリケーションを書くことは非常に可能であり、十分な性能を備えているはずです。 – ErikE

+2

あなたの特殊文字を適切にエスケープすると仮定すると、これは実行可能です...しかし...あなたはどうですか? SQL Serverはひどい文字列解析エンジンであり、比較的効率的な方法で常に準拠XMLを吐き出すことができるビルトインXMLエンジンを持っています。 –

+1

@ErikEほとんどのテーブルはjsonに非常に迅速に変換されます。これはFullCalendar用のテーブルを解析しているために発生しました。真ん中の解析ではテーブルを取り、フィールドと行を循環させて文字列を構築します。おそらく真ん中でいくつかのことを修正してより速く実行することはできますが、SQLを実行することでプロセスの余計なステップを避けることができればどうでしょうか? – davids

答えて

8

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

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

  • あなたは、この機能を可能にするには最高の場所です、あなたのアプリケーションの部品と部品の新しいバージョンを展開する場合は?

  • データベース(およびすべてのストアドプロシージャ)を復元する必要があると、何かに悪影響を及ぼしますか? Webフロントエンドの新しいバージョンをデプロイする場合、JSON変換がデータベースに結びついて問題を引き起こしますか?

  • 文字を正しくエスケープしますか?あなたは何日も通っていますか?日付の文字列はどのような形式になり、相手側の実際のDateオブジェクトに変換されるのですか(必要な場合)?

  • ユニットテスト(および自動テストで)が正しく動作していることを確認しますか?あなたはどのように回帰テストを行いますか?

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

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

中間層に翻訳を実行させることで作業が複雑になっているように見えるかもしれませんが、長期的にはより良くなると約束します。あなたの製品がスケールアウトして大規模に並行し始めるなら、いつでも安価に多くのWebサーバーを投げられるかもしれませんが、データベースサーバーのリソース飽和を簡単に修正できません。だから、DBをもっとうまく動作させる必要はありません。これはデータアクセスレイヤーであり、プレゼンテーションレイヤーではありません。可能な限りの作業を可能にします。他のすべてのコードを書く。あなたは喜んだでしょう。 Webアプリケーション

  1. に文字列処理のための

    スピードのヒントは、あなたのウェブ文字列の連結コードはSchlemiel the Painter's Algorithmに罹患していないことを確認してください。 JSONが生成される(Response.Write)ように出力バッファに直接書き込むか、適切なStringBuilderオブジェクトを使用するか、配列にJSONの部分を書き込み、後でJoin()します。長めの長い文字列にプレーンなバニラ連結を繰り返してはいけません。

  2. オブジェクトの参照をできるだけ少なくします。あなたのサーバー側の言語はわかりませんが、ASP Classicの場合は、フィールド名を使用しないでください。変数の各フィールドへの参照を取得するか、少なくとも整数フィールドインデックスを使用します。ループ内でその名前に基づいてフィールドを参照解除すると、パフォーマンスは(かなり)悪化します。
  3. 事前に構築されたライブラリを使用します。実証済みの真の図書館を利用できるときは、自分のものを転がしてはいけません。パフォーマンスは自分のものと同等かそれ以上でなければなりません。最も重要なのはです。です。
  4. これを行うのに時間を費やす場合は、今持っているものだけでなく、すべてのレコードセットの変換を処理するために十分抽象化してください。
  5. コンパイル済みコードを使用します。コンパイルされていても解釈されていなくても、常に最速のコードを得ることができます。 JSON変換ルーチンが本当にボトルネックであることがわかっているなら(そして、これを実際に証明しなければならないと推測しないでください)、コードをコンパイルされたものに入れてください。
  6. 文字列の長さを短くします。これは大きなものではありませんが、可能であれば多くの文字の代わりに1文字のjsonの名前を使用してください。巨大なレコードセットの場合、このになり、両端の節約になります。
  7. GZippedであることを確認してください。これはサーバー側の改善ではありませんが、完成せずにJSONのパフォーマンスについて言及することはできませんでした。 JSON

渡す日付は、私がお勧めすることは(フォローする仮想レコードの構造を定義する、JSON自体に)別のJSONスキーマを使用することです。このスキーマは、「レコードセット」のヘッダーとして送信することができます。また、ページに埋め込んでおくこともできます(ベースのJavaScriptファイルに含まれています)ので、毎回送信する必要はありません。次に、JSON解析コールバック(または最終結果オブジェクトのポストコールバック)で、スキーマ内で現在の列を調べ、必要に応じて変換を行います。 ECMAScript 5 strict modeでは、データ形式を変更せずにコードを簡素化できるため、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

+1

+1私よりも優れています。私は私の答えを取り除きます。 –

+1

あなたはいくつかの非常に良い点を挙げ、説得力のある議論をします。ほとんどの状況では適切な解決策ではないかもしれません。上記の問題については、日付やその他の回避策などの標準的な形式を計画していましたが、それはまさにその回避策でした。 MSは、XML形式を提供するようなJSON形式を追加するだけです。 – davids

+0

@davids JSONの日付を渡すことについての私の追加情報は役に立ちましたか? – ErikE

3

私はあなたがJSON.netを使用し、varchar型を返すCLRのSQL関数を作成しようとすることができ、あなたがやっていることな方法(contatenating)

しないだろう。

の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)); 
    } 
} 
+0

中間層で行うよりも、CLR SQL関数でjson.netをどのように使用していますか?私はCLR SQL関数を使用したことがないので、これは愚かな質問かもしれませんが、結果は同じではありませんか? – davids

+0

オブジェクトからSELECT MyDb.dbo.ConvertToJson(id)のような操作を行うことができますので、直接DB呼び出しが可能です。 – turtlepick

+0

JSONは特に日付と時刻のフィールドで扱いにくいかもしれないことを覚えておいてください(特殊文字とそのすべてを...) – turtlepick

関連する問題