使用更扁平模式的性能影响
Performance implications of using a flatter schema
我正在使用 FlatBuffers (C++) 来存储有关文件的元数据信息。这包括 EXIF、IPTC、GPS 和各种其他元数据值。
在我当前的模式中,我有一个相当 规范化的 定义,上面列出的每个组都有自己的 table。根 table 只包含每个子 table 的属性。
基本示例:
table GPSProperties {
latitude:double;
longitude:double;
}
table ContactProperties {
name:string;
email:string;
}
table EXIFProperties {
camera:string;
lens:string;
gps:GPSProperties;
}
table IPTCProperties {
city:string;
country:string;
contact:ContactProperties;
}
table Registry {
exifProperties:EXIFProperties;
iptcProperties:IPTCProperties;
}
root_type Registry;
这可行,但构建缓冲区时的嵌套限制开始使代码变得相当混乱。同样,将属性分解为单独的 tables 只是为了在模式中清晰。
我正在考虑 "flattening" 将整个架构合并为一个 table,但我想知道这样做是否对性能或内存有任何影响。这个 table 可以 有几百个字段,尽管大多数都是空的。
提案:
table Registry {
exif_camera:string;
exif_lens:string;
exif_gps_latitude:double;
exif_gps_longitude:double;
iptc_city:string;
iptc_country:string;
iptc_contact_name:string;
iptc_contact_email:string;
}
root_type Registry;
由于未设置或设置为其默认值的属性不会占用任何内存,因此我倾向于认为扁平化模式可能不是问题。但我不确定。
(请注意,性能是我最关心的问题,紧随其后的是内存使用。规范化模式表现出色,但我认为扁平化模式确实可以帮助我清理代码库。)
您应该首先了解的基础知识:
每个 table 的顶部都有一个 vtable,它告诉可以找到 table 的每个字段的偏移量。如果一个table中的字段太多,这个vtable会变大,不管你存不存。
如果您尝试创建 table 的层次结构,则您正在创建额外的 vtable,并且还会为设计增加间接成本。
如果多个对象中存储了相似的数据,则 vtable 也会共享。就像您创建的对象仅使用 exif_camera 变量一样!
因此,这取决于您的数据是否庞大且异构,是否使用更有条理的层次结构。但是,如果您的数据将是同质的,则更喜欢扁平化的 table.
由于您的大部分数据都是字符串,因此这两种设计的大小和速度将非常相似,因此您应该从软件工程的角度根据更适合您的方式进行选择。
也就是说,平面版本可能会在大小上更有效(更少 vtables)并且肯定会更快地访问(尽管再次强调,考虑到它主要是字符串数据,这是微不足道的).
平面版本可能效率较低的唯一方法是,如果您将大量它们存储在一个缓冲区中,其中设置的字段在每个 table 之间变化很大。那么非扁平化版本可能会产生更多的vtable分享。
在非平面版本中,table如 GPSProperties
可能是 struct
如果字段不太可能改变,这样会更有效率。
This single table could have a few hundred fields, though most would
be empty.
性能成本可能很小,您不会注意到,但对我来说,您上面的引述是决定使用哪种设计的摇摆因素。
当其他人在谈论vtables的成本时;我根本不会担心那个。每个 class 有一个 vtable,每个 运行 准备一次并且不会很昂贵。
拥有 100 个空的和未使用的字符串将非常昂贵(内存使用明智)并且会耗尽您创建的每个对象;此外,阅读您的字段将变得更加复杂,因为您不能再假设您阅读的 class 的所有数据都在那里。
如果大多数/所有字段一直都在,那么我就可以看到做单的吸引力了class;但他们不是。
我正在使用 FlatBuffers (C++) 来存储有关文件的元数据信息。这包括 EXIF、IPTC、GPS 和各种其他元数据值。
在我当前的模式中,我有一个相当 规范化的 定义,上面列出的每个组都有自己的 table。根 table 只包含每个子 table 的属性。
基本示例:
table GPSProperties {
latitude:double;
longitude:double;
}
table ContactProperties {
name:string;
email:string;
}
table EXIFProperties {
camera:string;
lens:string;
gps:GPSProperties;
}
table IPTCProperties {
city:string;
country:string;
contact:ContactProperties;
}
table Registry {
exifProperties:EXIFProperties;
iptcProperties:IPTCProperties;
}
root_type Registry;
这可行,但构建缓冲区时的嵌套限制开始使代码变得相当混乱。同样,将属性分解为单独的 tables 只是为了在模式中清晰。
我正在考虑 "flattening" 将整个架构合并为一个 table,但我想知道这样做是否对性能或内存有任何影响。这个 table 可以 有几百个字段,尽管大多数都是空的。
提案:
table Registry {
exif_camera:string;
exif_lens:string;
exif_gps_latitude:double;
exif_gps_longitude:double;
iptc_city:string;
iptc_country:string;
iptc_contact_name:string;
iptc_contact_email:string;
}
root_type Registry;
由于未设置或设置为其默认值的属性不会占用任何内存,因此我倾向于认为扁平化模式可能不是问题。但我不确定。
(请注意,性能是我最关心的问题,紧随其后的是内存使用。规范化模式表现出色,但我认为扁平化模式确实可以帮助我清理代码库。)
您应该首先了解的基础知识:
每个 table 的顶部都有一个 vtable,它告诉可以找到 table 的每个字段的偏移量。如果一个table中的字段太多,这个vtable会变大,不管你存不存。
如果您尝试创建 table 的层次结构,则您正在创建额外的 vtable,并且还会为设计增加间接成本。
如果多个对象中存储了相似的数据,则 vtable 也会共享。就像您创建的对象仅使用 exif_camera 变量一样!
因此,这取决于您的数据是否庞大且异构,是否使用更有条理的层次结构。但是,如果您的数据将是同质的,则更喜欢扁平化的 table.
由于您的大部分数据都是字符串,因此这两种设计的大小和速度将非常相似,因此您应该从软件工程的角度根据更适合您的方式进行选择。
也就是说,平面版本可能会在大小上更有效(更少 vtables)并且肯定会更快地访问(尽管再次强调,考虑到它主要是字符串数据,这是微不足道的).
平面版本可能效率较低的唯一方法是,如果您将大量它们存储在一个缓冲区中,其中设置的字段在每个 table 之间变化很大。那么非扁平化版本可能会产生更多的vtable分享。
在非平面版本中,table如 GPSProperties
可能是 struct
如果字段不太可能改变,这样会更有效率。
This single table could have a few hundred fields, though most would be empty.
性能成本可能很小,您不会注意到,但对我来说,您上面的引述是决定使用哪种设计的摇摆因素。
当其他人在谈论vtables的成本时;我根本不会担心那个。每个 class 有一个 vtable,每个 运行 准备一次并且不会很昂贵。 拥有 100 个空的和未使用的字符串将非常昂贵(内存使用明智)并且会耗尽您创建的每个对象;此外,阅读您的字段将变得更加复杂,因为您不能再假设您阅读的 class 的所有数据都在那里。
如果大多数/所有字段一直都在,那么我就可以看到做单的吸引力了class;但他们不是。