假设我有一个画布,其中有我可以添加的各种对象,例如a/an:
- 绘图
- 图像
- 图表
- 备注
- 表
对于每个对象,我需要存储尺寸和层顺序,例如:
- 对象ID
- 分层索引
- 尺寸((x1,y1),(x2,y2))
每个对象都有非常不同的属性,因此存储在不同的表(或类或其他什么)中。有可能将其存储到关系数据库中吗?如果有,如何做到这一点?在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)]},
...
]
我想到的一个选项是为每个表存储一个FK,但在这种情况下,我可能会将其连接到每个对象类型的N个不同表中,所以如果有100个对象类型。。。
A"严格的";关系数据库不适合这个任务,因为您只能选择:
- 每个对象类型都有不同的表,每个属性都有一列应用于特定对象类型
- 所有对象类型的单个表,每个属性都有列,其中大多数不用于任何给定的对象类型
- 一个子表,每个属性一行
在转到一个好的通用解决方案之前。,让我们讨论一下:
1.每种对象类型都有不同的表
这是一个不启动。问题是:
- 高昂的维护成本:每次向应用程序添加新的对象类型时,都必须创建一个新表
- 痛苦的查询:您必须连接到每个表,要么水平连接到一个非常长的行中,要么垂直连接到一系列未连接的连接中,从而生成稀疏数组(请参见选项2)
2.用于所有对象类型的单个表
尽管您处理的是稀疏数组,但如果大多数对象类型使用大多数属性(即不是的稀疏),这是一个不错的选择。然而,如果域中不同属性的数量很高,并且/或者大多数属性不是所有类型都使用的,则在引入新类型时必须添加列,尽管这比添加表要好,但仍然需要对新类型进行架构更改=高维护
3.儿童餐桌
这是一种经典的方法,但使用起来更糟,因为您要么必须运行一个单独的查询来收集每个对象的所有属性(缓慢、高维护),要么或为每个对象类型编写单独的查询,为每个属性连接一次子表,将多行扁平化为每个对象的一行,有效地产生了选项1,但是写查询的维护成本甚至更高
这些都不是很好的选择。你想要的是:
- 每个对象一行
- 简单查询
- 简单架构
- 低维护
文档数据库,如Elasticsearch,可以开箱即用地为您提供所有这些功能,但您可以通过放松";严格性";并将整个对象保存为一列中的json:
create table object (
id int, -- typically auto incrementing
-- FK to parent - see below
json text -- store object as json
);
顺便说一句,postgres是一个不错的选择,因为它通过json
数据类型对json有原生支持。
在我的职业生涯中,我已经用过好几次了,总是很成功。我为对象类类型添加了一列(在java上下文中):
create table object (
id int,
-- FK to parent - see below
class_name text,
json text
);
并使用json库将使用指定类的json反序列化为该类的对象。无论你使用什么语言,都有办法实现这个想法。
至于层次结构,关系数据库可以很好地做到这一点。来自画布:
create table canvas (
id int,
-- various attributes
);
如果对象未被重用:
create table object (
id int,
canvas_id int not null references canvas,
class_name text,
json text,
layer int not null
);
如果对象被重复使用:
如果对象未被重用:
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
);
您有许多选项,如下所示。
你选择哪一个没有太大区别,但我会避免你所说的多桌设计。一个具有100个属性的对象类型将被分散在101个表中而没有增益。针对正在读取的每种对象类型进行101次磁盘页面访问。这是不必要的(如果这些页面被缓存,那么这个问题会比其他情况下小,但仍然是浪费)。
如果你不想过滤"所有颜色为红色的对象"之类的东西,即使是双表也不是真正必要的,但我想性能并不是那么迫切需要达到这一点,其他事情更重要,或者其他瓶颈对性能的影响更大,所以从不超过双表中选择一个最适合你的。
单表-每个对象类型的灵活架构
objectlayerindex | 类型 | 道具x0 | y0 | <1>x1 | y1||
---|---|---|---|---|---|---|
0 | 绘图 | {颜色:#00FF00,背景色:#00FFFF} | <1>2 | 3 | 4 | |
1 | 图表 | {标题:2021_sales,值:[[0,0],[3,4]]} | <11><22>>33 | 44