JSON 列或传统列
JSON Column OR Traditional Columns
我的团队正在开发一个发票模块,我们的用户需要能够在发票中添加订单项并将这些订单项存储在我们的数据库中。这些订单项可以在初始创建后进行编辑。
发票的行项目看起来像这样。
LineItemName
EnteredBy
Quantity
CostPerUnit
Subtotal
我们的一位团队成员建议我们将行数据存储到一个 JSON 列中,而不是多个 SQL 列中。他的论点是,将所有行项目数据存储到单个 JSON 列中比编写代码来检测哪些行项目可能已被删除、更新、重新排序或以其他方式从数据库的原始状态。
我之前没有使用过 JSON 列,据我所知,在使用这些列时存在许多性能问题,以及在基于 [=23] 构建查询时存在一些额外的复杂性=]的数据列。我们将不得不报告这些行项目,因此性能绝对是一个问题。我们也是 运行 SQL Server 2012,据我所知,它不包含对 JSON 列的本机支持,除非我们升级到 SQL Server 2016。旁注,我们很可能会在接下来的 2-3 年内移动到 MYSQL。
任何人都可以就此处的正确调用提供一些指导吗?我的直觉是,我们应该利用现有方法并编写额外的代码来检测数据库更改,以避免以后出现令人头疼的性能问题和报告复杂性。
简短回答:不要存储在 JSON 中,使用列,这就是它们在那里的原因。
长答案
您正在使用关系数据库来存储您的数据,使用这些软件提供的功能来存储和组织您的数据。
因为它已经出现在评论中,将值存储在它们单独的列中,允许您执行不同的聚合,在这些列上进行过滤而无需解析非关系数据结构的开销(很可能使用第三方plugin/clr/function/whatever).
另外JSON数据没有固定的结构。如果不解析字段并编写自定义验证,则无法验证存储在 JSON 字段中的数据的一致性。
在一个字段中存储多个数据也意味着,你不能(或不容易)
- 对嵌入字段使用约束
- 您不能强制执行嵌入字段的每个字段的结构、有效范围、有效值
- 定义嵌入字段的数据类型
- 索引数据(不包括它们)
- aggregate/search 在那些领域
- 扩展系统
- 查询嵌入的元数据、字段列表等
数据库服务器不能
- 跟踪每个字段的索引统计信息
- 使用 JSON 字段优化查询(因为提取数据需要进行字符串操作)
- 无法优化存储每个字段的数据。
以上内容很重要,但是 none 个列表是完整的。
你会赢什么?
- 一些字段名称。
- 数据库中有一些灵活性,但应用程序中的功能要复杂得多,因为所有验证都应该在应用程序中完成两次 - 当您要写入数据时和读取数据时。
- 当您必须在 JSON 字段中修复某些内容时,会非常头疼。
作为替代方案,您可以使用 XML 列,SQL 服务器支持它,上面的一些东西不是问题,但是:它仍然没有固定的结构。 (如果有,你可以将数据存储在传统的列中。这两种情况,你都必须手动指定结构)。
注意:您为存储数据选择的格式当然是基于意见的,但根据经验,只要传统列可以满足您的需求,就使用它们并避免使用序列化数据。特别是如果您只想使用它的某些部分进行任何类型的计算。
什么时候可以存储序列化数据:
当强制一致性并不重要时,您永远不会将其用于统计查询或过滤。 (然而,在大多数情况下,never 部分不是真的 :))
我会尝试给出一个稍微不同的答案:)
如果您希望进行大量更新和计算,请使用关系列。引用和更新列优于更新和引用 JSON 字段。在这种情况下,您正在优化 DML 性能和可能的一些分析。
如果您有很少更改的信息,并且如果您想避免过多的 JOIN,或者如果您的应用程序需要 JSON,请使用 JSON/XML。在这种情况下,您将优化读取和加载性能。
在前面的回答中你可以看到关系模式的很多好处,我不能说这是错误的。但是,我会提到一些 JSON 可以提供帮助的用例:
- 假设您有大量 table,您需要将 10 万张发票与 100 万张发票行项目合并。在关系模型中,您将有两个 table 扫描和 JOIN,而在 JSON/XML 中,您将有一个 table 扫描。如果您的应用程序需要格式为 JSON 的响应(例如,您正在通过 Ajax 调用将订单项作为 JSON 发送到 angular、Knockout 或其他 JavaScript 模板) JSON 将是完美的选择。想象一下,与使用 JSON 的单一 table 扫描相比,在更复杂的结构上查询会是什么样子。 De-normalization 是提高查询性能的最古老的技巧之一,JSON 只是一种反规范化技术,如物化视图、OLAP 多维数据集中的聚合等。它不是解决所有问题的方法,但它在某些情况下有帮助。
- 假设您需要导入 parent/child tables。您需要导入一个发票行,采用@@identity,使用该标识插入相关的行项目,并对每个导入的发票重复此操作。替代方法是通过设置 IDENTITY INSERT ON 来强制使用 id。使用 JSON/XML,如果您将格式为 JSON 的行项目作为每张发票的一部分,您可以使用简单的批量导入,这是加载数据的最快方式。
这些是人们转而使用 NoSQL(例如 MongoDB 或 Azure DocumentDB)的一些原因。 SQL 2016 会支持JSON,之前的版本需要用XML,原理是一样的
在您的情况下,您似乎会经常更新订单项并且不需要快速 read/load 场景,因此我建议使用关系模式。
我的团队正在开发一个发票模块,我们的用户需要能够在发票中添加订单项并将这些订单项存储在我们的数据库中。这些订单项可以在初始创建后进行编辑。
发票的行项目看起来像这样。
LineItemName
EnteredBy
Quantity
CostPerUnit
Subtotal
我们的一位团队成员建议我们将行数据存储到一个 JSON 列中,而不是多个 SQL 列中。他的论点是,将所有行项目数据存储到单个 JSON 列中比编写代码来检测哪些行项目可能已被删除、更新、重新排序或以其他方式从数据库的原始状态。
我之前没有使用过 JSON 列,据我所知,在使用这些列时存在许多性能问题,以及在基于 [=23] 构建查询时存在一些额外的复杂性=]的数据列。我们将不得不报告这些行项目,因此性能绝对是一个问题。我们也是 运行 SQL Server 2012,据我所知,它不包含对 JSON 列的本机支持,除非我们升级到 SQL Server 2016。旁注,我们很可能会在接下来的 2-3 年内移动到 MYSQL。
任何人都可以就此处的正确调用提供一些指导吗?我的直觉是,我们应该利用现有方法并编写额外的代码来检测数据库更改,以避免以后出现令人头疼的性能问题和报告复杂性。
简短回答:不要存储在 JSON 中,使用列,这就是它们在那里的原因。
长答案
您正在使用关系数据库来存储您的数据,使用这些软件提供的功能来存储和组织您的数据。
因为它已经出现在评论中,将值存储在它们单独的列中,允许您执行不同的聚合,在这些列上进行过滤而无需解析非关系数据结构的开销(很可能使用第三方plugin/clr/function/whatever).
另外JSON数据没有固定的结构。如果不解析字段并编写自定义验证,则无法验证存储在 JSON 字段中的数据的一致性。
在一个字段中存储多个数据也意味着,你不能(或不容易)
- 对嵌入字段使用约束
- 您不能强制执行嵌入字段的每个字段的结构、有效范围、有效值
- 定义嵌入字段的数据类型
- 索引数据(不包括它们)
- aggregate/search 在那些领域
- 扩展系统
- 查询嵌入的元数据、字段列表等
数据库服务器不能
- 跟踪每个字段的索引统计信息
- 使用 JSON 字段优化查询(因为提取数据需要进行字符串操作)
- 无法优化存储每个字段的数据。
以上内容很重要,但是 none 个列表是完整的。
你会赢什么?
- 一些字段名称。
- 数据库中有一些灵活性,但应用程序中的功能要复杂得多,因为所有验证都应该在应用程序中完成两次 - 当您要写入数据时和读取数据时。
- 当您必须在 JSON 字段中修复某些内容时,会非常头疼。
作为替代方案,您可以使用 XML 列,SQL 服务器支持它,上面的一些东西不是问题,但是:它仍然没有固定的结构。 (如果有,你可以将数据存储在传统的列中。这两种情况,你都必须手动指定结构)。
注意:您为存储数据选择的格式当然是基于意见的,但根据经验,只要传统列可以满足您的需求,就使用它们并避免使用序列化数据。特别是如果您只想使用它的某些部分进行任何类型的计算。
什么时候可以存储序列化数据: 当强制一致性并不重要时,您永远不会将其用于统计查询或过滤。 (然而,在大多数情况下,never 部分不是真的 :))
我会尝试给出一个稍微不同的答案:)
如果您希望进行大量更新和计算,请使用关系列。引用和更新列优于更新和引用 JSON 字段。在这种情况下,您正在优化 DML 性能和可能的一些分析。
如果您有很少更改的信息,并且如果您想避免过多的 JOIN,或者如果您的应用程序需要 JSON,请使用 JSON/XML。在这种情况下,您将优化读取和加载性能。
在前面的回答中你可以看到关系模式的很多好处,我不能说这是错误的。但是,我会提到一些 JSON 可以提供帮助的用例:
- 假设您有大量 table,您需要将 10 万张发票与 100 万张发票行项目合并。在关系模型中,您将有两个 table 扫描和 JOIN,而在 JSON/XML 中,您将有一个 table 扫描。如果您的应用程序需要格式为 JSON 的响应(例如,您正在通过 Ajax 调用将订单项作为 JSON 发送到 angular、Knockout 或其他 JavaScript 模板) JSON 将是完美的选择。想象一下,与使用 JSON 的单一 table 扫描相比,在更复杂的结构上查询会是什么样子。 De-normalization 是提高查询性能的最古老的技巧之一,JSON 只是一种反规范化技术,如物化视图、OLAP 多维数据集中的聚合等。它不是解决所有问题的方法,但它在某些情况下有帮助。
- 假设您需要导入 parent/child tables。您需要导入一个发票行,采用@@identity,使用该标识插入相关的行项目,并对每个导入的发票重复此操作。替代方法是通过设置 IDENTITY INSERT ON 来强制使用 id。使用 JSON/XML,如果您将格式为 JSON 的行项目作为每张发票的一部分,您可以使用简单的批量导入,这是加载数据的最快方式。
这些是人们转而使用 NoSQL(例如 MongoDB 或 Azure DocumentDB)的一些原因。 SQL 2016 会支持JSON,之前的版本需要用XML,原理是一样的
在您的情况下,您似乎会经常更新订单项并且不需要快速 read/load 场景,因此我建议使用关系模式。