我有一个包含以下模式的数万亿条记录的大表(这里的序列号是关键):
MyTable
Column | Type | Modifiers
----------- +--------------------------+-----------
serial_number | int |
name | character varying(255) |
Designation | character varying(255) |
place | character varying(255) |
timeOfJoining | timestamp with time zone |
timeOfLeaving | timestamp with time zone |
现在,我想在此表中触发下面给出的表单的查询:
select place from myTable where Designation='Manager' and timeOfJoining>'1930-10-10' and timeOfLeaving<'1950-10-10';
我的目标是实现快速查询执行时间。因为,我从头开始设计自己的数据库,因此我有以下选择。请指导我两个选项中哪一个更快。
创建2个单独的表。这里,table1包含模式(serial_no,name,Designation,place),表2包含模式(serial_no,timeOfJoining,timeOfLeaving)。然后在两个表之间执行合并连接。这里,serial_no是两个表中的关键
保留一个单独的表MyTable。并运行以下计划:创建索引Designation_place_name并使用Designation_place_name索引,查找符合索引条件关系的行='Manager'(光盘上的行随机访问)然后使用过滤器函数仅保留与timeOfJoining匹配的行标准。
请帮我弄清楚哪一个会更快。如果你能告诉我各自的利弊,那将是很棒的。
编辑:我打算将我的表用作只读。
答案 0 :(得分:3)
如果您正在处理大量的行并且想要使用关系数据库,那么这种查询的最佳选择是完全在索引中满足它。示例查询是:
select place
from myTable
where Designation='Manager' and
timeOfJoining > '1930-10-10' and
timeOfLeaving < '1950-10-10';
索引应包含表中提到的四个字段。这表明索引如:mytable(Designation, timeOfJoining, timeOfLeaving, place)
。请注意,由于不等式,只有前两个将用于where
子句。但是,大多数数据库都会对相应的数据进行索引扫描。
如此大量的数据,您还有其他问题。虽然内存越来越便宜并且机器越来越大,但索引通常会加快查询速度,因为索引比原始表小,而且内存加载速度更快。对于“万亿”的记录,你谈论的是数十万亿字节的内存,仅用于索引 - 而且我不知道哪些数据库能够管理这么多的内存。
因为这是一个如此庞大的系统,所以硬件成本仍然相当昂贵。我建议一个自定义解决方案,以压缩格式存储数据,并为查询提供特殊用途的索引。现成的数据库是适用于几乎所有数据问题的优秀产品。但是,这似乎接近其适用范围。
与现成的数据库相比,即使很小的效率也会开始增加如此大量的数据。例如,页面上的记录布局总是在页面上留下空白空间(记录不完全适合页面,数据库具有您可能不需要的开销,例如用于可空性的位,等等)。假设页面结构和空白空间的开销达到页面大小的5%。对于大多数应用来说,这都是噪音。但是100万亿字节中有5%是5万亿字节 - 大量额外的I / O时间和浪费的存储空间。
编辑:
两种选择之间选择的真正答案是测试它们。这应该不难,因为您不需要在数万亿行上测试它们 - 如果您有硬件,那么您可以使用硬件进行较小的测试。在机器上花费几十亿行,相应地减少内存和CPU,看看哪个行更好。对结果感到满意后,将数据乘以10再试一次。如果你不相信结果,你可能想再这样做。
但我的意见是,第二个更快。第一个复制两个表中的“序列号”,每行添加8个字节(“int”通常是4个字节,并且不够大,所以你需要bigint)。仅此一项就可以增加任何分析的I / O时间和索引大小。如果您正在考虑使用柱状数据存储(例如Vertica),则可能会保存此空间。删除一列或两列的节省是以总共读取更多字节为代价的。
另外,不要在表格中存储任何变量的原始形式。 “指定”应该在查找表以及“地点”和“名称”中,因此每个都是4字节(对于维度应该足够大,除非一个人是地球上的所有人)。
但是。 。 。在成本,可维护性和可扩展性方面,“最佳”解决方案可能类似于Hadoop。这就是像谷歌和雅虎这样的公司管理大量数据的方式,而且它似乎也适用于此。
答案 1 :(得分:0)
鉴于数据的数量和类型,我建议使用第二种方案。好处是,你不需要加入任何东西。加入通常非常昂贵。但是,在这种情况下,您将持有大量冗余数据。
第一种选择是内存效率更高,第二种选择效率更高。
此外,使用索引,DBMS能够使用索引扫描从存储中读取数据。此外,您应该考虑将变长数据类型更改为固定长度数据类型,然后DBMS在元组之间跳转更容易,因为每个元组具有固定(和已知)长度。在这种情况下,像skip the next 100000 tuples
这样的操作对于DBMS来说很容易。
答案 2 :(得分:0)
很抱歉告诉您,但这个架构不适用于任何关系数据库的“万亿”记录。只是存储serial_number的索引页面和1万亿行的指定将需要465太字节。这是整个世界气候数据中心数据的两倍以上,该数据库目前是世界上最大的数据库。如果这些要求是真实的,那么您真的需要转向星形/雪花模式。这意味着此事实表中没有varchars,甚至不是日期,只有整数。将所有文本和日期字段移动到维度。
答案 3 :(得分:0)
在大多数情况下,单个表格有一定意义,但将所有这些值存储为字符串会非常荒谬,具体取决于您可以使用的名称/名称/位置字段的唯一性:
serial_number | BIGINT
name_ID | INT
Designation_ID | INT
place_ID | INT
timeOfJoining | timestamp with time zone
timeOfLeaving | timestamp with time zone
在不知道数据的情况下,不可能知道哪些查找是实用的。正如其他人提到的那样,你面临着一些挑战。关于索引,我同意戈登的意见。