最近,我尝试了Azure SQL数据库的新for json auto
功能。
例如,当我使用此查询选择大量记录时:
Select
Wiki.WikiId
, Wiki.WikiText
, Wiki.Title
, Wiki.CreatedOn
, Tags.TagId
, Tags.TagText
, Tags.CreatedOn
From
Wiki
Left Join
(WikiTag
Inner Join
Tag as Tags on WikiTag.TagId = Tags.TagId) on Wiki.WikiId = WikiTag.WikiId
For Json Auto
然后使用 C#SqlDataReader
进行选择:
var connectionString = ""; // connection string
var sql = ""; // query from above
var chunks = new List<string>();
using (var connection = new SqlConnection(connectionString))
using (var command = connection.CreateCommand()) {
command.CommandText = sql;
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read()) {
chunks.Add(reader.GetString(0)); // Reads in chunks of ~2K Bytes
}
}
var json = string.Concat(chunks);
我得到了很多数据块。
为什么我们有这个限制?我们为什么不把所有东西都放在一大块里呢?
当我阅读nvarchar(max)
专栏时,我将在一个块中获取所有内容。
感谢您的解释
来自使用 FOR JSON 将查询结果格式化为 JSON:
FOR JSON 子句的输出
结果集包含单个列。
小型结果集可能包含一行。
大型结果集将长 JSON 字符串拆分为多行。 默认情况下,当输出设置为"结果"时,SQL Server Management Studio (SSMS( 会将结果连接到一行中 网 格。SSMS 状态栏显示实际行计数。
其他客户端应用程序可能需要代码通过连接 多行的内容。有关 C# 中此代码的示例 应用程序中,请参阅在 C# 客户端应用中使用 FOR JSON 输出。
我会说这完全是出于性能原因,类似于XML。更多 选择 对于 XML 自动和返回数据类型和 服务器端 对于 XML 返回什么?
在SQL Server 2000中,服务器端XML发布 - FOR XML(参见 http://msdn2.microsoft.com/en-us/library/ms178107(SQL.90(.aspx( - 是在查询处理器和数据传输层之间的代码层中实现的。如果没有 FOR XML,查询处理器将执行 SELECT 查询,生成的行集由服务器端 TDS 代码发送到客户端。当 SELECT 语句包含 FOR XML 时,查询处理器生成结果的方式与不使用 FOR XML 的方式相同,然后 FOR XML 代码将行集格式化为 XML。为了获得最大的 XML 发布性能,FOR XML 会对生成的行集进行 XML 格式化,并直接将其输出以小块的形式发送到服务器端 TDS 代码,而无需在服务器空间中缓冲整个 XML。区块大小为 2033 个 UCS-2 字符。因此,大于 2033 个 UCS-2 字符的 XML 将分多行发送到客户端,每行包含 XML 的一个区块。SQL Server 为此行集使用预定义的列名,其中一列类型为 NTEXT - "XML_F52E2B61-18A1-11d1-B105-00805F49916B" – 以 UTF-16 编码指示分块 XML 行集。这需要 API 对 XML 区块行集进行特殊处理,以将其公开为客户端上的单个 XML 实例。在 ADO.Net 中,需要使用ExecuteXmlReader,在ADO/OLEDB中,应该使用ICommandStream接口。
作为SQL代码中的解决方法(即,如果您不想更改查询代码以将块放在一起(,我发现将查询包装在CTE中,然后选择给我预期结果的表单:
--Note that I query from information_schema to just get a lot of data to replicate the problem.
--doing this query results in multiple rows (chunks) returned
SELECT * FROM information_schema.columns FOR JSON PATH, include_null_values
--doing this query results in a single row returned
;WITH SomeCTE(JsonDataColumn) AS
(
SELECT * FROM information_schema.columns FOR JSON PATH, INCLUDE_NULL_VALUES
)
SELECT JsonDataColumn FROM SomeCTE
第一个查询为我重现了这个问题(返回多行,每行都是总数据的块(,第二个查询给出一行包含所有数据。SSMS 不适合重现问题,您必须使用其他客户端代码进行尝试。
我不知道阻止 FOR JSON 拆分长字符串的设置,但可以通过子选择来解决。只需将您的选择与另一个包装在一起即可。
SELECT (SELECT Wiki.WikiId ....)