全局变量是存储数据的宝剑。 树木。 第2部分

全局变量是存储数据的宝剑。 树木。 第2部分入门 - 请参阅第 1 部分。

3. 使用全局变量时的结构变体

像有序树这样的结构有各种特殊情况。让我们考虑一下那些在使用全局变量时具有实际价值的内容。

3.1 特殊情况 1. 一个节点没有分支


全局变量是存储数据的宝剑。 树木。 第2部分全局变量不仅可以像数组一样使用,还可以像常规变量一样使用。例如,作为计数器:

Set ^counter = 0  ; установка счётчика
Set id=$Increment(^counter) ;  атомарное инкрементирование

在这种情况下,全局除了它的含义之外,还可以有分支。一者并不排斥另一者。

3.2 特殊情况2.一个顶点多分支

一般来说,这是一个经典的键值基础。而如果我们将一个值的元组保存为一个值,我们将得到一个非常普通的带有主键的表。

全局变量是存储数据的宝剑。 树木。 第2部分

要在全局变量上实现表,我们必须自己根据列值生成行,然后使用主键将它们保存到全局变量中。为了使读取时能够将字符串再次分为几列,可以使用:

  1. 分隔符。
    Set ^t(id1) = "col11/col21/col31"
    Set ^t(id2) = "col12/col22/col32"
  2. 一种严格的方案,其中每个字段占用预定数量的字节。就像关系数据库中所做的那样。
  3. 一个特殊的函数 $LB(在缓存中可用),它创建一个值的字符串。
    Set ^t(id1) = $LB("col11", "col21", "col31")
    Set ^t(id2) = $LB("col12", "col22", "col32")

有趣的是,使用全局变量来做类似于关系数据库中二级索引的事情并不困难。我们将这种结构称为索引全局变量。索引全局是一个辅助树,用于快速搜索不属于主全局主键的字段。要填写并使用它,您需要编写额外的代码。

让我们在第一列上创建一个全局索引。

Set ^i("col11", id1) = 1
Set ^i("col12", id2) = 1

现在,为了快速搜索第一列中的信息,我们必须查看全局 ^i 并找到与第一列的所需值对应的主键(id)。

插入值时,我们可以立即为所需字段创建值和索引全局变量。为了可靠性,让我们将所有内容都封装在一个事务中。

TSTART
Set ^t(id1) = $LB("col11", "col21", "col31")
Set ^i("col11", id1) = 1
TCOMMIT

有关如何在 M 上执行此操作的详细信息 全局变量表, 二级指标模拟.

如果插入/更新/删除行的函数是用 COS/M 编写并编译的,则此类表的运行速度将与传统数据库中一样快(甚至更快)。我通过对一个两列表的批量 INSERT 和 SELECT 测试检查了此语句,包括使用 TSTART 和 TCOMMIT 命令(事务)。

我还没有测试过具有并发访问和并行事务的更复杂的场景。

在不使用事务的情况下,插入率为每百万值 778 次插入/秒。
拥有 300 亿个值 - 每秒 422 次插入。

使用事务时 - 572M 插入每秒 082 次插入。所有操作均通过编译的 M 代码执行。
硬盘是普通硬盘,不是SSD。带回写功能的 RAID5。 Phenom II 1100T 处理器。

要以类似的方式测试 SQL 数据库,您需要编写一个将在循环中执行插入的存储过程。在测试 MySQL 5.5(InnoDB 存储)时,使用这种方法我每秒收到的插入次数不超过 11K。
是的,全局表的实现看起来比关系数据库中的表更复杂。因此,全局变量上的工业数据库具有 SQL 访问权限,以简化表格数据的处理。

全局变量是存储数据的宝剑。 树木。 第2部分一般来说,如果数据模式不会频繁更改,插入速度并不重要,并且整个数据库可以轻松地以规范化表的形式表示,那么使用 SQL 会更容易,因为它提供了更高级别的抽象。

全局变量是存储数据的宝剑。 树木。 第2部分在这个特殊的例子中我想表明 全局变量可以充当创建其他数据库的构造函数。就像可以编写其他语言的汇编程序一样。以下是如何在全局变量上创建类似物的示例 键值、列表、集合、表格、面向文档的数据库。

如果您需要以最少的努力创建某种非标准数据库,那么您应该考虑全局变量。

3.3 特殊情况3.二层树,第二层的每个节点都有固定数量的分支

全局变量是存储数据的宝剑。 树木。 第2部分您可能猜到了:这是全局表的另一种实现。让我们将这个实现与之前的实现进行比较。

两级树上的表与两级树上的表在单层树上。

缺点
优点

  1. 插入速度较慢,因为您需要将节点数设置为等于列数。
  2. 消耗更多磁盘空间。由于具有列名的全局索引(理解为数组索引)会占用磁盘空间,并且每行都会重复。

  1. 更快地访问各个列的值,因为不需要解析字符串。根据我的测试,在 11,5 列上速度提高了 2%,在更多列上速度提高了更多。
  2. 更容易更改数据模式
  3. 代码更清晰

结论: 并不适合所有人。由于速度是全局变量最关键的好处之一,因此使用此实现没有什么意义,因为它的执行速度很可能不会比关系数据库中的表快。

3.4 一般情况。树和有序树

任何可以表示为树的数据结构都非常适合全局变量。

3.4.1 具有子对象的对象

全局变量是存储数据的宝剑。 树木。 第2部分

这是全局变量传统使用的领域。医学领域有大量的疾病、药物、症状和治疗方法。为每个患者创建一个包含一百万个字段的表是不合理的。而且,99%的字段都是空的。

想象一个 SQL 数据库表:“患者”~ 100 个字段,“医学”- 000 个字段,“治疗”- 100 个字段,“并发症”- 000 个字段,等等。等等。或者,您可以创建一个包含数千个表的数据库,每个表针对特定类型的患者(它们可以重叠!)、治疗、药物以及用于这些表之间连接的数千个表。

全局变量对于医学来说是理想的选择,因为它们允许您以树的形式为每个患者创建其病史、各种疗法和药物作用的准确描述,而无需在空列上浪费额外的磁盘空间,就像关系案例中的情况就是这样。

全局变量是存储数据的宝剑。 树木。 第2部分使用全局变量可以方便地创建包含人员数据的数据库,当积累和系统化尽可能多的有关客户的各种信息非常重要时。医学、银行、营销、归档和其他领域对此有需求

.
当然,在 SQL 中你也可以模拟一棵只有几个表的树(EAV, 1,2,3,4,5,6,7,8,9,10),但是这要复杂得多并且速度会更慢。本质上,您必须编写一个适用于表的全局变量,并将所有与表有关的工作隐藏在抽象层下。使用高级技术(SQL)来模拟低级技术(全局)是错误的。不当。

众所周知,更改巨型表上的数据模式(ALTER TABLE)可能需要相当长的时间。例如,MySQL 通过将旧表中的信息完全复制到新表来执行 ALTER TABLE ADD|DROP COLUMN(经过测试的 MyISAM、InnoDB 引擎)。这可能会使包含数十亿条记录的工作数据库挂起数天甚至数周。

全局变量是存储数据的宝剑。 树木。 第2部分如果我们使用全局变量,那么改变数据结构就不会产生任何成本。 我们可以随时向层次结构的任何级别的任何对象添加所需的任何新属性。与重命名分支相关的更改可以在正在运行的数据库的后台运行。


因此,当涉及到存储具有大量可选属性的对象时,全局变量是一个不错的选择。

此外,让我提醒您,对任何属性的访问都是即时的,因为在全局中所有路径都是 B 树。

一般来说,全局数据库是一种面向文档的数据库,能够存储分层信息。因此,面向文档的数据库可以在存储医疗记录领域与全局数据库竞争。 但还是不太一样我们拿MongoDB来对比一下。 在这个域中 它输给全球的原因如下:

  1. 文档大小。 存储单元是JSON格式的文本(更准确地说是BSON),最大容量约为16MB。该限制是专门进行的,以便在 JSON 数据库中存储巨大的 JSON 文档然后通过字段访问时,JSON 数据库在解析过程中不会变慢。该文件应包含有关患者的所有信息。我们都知道患者记录有多厚。 16MB 的最大卡大小立即终止了患者疾病卡包含 MRI 文件、X 射线扫描和其他研究的情况。在全球的一个分支中,您可以拥有千兆字节和兆兆字节的信息。原则上,我们可以结束这种情况,但我会继续。
  2. 患者病历中新属性的意识/改变/删除时间。 这样的数据库必须将整个映射读入内存(这是一个很大的量!),解析BSON,添加/更改/删除新节点,更新索引,将其打包到BSON中,并将其保存到磁盘。全局变量只需要访问特定的属性并对其进行操作。
  3. 快速访问各个属性。 对于文档中的许多属性及其多级结构,由于全局中的每个路径都是 B 树,因此对各个属性的访问会更快。在 BSON 中,您必须线性解析文档才能找到所需的属性。

3.3.2 关联数组

关联数组(即使是嵌套数组)非常适合全局变量。例如,PHP 中的这样一个数组将显示在第一张图片 3.3.1 中。

$a = array(
  "name" => "Vince Medvedev",
  "city" => "Moscow",
  "threatments" => array(
    "surgeries" => array("apedicectomy", "biopsy"),
    "radiation" => array("gamma", "x-rays"),
    "physiotherapy" => array("knee", "shoulder")
  )
);

3.3.3 分层文档:XML、JSON

也可以轻松存储在全局变量中。可以以不同的方式布置以进行存储。

XML
将 XML 分解为全局变量的最简单方法是将标记属性存储在节点中。如果需要快速访问标签属性,那么我们可以将它们移动到单独的分支中。

全局变量是存储数据的宝剑。 树木。 第2部分

<note id=5>
<to>Вася</to>
<from>Света</from>
<heading>Напоминание</heading>
<body>Позвони мне завтра!</body>
</note>

在 COS 上,这对应于代码:

Set ^xml("note")="id=5"
Set ^xml("note","to")="Саша"
Set ^xml("note","from")="Света"
Set ^xml("note","heading")="Напоминание"
Set ^xml("note","body")="Позвони мне завтра!"

备注: 对于 XML、JSON、关联数组,您可以想出许多不同的全局显示方式。在这种情况下,我们没有在注释标签中反映子标签的顺序。全球范围 ^xml 子标签将按字母顺序显示。为了严格反映顺序,您可以使用例如以下显示:

全局变量是存储数据的宝剑。 树木。 第2部分
JSON。
3.3.1 节中的第一张图片显示了此 JSON 文档的反映:

var document = {
  "name": "Vince Medvedev",
  "city": "Moscow",
  "threatments": {
    "surgeries": ["apedicectomy", "biopsy"],
    "radiation": ["gamma", "x-rays"],
    "physiotherapy": ["knee", "shoulder"]
  },
};

3.3.4 通过层次关系连接的相同结构

示例:销售办事处的结构、传销结构中人员的位置、国际象棋中的空缺数据库。

首次推出数据库。 您可以使用行程力估计作为全局节点的索引值。然后,为了选择最强的动作,选择权重最大的分支就足够了。在全局中,每个级别的所有分支都会按照移动强度进行排序。

全局变量是存储数据的宝剑。 树木。 第2部分

销售办事处的结构,传销人员的结构。 节点可以存储一定的反映整个子树特性的缓存值。例如,给定子树的销量。任何时候我们都可以得到一个反映任何分支机构所取得的成就的数字。

全局变量是存储数据的宝剑。 树木。 第2部分

4. 在什么情况下使用全局变量最有利?

第一列介绍了通过使用全局变量可以显着提高速度的情况,第二列介绍了设计或数据模型得到简化的情况。

速度
易于数据处理/呈现

  1. 插入[每级自动排序]、[按主键索引]
  2. 删除子树
  3. 具有大量需要单独访问的嵌套属性的对象
  4. 分层结构能够绕过任何分支的子分支,甚至是不存在的分支
  5. 子树的深度优先遍历
  1. 具有大量可选[和/或嵌套]属性/实体的对象/实体
  2. 无模式数据。当新的属性经常出现而旧的属性消失时。
  3. 您需要创建一个自定义数据库。
  4. 路径库和决策树。当可以方便地将路径表示为树时。
  5. 不使用递归删除层次结构

延期 “全局变量是存储数据的宝剑。稀疏数组。第 3 部分”.

免责声明: 本文以及我对其的评论仅代表我的观点,与 InterSystems Corporation 的官方立场无关。

来源: habr.com

添加评论