【问题标题】:SQL Server Performance with Key/Pair Table vs XML Field and XPathSQL Server 性能与键/对表与 XML 字段和 XPath
【发布时间】:2010-02-19 16:28:10
【问题描述】:

我已经看到了一些关于这个主题的问题,但我正在寻找有关这两种技术之间性能差异的一些见解。

例如,假设我正在记录将进入系统的事件日志,其中包含特定事件的键/值对字典集。我将在事件表中记录一个带有基本数据的条目,但是我需要一种方法来链接其他键/值数据。我永远不会知道会出现什么样的键或值,所以任何类型的预定义枚举表似乎都是不可能的。

此事件数据将不断流入,因此插入时间与查询时间一样重要。

当我查询特定事件时,我将使用事件上的一些字段以及键/值数据中的数据。对于 XML 方式,我只需使用 Attributes.exists('xpath') 语句作为 where 子句的一部分来过滤记录。

规范化的方法是使用具有基本键和值字段的表,并带有指向事件记录的外部链接。这看起来简洁明了,但我担心所涉及的数据量。

【问题讨论】:

    标签: sql-server xml database performance xpath


    【解决方案1】:

    对于“灵活”的存储机制,您有三个主要选项。

    • XML 字段很灵活,但会将您置于 Blob 存储领域,查询速度很慢。我已经看到,当它使用 Xpath 查询从 blob 中挖掘内容时,对 30,000 行的小型数据集的查询需要 5 分钟。这是迄今为止最慢的选项,但它很灵活。

    • 键/值对要快得多,尤其是在事件键上放置聚集索引时。这意味着单个事件的所有属性将在物理上一起存储在数据库中,这将最大限度地减少 I/O。该方法不如 XML 灵活,但速度要快得多。针对它进行报告的最有效查询将涉及数据透视(即表扫描以生成中间展平结果);加入获取单个字段会慢得多。

    • 最快的方法是创建一个包含一组用户定义字段 (Field1 - Field50) 的平面表,并保存一些有关字段内容的元数据。这是插入速度最快、查询速度最快且最简单的方法,但表的内容对于无法访问元数据的任何内容都是不透明的。

    【讨论】:

      【解决方案2】:

      我认为键/值表方法的问题在于数据类型——如果一个值可以是日期时间、字符串、Unicode 字符串或整数,那么如何定义列?这种困境意味着值列必须是一种数据类型,其中可以包含所有不同类型的数据,这会引发查询效率/易用性的问题。或者,您有多个特定数据类型的列,但我认为这有点笨拙。

      对于真正灵活的模式,我想不出比 XML 更好的选择。您可以索引 XML 列。

      This article off MSDN 更详细地讨论了 XML 存储。

      【讨论】:

      • sql_variant 可以包含不同的类型,BOL 建议用于实体值表
      • @KM - 是的,它可以,但它不支持所有类型,并且限制为 ~8000 字节 - 尽管在这种情况下可能不是问题。我主要关心的是查询性能和可能的类型转换问题——我不知道
      • 您是否曾经实际使用过将数据存储为 XML 列的非常复杂的应用程序?我正在使用一个保险单管理系统,正如我们所说的那样。 5分钟查询29000条记录是一个实际的系统基准。
      • 是的,在 XML 类型存在之前(XML 数据存储为 NTEXT,eek),数百万行数据。出于报告目的,这需要将数据拆分为正确类型的一组非规范化表。这是一个折衷方案——XML 提供了最大的灵活性,我原以为对 XML 进行仔细的索引会产生合理的性能。但是,我有兴趣看到与数据/值对方法的同类比较——我主要关心的是我上面提到的数据类型。
      • XML 列在批处理作业中很慢(ntext 列更是如此),至少在文档非常复杂的情况下是如此。我目前正在使用的系统确实有一个碎纸机,可以吐出数据的关系视图。供应商声称每条记录大约需要 5-10 秒来进行粉碎,这主要受 CPU 限制。具有聚集索引的 KVP 可以最大限度地减少批处理作业的 I/O,但最好的方法是旋转数据,而不是使用过滤器连接自身。不同的类型可以作为文本表示或每种可能类型的占位符列来处理。
      【解决方案3】:

      我假设对于 INSERT 和 SELECT 操作,规范化的方式会更快,如果仅仅是因为这是任何 RDBMS 的优化目标。 “所涉及的数据量”部分也可能是一个问题,但更容易解决 - 您需要立即手头的数据多长时间,您可以在一天、几周或 3 个月后将其存档,等等? SQL Server 可以处理很多事情。

      此事件数据将不断流入,因此插入时间与查询时间一样重要。

      选项 3:如果您确实有大量数据不断流式传输 - 在共享内存、进程内 sqlite、单独的数据库表甚至它自己的服务器中创建一个单独的队列,以存储传入的原始事件和属性,以及让另一个进程(计划任务、Windows 服务等)将该队列解析为针对快速 SELECT 调整的任何首选格式。最佳输入,最佳输出,准备好向任一方向扩展,每个人都很高兴。

      【讨论】:

        猜你喜欢
        • 2020-11-03
        • 1970-01-01
        • 2021-08-26
        • 2023-04-09
        • 2019-07-09
        • 1970-01-01
        • 2010-10-18
        • 1970-01-01
        • 2011-01-05
        相关资源
        最近更新 更多