使用SQL返回JSON字符串

dav*_*ids 10 c# asp.net-mvc json sql-server-2008

这是一个"最佳实践"问题.我们正在就此主题进行内部讨论,并希望得到更广泛受众的意见.

我需要将我的数据存储在MS SQL Server具有普通列和行的传统表中.我有时需要返回DataTable到我的Web应用程序,有时我需要返回一个JSON字符串.

目前,我将表返回到中间层并将其解析为JSON字符串.这似乎在大多数情况下运行良好,但偶尔会在大型数据集上花费一些时间(解析数据,而不是返回表).

我正在考虑修改存储过程以选择性地返回一个DataTable或一个JSON字符串.我只想@isJson bit在SP中添加一个参数.

如果用户想要字符串而不是表,则SP将执行如下查询:

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

这会产生如下内容:

{id:"1342",name:"row1"},{id:"3424",name:"row2"}
Run Code Online (Sandbox Code Playgroud)

当然,用户也可以通过将false传递给@isJson参数来获取表.

我想清楚,数据存储不受影响,现有的任何视图和其他进程也不会受到影响.这只是对某些存储过程的结果的更改.

我的问题是:

  1. 有没有人在大型应用程序中尝试过这个?如果是这样,结果是什么?
  2. 您对这种方法有什么看法/期望?
  3. 除了以这种方式修改存储过程或解析中间层中的字符串之外,还有更好的方法从SQL Server中的表转到JSON吗?

Eri*_*ikE 8

我个人认为这种字符串操作的最佳位置是程序代码,它是一种完全表达的语言,具有函数并且可以编译.在T-SQL中执行此操作并不好.程序代码可以具有正确转义的快速功能.

让我们稍微思考一下:

  • 部署应用程序的部件和部件的新版本时,此功能的最佳位置在哪里?

  • 如果你必须恢复你的数据库(及其所有存储过程)会对任何事情产生负面影响吗?如果要部署新版本的Web前端,将JSON转换绑定到数据库会导致问题吗?

  • 你将如何正确地逃脱角色?你发送任何日期?日期字符串的格式是什么,以及如何将它们转换为另一端的实际Date对象(如果需要)?

  • 您将如何对其进行单元测试(以及自动化测试!)以证明其工作正常?你将如何回归测试呢?

  • SQL Server UDF可能非常慢.你满足于使用慢速函数,还是速度入侵你的SQL代码之类的东西Replace(Replace(Replace(Replace(Value, '\', '\\'), '"', '\"'), '''', '\'''), Char(13), '\n')?那么Unicode \u\x转义呢?如何拆分'</script>''<' + '/script>'?(也许这不适用,但也许它可以,取决于你如何使用你的JSON.)你的T-SQL程序是否会完成所有这些,并且可以重用于不同的记录集,或者你每次都会重写它们你需要返回JSON的SP?

  • 您可能只有一个需要返回JSON的SP.目前.有一天,你可能会有更多.然后,如果你发现了一个bug,你必须在两个地方修复它.或者五个.或者更多.

让中间层进行翻译可能会让你的事情变得更复杂,但我保证从长远来看它会变得更好.如果您的产品向外扩展并开始大规模并行 - 您可以随便丢弃更多的Web服务器,但是您无法轻松修复数据库服务器资源饱和度!因此,不要让DB做更多的工作.它是数据访问层,而不是表示层.尽可能减少工作量.为其他一切编写代码.你会很高兴的.

Web应用程序中字符串处理的速度提示

  1. 确保您的Web字符串连接代码不受Schlemiel the Painter算法的影响.可以在生成JSON时直接写入输出缓冲区(Response.Write),也可以使用正确的StringBuilder对象,或者将JSON的部分写入数组,稍后将Join()写入.不要一遍又一遍地对更长更长的字符串进行普通的连接.
  2. 尽可能少地取消引用对象.我不知道你的服务器端语言,但如果碰巧是ASP Classic,请不要使用字段名称 - 要么获得对变量中每个字段的引用,要么至少使用整数字段索引.在循环内基于其名称取消引用字段会(性能)更差.
  3. 使用预先构建的库.当你可以使用一个久经考验的库时,不要自己动手.性能应该与您自己的性能相同或更好,并且(最重要的是)它将被测试更正.
  4. 如果你打算花时间做这个,那就把它抽象得足以处理转换任何记录集,而不仅仅是你现在拥有的记录集.
  5. 使用编译代码.您可以在编译时获得最快的代码,而不是解释.如果您确定JSON转换例程确实是瓶颈(并且您必须证明这是真实的,请不要猜测)然后将代码转换为已编译的内容.
  6. 减少字符串长度.这不是一个大问题,但如果可能的话,使用单字母json名称而不是多字母.对于一个巨大的记录集,这增加两端的节省.
  7. 确保它是GZipped.这不是服务器端的改进,但我没有提到完整的JSON性能.

用JSON传递日期

我建议使用单独的JSON模式(本身在JSON中,定义要遵循的虚拟记录集的结构).此模式可以作为标题发送到要跟随的"记录集",或者它可以已经加载到页面中(包含在基本javascript文件中),因此不必每次都发送它.然后,在您的JSON解析回调(或最终结果对象的回调后)中查找当前列的架构并根据需要进行转换.您可能会考虑使用ISO格式,因为在ECMAScript 5严格模式下,应该有更好的日期支持,您的代码可以简化而无需更改数据格式(简单的对象检测可以让您将此代码用于任何支持的浏览器它):

日期

日期现在能够解析和输出ISO格式的日期.

Date构造函数现在尝试将日期解析为ISO格式,首先,然后转到它接受的其他输入.

此外,日期对象现在有一个新的.toISOString()方法,它以ISO格式输出日期.var date = new Date("2009-05-21T16:06:05.000Z");

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