1

我有一个包含以下模式的数万亿条记录的大表(这里序列号是关键):

                  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';

我的目标是实现快速的查询执行时间。因为,我正在从头开始设计自己的数据库,因此我有以下选择。请指导我这两个选项中的哪一个会更快。

  1. 创建2个单独的表。在这里,table1 包含模式(serial_no、name、Designation、place),表 2 包含模式(serial_no、timeOfJoining、timeOfLeaving)。然后在两个表之间执行合并连接。这里,serial_no 是两个表中的键

  2. 保留一个单一的表 MyTable。并运行以下计划:创建一个索引 Designation_place_name 并使用 Designation_place_name 索引,找到符合索引条件关系 = 'Manager'(磁盘上的行是随机访问的)的行,然后使用过滤功能只保留与 timeOfJoining 匹配的行标准。

请帮我弄清楚哪一个会更快。如果你也能告诉我各自的利弊,那就太好了。

编辑:我打算将我的表用作只读。

4

4 回答 4

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。这就是像谷歌和雅虎这样的公司管理大量数据的方式,在这里看起来也很合适。

于 2013-06-23T18:54:40.363 回答
0

在大多数情况下,单个表是有意义的,但是将所有这些值存储为字符串是荒谬的,这取决于您的名称/名称/位置字段的唯一性,您可以使用如下内容:

 serial_number         | BIGINT  
 name_ID               | INT   
 Designation_ID        | INT 
 place_ID              | INT    
 timeOfJoining         | timestamp with time zone 
 timeOfLeaving         | timestamp with time zone  

如果不知道数据,就不可能知道哪些查找是实用的。正如其他人所提到的,您将面临一些挑战。关于索引,我同意 Gordon 的观点。

于 2013-06-23T19:44:36.330 回答
0

很遗憾地告诉你,但这个模式不适用于任何关系数据库的“万亿”记录。仅存储 1 万亿行的 serial_number 和 Designation 的索引页就需要 465 TB。这比目前保持世界纪录最大的整个世界气候数据中心数据库的规模大了一倍多。如果这些要求是真实的,那么您确实需要迁移到星形/雪花模式。这意味着这个事实表中没有 varchars,甚至没有日期,只有整数。将所有文本和日期字段移动到维度。

于 2013-06-23T19:30:28.757 回答
0

鉴于数据的数量和类型,我建议使用第二种选择。好处是,你不需要加入任何东西。连接通常非常昂贵。但是,在这种情况下,您会持有大量冗余数据。

第一个选项将更节省内存,第二个更节省时间。

此外,使用索引,DBMS 能够使用索引扫描从存储中读取数据。此外,您应该考虑将可变长度数据类型更改为固定长度数据类型,然后 DBMS 可以更轻松地在元组之间跳转,因为每个元组都有固定(且已知)的长度。在这种情况下,skip the next 100000 tuples对于 DBMS 来说,类似的操作很容易。

于 2013-06-23T18:59:19.167 回答