【问题标题】:Quickest method for matching nested XML data against database table structure将嵌套 XML 数据与数据库表结构匹配的最快方法
【发布时间】:2013-07-25 23:01:51
【问题描述】:

我有一个创建datarequests 的应用程序,这可能非常复杂。这些需要作为表存储在数据库中。 datarequest(作为 XML)的轮廓将是...

<datarequest>
  <datatask view="vw_ContractData" db="reporting" index="1">
    <datefilter modifier="w0">
      <filter index="1" datatype="d" column="Contract Date" param1="2009-10-19 12:00:00" param2="2012-09-27 12:00:00" daterange="" operation="Between" />
    </datefilter>
    <filters>
      <alternation index="1">
        <filter index="1" datatype="t" column="Department" param1="Stock" param2="" operation="Equals" />
      </alternation>
      <alternation index="2">
        <filter index="1" datatype="t" column="Department" param1="HR" param2="" operation="Equals" />
      </alternation>
      </filters>
    <series column="Turnaround" aggregate="avg" split="0" splitfield="" index="1">
      <filters />
    </series>
    <series column="Requested 3" aggregate="avg" split="0" splitfield="" index="2">
      <filters>
        <alternation index="1">
          <filter index="1" datatype="t" column="Worker" param1="Malcom" param2="" operation="Equals" />
        </alternation>          
      </filters>
    </series>
    <series column="Requested 2" aggregate="avg" split="0"  splitfield="" index="3">
      <filters />
    </series>
    <series column="Reqested" aggregate="avg" split="0" splitfield="" index="4">
      <filters />
    </series>
  </datatask>
</datarequest>

这对包含日期范围、主过滤器、系列和系列过滤器的数据请求进行编码。基本上,任何具有index 属性的元素都可以在其父元素中出现多次——datefilter 中的filter 除外。

但是这个结构有点学术,问题更根本:

当请求通过时,像这样的 XML 会作为存储过程的参数发送到 SQLServer。这个 XML 被分解成一个去规范化的表,然后迭代地写入规范化的表,例如 tblDataRequest (DataRequestID PK)tblDataTasktblFiltertblSeries。这很好。

当我想将给定的 XML 定义与数据库中已经保存的 XML 定义匹配时,就会出现问题。我目前这样做是...

  • 将 XML 分解为非规范化表
  • 使用 CTE 将数据库中的所有现有数据提取到相同的非规范化形式中
  • 使用巨大的WHERE 条件匹配(34 行长)

..这将返回与给定 XML 完全匹配的任何 DataRequestID。我担心这种方法最终会变得非常缓慢 - 部分原因是我不相信 CTE 会进行任何巧妙的过滤,它会每次应用巨大的WHERE 之前提取所有数据.

我认为必须有更好的解决方案,例如

  • 在存储datarequest 时,还要以某种方式存储数据请求的哈希值并简单地匹配它。在发生碰撞的情况下,使用当前方法。但是,我想使用 set-logic 来做到这一点。而且,我担心 XML 中无关紧要的小差异会改变散列 - 虚假空格等。
  • 不知何故从下往上迭代地执行匹配。例如,生成在最低级别匹配的过滤器列表。将其用作IN 的一部分以匹配系列。将其用作 IN 的一部分以匹配 DataTasks 等。问题是,当我考虑这个问题太久时,我开始昏迷。

基本上 - 以前有没有人遇到过这种问题(他们一定遇到过)。解决它的推荐路线是什么?示例(伪)代码会很棒:)

【问题讨论】:

  • 我使用 XML 规范化(修剪和排序节点)和哈希处理了与此类似的问题。它工作得很好而且很快。所以它首先解析 XML,应用规范化,然后以一般方式计算哈希。
  • @ViktorStolbin 感谢您的评论。所以我有希望!我不需要对节点进行排序,因为顺序很重要——尽管属性顺序不是。你排序属性顺序了吗?
  • 我正在对所有内容进行排序,因为 XML 是数据库查询的直接表示,我依赖那里的数据库查询优化。
  • 一件事。可能哈希实现应该对元素顺序敏感。
  • 显然是 SQLServer XML 类型 cannot be trusted to preserve attribute order. 我可能需要在应用程序端对我的 XML 进行排序,然后才能将其作为 VARCHAR 传递给存储过程。

标签: sql sql-server-2005 data-structures orm


【解决方案1】:

为了消除微小差异的可能性,我将通过 XML 转换 (XSLT) 运行请求。

或者,因为您已经获得了将其解析为非规范化暂存表的代码,这也很好。然后我会简单地使用FOR XML 创建一个新的 XML 文档。

您的目标是创建一个标准化的 XML 文档,该文档在适当的地方尊重排序,并在不存在的地方消除不一致。

完成后,将其存储在新表中。现在您可以将“标准化”请求 XML 与现有数据进行直接比较。

要进行实际比较,您可以使用哈希,将 XML 存储为字符串并进行直接字符串比较,或者像这样进行完整的 XML 比较:http://beyondrelational.com/modules/2/blogs/28/posts/10317/xquery-lab-36-writing-a-tsql-function-to-compare-two-xml-values-part-2.aspx

只要 XML 从不超过 8000 字节,我的偏好是创建一个唯一的字符串(如果您有特殊字符支持,则为 VARCHAR(8000) 或 NVARCHAR(4000))并在列上创建一个唯一索引。

【讨论】:

  • +1 出色的答案 Rai!欢迎来到 SO。顺便说一句,这种方法几乎是我解决问题的方法!
猜你喜欢
  • 1970-01-01
  • 2021-10-19
  • 2015-03-30
  • 1970-01-01
  • 1970-01-01
  • 2020-01-13
  • 2023-02-24
  • 2015-05-07
  • 1970-01-01
相关资源
最近更新 更多