2012-07-16 47 views
10

這是一個「最佳實踐」問題。我們正在就這個話題進行內部討論,並希望得到更多聽衆的意見。使用SQL返回JSON字符串

我需要將數據存儲在具有普通列和行的傳統MS SQL Server表中。我有時需要返回一個DataTable到我的web應用程序,而其他時間我需要返回一個JSON字符串。

目前,我將表返回到中間層並將其解析爲JSON字符串。這似乎大部分工作得很好,但偶爾會花費一些時間處理大數據集(解析數據,不返回表)。

我在考慮修改存儲過程以選擇性返回DataTableJSON字符串。我會簡單地向SP添加一個@isJson bit參數。

如果用戶想要的字符串,而不是表中的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"} 

當然,用戶可以也可以通過將false傳遞給@isJson參數來獲取表格。

我想明確一點,數據存儲不受影響,也不存在任何現有的視圖和其他過程。這只是對一些存儲過程的結果的改變。

我的問題是:

  1. 有沒有人在一個大的應用程序嘗試呢?如果是這樣,結果如何?
  2. 你看到了什麼問題/你會用這種方法期待什麼?
  3. 除了以這種方式修改存儲過程或解析中間層中的字符串之外,是否有更快的方式從SQL Server中的錶轉換爲JSON?
+0

告訴我們更多關於中間層的信息。什麼花了這麼久?它是編譯代碼嗎?應該很有可能編寫一個將記錄集轉換爲JSON並具有相當足夠性能的應用程序。 – ErikE 2012-07-16 20:52:13

+2

假設你正確地逃避你的特殊字符,這是可行的......但是......你爲什麼? SQL Server是一個糟糕的字符串解析引擎,並且您有一個內置的XML引擎,可以始終以相對有效的方式吐出符合要求的XML。 – 2012-07-16 20:53:49

+1

@ErikE大多數表格都很快轉換成json。這只是因爲我們正在解析FullCalendar表。中間解析簡單地接受表並使用foreach循環遍歷字段和行來構建字符串。我們可以在中間修復一些東西以使其更快地執行,但是如果我們可以通過SQL來避免額外的步驟,那麼......爲什麼不呢? – davids 2012-07-16 20:54:56

回答

8

我個人認爲對於這類字符串操作的最佳位置是在程序代碼一個充分表達的語言,具有功能並且可以編譯。在T-SQL中這樣做不好。程序代碼可以具有快速的功能,可以進行適當的轉義。

讓我們想想事情有點:

  • 在部署部件和應用程序的作品的新版本,其中這個功能最好的地方是什麼?

  • 如果您必須恢復您的數據庫(及其所有存儲過程)是否會對任何事情產生負面影響?如果您正在部署Web前端的新版本,JSON轉換是否會導致數據庫出現問題?

  • 如何正確地轉義字符?你是否發送任何日期?日期字符串的格式是什麼,以及如何將它們轉換爲另一端的實際日期對象(如果需要的話)?

  • 你將如何測試它(並與自動化測試!)以證明它工作正常?你將如何迴歸測試它?

  • SQL Server UDF可能非常慢。你是否滿足於使用一個緩慢的函數,或者爲了加速你的SQL代碼,比如Replace(Replace(Replace(Replace(Value, '\', '\\'), '"', '\"'), '''', '\'''), Char(13), '\n')? Unicode呢,\u\x轉義麼?將'</script>'拆分爲'<' + '/script>'怎麼樣? (也許這並不適用,但也許它的確如此,具體取決於您如何使用JSON。)您的T-SQL過程是否可以完成所有這些工作,並且可以重複使用不同的記錄集,或者每次都將其重寫SP你需要返回JSON?

  • 您可能只有一個SP需要返回JSON。目前。有一天,你可能會有更多。那麼如果你發現一個bug,你必須在兩個地方修復它。或五。或者更多。

看起來你正在讓中間層做翻譯變得更加複雜,但我向你保證,從長遠來看它會更好。如果您的產品擴展並開始大規模並行 - 您可以隨時以更便宜的價格投放更多的Web服務器,但是您無法如此輕鬆地修復數據庫服務器資源飽和問題!所以不要讓DB做更多的工作。它是一個數據訪問層,而不是表示層。儘量減少工作量。編寫其他代碼。你會很高興你做到了。

絃樂超速提示在Web應用程序

  1. 處理確保您的網絡字符串連接代碼不會Schlemiel the Painter's Algorithm吃虧。當生成JSON時(Response.Write)直接寫入輸出緩衝區,或者使用正確的StringBuilder對象,或者將JSON的各部分寫入數組並稍後加入()。不要將簡單的香草串聯到一個更長和更長的字符串。
  2. 取消引用對象儘可能少。我不知道你的服務器端語言,但如果它恰好是ASP Classic,不要使用字段名 - 要麼獲得對變量中每個字段的引用,要麼至少使用整數字段索引。在循環內根據其名稱取消引用字段會(性能)更差。
  3. 使用預先構建的庫。當你可以使用一個久經考驗的圖書館時,不要推出自己的圖書館。性能應該與您自己相等或更好(最重要的是)測試正確
  4. 如果您打算花時間做這件事,請將其抽象得足以處理轉換任何記錄集,而不僅僅是您現在擁有的記錄集。
  5. 使用編譯後的代碼。編譯時總是可以獲得最快的代碼,而不是解釋。如果您確定JSON轉換例程確實是瓶頸(並且您必須證明這是真實的,請不要猜測),然後將代碼轉換爲編譯好的代碼。
  6. 減少字符串長度。這不是一個大問題,但是如果可能的話,使用單字母json名稱而不是多字母。對於一個巨大的記錄這加起來節省兩端。
  7. 確保它被GZipped。這不是一個服務器端的改進,但是我沒有完整地提到JSON性能。

在JSON

傳遞日期是什麼,我建議是(以JSON本身定義虛擬記錄的結構遵循)使用單獨的JSON模式。這個模式可以作爲標題發送到「記錄集」中,也可以已經加載到頁面中(包含在基本JavaScript文件中),因此不必每次都發送。然後,在您的JSON解析回調(或最終生成對象的回調後)中查找當前列的模式,並根據需要進行轉換。您可以考慮使用ISO格式,因爲在ECMAScript 5 strict mode中應該有更好的日期支持,並且您的代碼可以簡化而不必更改數據格式(並且簡單的對象檢測可以讓您使用此代碼用於支持它的任何瀏覽器):

日期

日期現在既能解析和輸出ISO格式的日期。

Date構造函數現在試圖解析日期,就好像它是ISO格式的,首先,然後移動到它接受的其他輸入。

此外,日期對象現在有一個新的.toISOString()方法,以ISO格式輸出日期。 var date = new Date(「2009-05-21T16:06:05.000Z」);

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

+1

+1比我的好。我會刪除我的答案。 – 2012-07-16 21:30:57

+1

您提出了一些非常好的觀點,並提出了令人信服的論點。對於大多數情況來說,這可能不是最佳解決方案。我們正在計劃針對上述問題的日期和其他解決方案的標準格式,但他們只是......解決方法。 MS只需添加JSON格式,就像他們提供的XML格式一樣。 – davids 2012-07-16 22:04:41

+0

@davids關於在JSON中傳遞日期的更多信息對我有幫助嗎? – ErikE 2012-07-17 21:54:09

3

我不會做你正在做的方式(contatenating)

您可以嘗試創建一個使用JSON.net並返回一個varchar一個CLR SQL函數。

這裏瞭解如何創建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 2012-07-16 21:04:35

+0

您將可以執行類似SELECT MyDb.dbo.ConvertToJson(id)的操作,因此您可以直接進行數據庫調用。 – turtlepick 2012-07-16 21:05:33

+0

請記住,JSON可以是非常棘手的,特別是日期和時間字段(你也可能想要說明特殊字符和所有......) – turtlepick 2012-07-16 21:06:31