在网格中存储分层对象

Storing layered objects in a grid

假设我有一个 canvas,我可以在其中添加各种对象,例如 a/an:

对于每个对象,我需要存储尺寸和层顺序,例如这样的东西:

每个对象都具有截然不同的属性,因此存储在不同的 table 中(或 类 或其他)。是否可以将其存储到关系数据库中,如果可以,如何实现?在 JSON 中会是这样的:

// LayerIndex is the ArrayIndex
// No need to store ObjectID, since the object is stored within the array itself
Layers = [
    {Type: Drawing, Props: <DrawingPropertyObj>, Dimensions: [(1,2), (3,4)]},
    {Type: Chart,   Props: <ChartPropertyObj>,   Dimensions: [(3,4), (10,4)]},
    {Type: Table,   Props: <TablePropertyObj>,   Dimensions: [(10,20), (30,44)]},
    ...
]

我想到的一个选择是为每个 table 存储一个 FK,但在那种情况下,我可能会将其加入每个对象类型的 N 个不同的 table,所以如果有是 100 种对象类型,...

您有很多选项,如下所示。

你选哪个没有太大区别,但我会避免你说的multi-table设计。具有 100 个属性的 object 类型将分散在 101 table 秒中而没有任何收益。正在读取的每个 object 类型有 101 次磁盘页面访问。这是不必要的(如果这些页面被缓存,那么这个问题会比其他情况少,但仍然是浪费)。

如果你不想过滤像'all objects with color=red'这样的东西,即使是双table也不是真正必要的,但我想达到这一点性能并不是那么迫切,其他事情更重要,或其他瓶颈对性能的影响更大,因此请选择最适合您的 no-more-than-dual-table。

单个 table - 每个 object 类型的灵活模式

objlayerindex type props x0 y0 x1 y1
0 drawing {color:#00FF00,background-color:#00FFFF} 1 2 3 4
1 chart {title:2021_sales,values:[[0,0],[3,4]]} 11 22 33 44
  • props中的key是为了灵活使用,不同的object同类型的可能有不同的key,比如没有字幕的图表可以省略这个key。

单一 table - 每个 object 类型的固定架构

objlayerindex type props x0 y0 x1 y1
0 drawing #00FF00,#00FFFF 1 2 3 4
1 chart 2021_sales,"[[0,0],[3,4]]" 11 22 33 44
  • 这个模式是固定的——绘图总是有颜色+背景颜色;图表总是有标题+值;等 - 较少 space 使用但更改模式涉及对现有数据的一些工作。

双table

主要
objlayerindex type x0 y0 x1 y1
0 drawing 1 2 3 4
1 chart 11 22 33 44
属性
objlayerindex propertyname propertyvalue
0 color #00FF00
0 background-color #00FFFF
1 title 2021_sales
1 values [[0,0],[3,4]]
  • 这里我们假设 属性 顺序不重要。如果是,则需要一个额外的列 propertyindex。对于那些喜欢归一化的人来说,也可以从这个 table 中取出 propertyname 到一个 propertykey-propertydescription 并通过它的 propertykey.
  • 引用它

多个table

主要
objlayerindex type x0 y0 x1 y1
0 drawing 1 2 3 4
1 chart 11 22 33 44
颜色
objlayerindex colorcode
0 #00FF00
Background-Color
objlayerindex colorcode
0 #00FFFF
标题
objlayerindex title
1 2021_sales
objilayerindex chart
1 [[0,0],[3,4]]
  • 具体这种数据可以多归一化一级:
objlayerindex datapoint x y
1 0 0 0
1 1 3 4

您也可以使用 non-relational 格式。

文档(Json)存储

[
  {type:drawing,props:{color:#00FF0,background-color:#00FF0},position:[1,2,3,4]},
  {type:chart,props:{title:2021_sales,values:[[0,0],[3,4]]},position:[11,22,33,44]}
]
  • 我们在这里引用是因为它是一种流行且简单的格式,但是可以使用不同的编码来代替 JSON(CSV、protocolbuffers、avro 等)

“严格”的关系数据库不适合这项任务,因为您可以选择:

  1. 每个 object 类型的不同 tables,每个属性都有一个列,适用于该特定 object 类型
  2. 所有 object 类型的单个 table,每个属性都有列,其中大部分不用于任何给定的 object 类型
  3. A child table,每个属性一行

在继续讨论一个好的通用解决方案之前,让我们讨论一下:

1。每个 object 类型 table 不同

这是一个non-starter。问题是:

  • 高维护成本:每次向应用程序添加新的 object 类型时都必须创建一个新的 table
  • 痛苦的查询:您必须连接到每个 table,或者水平连接 - 每个 table 连接成一个非常长的行,或者垂直连接到一系列联合连接,导致 sparse array(见选项 2)

2。所有 object 类型

的单个 table

虽然你处理的是sparse array,但如果大多数object类型使用大部分属性(即不是那个稀疏),这是一个不错的选择。但是,如果您的域中不同属性的数量很多,and/or 大多数属性并未被所有类型使用,您必须在引入新类型时添加列,尽管这比添加 table 更好s,仍然需要为新类型更改架构 = 高维护

3。 Achildtable

这是 classic 方法,但使用起来更糟糕,因为您必须 运行 一个单独的查询来收集每个 object 的所有属性(慢, 高维护), or 为每个 object 类型编写单独的查询, 为每个属性加入 child table 一次以压平许多将每个 object 的行分成一行,有效地导致选项 1,但编写查询的维护成本更高

None 这些都是很好的选择。你要的是:

  • 每行一行 object
  • 简单查询
  • 简单架构
  • 低维护

A document database, such as Elasticsearch 为您提供了开箱即用的所有这些,但是您可以通过放宽“严格性”并将整个 object 保存为 [=92 来使用关系数据库实现相同的效果=] 在单列中:

create table object (
  id int, -- typically auto incrementing
  -- FK to parent - see below
  json text -- store object as json
);

顺便说一句,postgres 将是一个不错的选择,因为它通过 json 数据类型具有 native support for json

我在我的职业生涯中使用过几次,每次都成功。我为 object class 类型添加了一列(在 java 上下文中):

create table object (
  id int,
  -- FK to parent - see below
  class_name text,
  json text
);

并使用 json 库将使用指定 class 的 json 反序列化为 class 的 object。无论您使用何种语言,都可以通过某种方式实现这一想法。

至于层次结构,关系数据库做得很好。来自 canvas:

create table canvas (
  id int,
  -- various attributes
);

如果 object 没有重复使用:

create table object (
  id int,
  canvas_id int not null references canvas,
  class_name text,
  json text,
  layer int not null
);   

如果 object 被重复使用:

如果 object 没有重复使用:

create table object (
  id int,
  class_name text,
  json text
);

create table canvas_object (
  canvas_id int not null references canvas,
  object_id int not null references object,
  layer int not null
);