SqlDataReader 和 SQL Server 2016 FOR JSON 将 json 拆分为 2k 字节的块



最近,我尝试了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 ....)

最新更新