数十亿行的最佳数据存储


86

我需要能够存储少量数据(大约50-75字节)以存储数十亿条记录(一年约30亿条/月)。

唯一的要求是对具有相同GUID的所有记录进行快速插入和快速查找,并能够从.net访问数据存储。

我是一名SQL Server专家,我认为SQL Server可以做到这一点,但是在所有有关BigTable,CouchDB和其他nosql解决方案的讨论中,听起来越来越像传统RDBS的替代方法可能是最佳的选择,因为分布式查询和扩展。我尝试过cassandra,.net库目前无法编译或全部更改(以及cassandra本身)。

我已经研究了许多可用的nosql数据存储,但是找不到一个能够满足我作为强大的生产就绪平台的需求的数据存储。

如果您必须存储360亿条小型平面记录,以便可以从.net进行访问,那么会选择什么,为什么呢?


是的,我的数字是正确的。当前,我们有这么多数据进入系统,但是我们将其汇总并仅存储汇总计数,因此我们将丢失每条记录的数据并仅维护每小时的数据总和。由于业务需求,我们希望保留每条记录的原始记录,即每月3Bil行。
乔迪·普莱特

您提出了一些很好的问题。答案是:95%的正常运行时间就足够了-数据已经延迟了可变的数量,因此无论如何我都需要在事实发生后将其同步,因此短时间内的中断不会成为问题。丢失刀片甚至数千个刀片并不是世界末日。但是,丢失一天的数据价值将是非常糟糕的。一致性也不是那么重要。基本上,在一天中插入30Mil行之后,我需要使用相同的GUID(可能是20行)来获取所有行,并合理地确定我会把它们全部收回。
乔迪·普莱特

您是每天/每小时排定的批处理作业中丢弃3000万行,还是一次不断地添加它们?
雷木斯·鲁萨努

数据来自FTP站点...文件不断传入,我有一个解析文件的过程,当前它会生成汇总数据并插入汇总值(可能是1000行)作为事务。新过程将需要从每个到达的文件中插入成千上万的行,可能使用批量插入将是最有效的方式。
乔迪·普莱特

这听起来像是SSIS和SQL Server的ETL作业。他们确实以超过2TB /小时的上传速度保持了ETL的世界纪录:blogs.msdn.com/sqlperf/archive/2008/02/27/etl-world-record.aspx
Remus Rusanu 2010年

Answers:


102

使用SQL Server可以存储约3.5TB的数据并以1k / sec的速度24x7插入,并以未指定的速率进行查询,但是SQL Server可以实现此功能,但是还有更多问题:

  • 您对此有什么可用性要求?正常运行时间为99.999%,还是足够95%?
  • 您有什么可靠性要求?缺少插入物会花费您100万美元吗?
  • 您有什么可恢复性要求?如果您丢失一天的数据,这有关系吗?
  • 您有什么一致性要求?是否需要保证写操作在下一次读取时可见?

如果您需要我强调的所有这些要求,那么无论您尝试使用哪种俩(分片,分区等),建议的负载都将在关系系统,任何系统上花费数百万美元的硬件和许可费用。按照其定义,nosql系统将无法满足所有这些要求。

因此,显然您已经放宽了其中一些要求。在Visual Guide to NoSQL Systems上有一个很好的可视化指南,比较了基于'pick 2 out of 3'范式的nosql产品:

Nosql比较

OP评论更新后

使用SQL Server,这将直接实现:

  • 一个单表集群(GUID,时间)键。是的,将会变得碎片化,但是碎片会影响预读并且仅在进行有效范围扫描时才需要预读。由于您仅查询特定的GUID和日期范围,因此碎片不会有太大关系。是的,它是一个宽键,因此非叶子页的键密度很低。是的,这将导致不良的填充系数。是的,可能会发生页面拆分。尽管存在这些问题,但鉴于要求,仍然是最佳的群集密钥选择。
  • 按时间对表进行分区,以便您可以通过自动滑动窗口有效地删除过期的记录。通过上个月的联机索引分区重建来增强此功能,以消除GUID群集引入的不良填充因子和碎片。
  • 启用页面压缩。由于GUID首先聚集了键组,因此GUID的所有记录将彼此相邻,这为页面压缩提供了部署字典压缩的好机会。
  • 您将需要一个用于日志文件的快速IO路径。您感兴趣的是高吞吐量,而不是低延迟,这样日志才能保持每秒1K次插入,因此剥离是必须的。

分区和页面压缩都需要企业版SQL Server,它们在标准版上将不起作用,并且两者对于满足要求都非常重要。

附带说明一下,如果记录来自前端Web服务器场,则我将Express放在每个Web服务器上,而不是在后端插入INSERT,而是SEND使用本地连接/事务将信息发送到后端在Express上与Web服务器位于同一位置。这为解决方案提供了更好的可用性。

所以这就是我在SQL Server中要做的事情。好消息是,您将面临的问题已得到充分理解,解决方案也已广为人知。这并不一定意味着它比使用Cassandra,BigTable或Dynamo所能达到的更好。我会让某人对no-sql-ish的事情更加了解。

请注意,我从未提到过编程模型,.Net支持等。老实说,我认为它们与大型部署无关。它们在开发过程中起着巨大的作用,但是一旦ORM开销降低了性能,部署一旦成功就无关紧要了:)


我热链接了Nathan的网站,但这不是slashdot主页;)
Remus Rusanu 2010年

@RemusRusanu:正在查看dba.se迁移。只是为您准备:-)和+1
gbn 2012年

从Microsoft SQL Server 2016开始,表分区不再需要企业版,因为SQL Server 2016的几乎所有版本现在都可以使用表分区
。– TChadwick

17

与流行的看法相反,NoSQL与性能甚至可伸缩性无关。这主要是为了最大程度地减少所谓的“对象关系”阻抗失配,而且还涉及水平可伸缩性与RDBMS的更典型的垂直可伸缩性。

对于快速插入和快速查找的简单要求,几乎所有数据库产品都可以使用。如果要添加关系数据或联接,或者需要执行任何复杂的事务逻辑或约束,则需要一个关系数据库。NoSQL产品无法比拟。

如果需要无模式数据,则需要使用面向文档的数据库,例如MongoDB或CouchDB。松散的架构是其中的主要吸引力。我个人喜欢MongoDB,并在一些自定义报告系统中使用它。当数据需求不断变化时,我发现它非常有用。

NoSQL的另一个主要选项是分布式键值存储,例如BigTable或Cassandra。如果要跨运行商用硬件的许多计算机扩展数据库,这些功能特别有用。显然,它们在服务器上也能很好地工作,但是它们并没有利用高端硬件以及SQL Server或Oracle或其他为垂直扩展而设计的数据库的优势,并且显然,它们没有关系,也不利于执行规范化或约束。另外,您已经注意到,.NET支持充其量是最多的。

所有关系数据库产品都支持有限种类的分区。它们不像BigTable或其他DKVS系统那样灵活,它们无法轻松地在数百台服务器之间进行分区,但是听起来确实不是您要的那样。只要您正确索引和规范化数据,在功能强大的硬件上运行数据库(尤其是如果可以负担的话,SSD),并在2或3或5个物理磁盘上进行分区,它们就可以很好地处理数十亿个记录。必要。

如果您符合上述条件,并且您正在公司环境中工作,并且有足够的钱花在体面的硬件和数据库优化上,那么我现在会坚持使用SQL Server。如果您花了几分钱,并且需要在低端Amazon EC2云计算硬件上运行它,那么您可能想要选择Cassandra或Voldemort(假设您可以使用.NET进行操作)。


11

很少有人以数十亿行集的大小工作,而且大多数情况下,我在堆栈溢出时看到这样的请求,但数据却远不如所报告的那样大。

360亿,每月30亿,即每天大约1亿,每小时416万,每分钟约7万行,每秒11k行,并持续12个月进入系统,前提是没有停机时间。

这些数字不是不可能的,我已经完成了较大的系统,但是您想仔细检查一下这实际上是您要指的数量-很少有应用程序真正具有此数量。

在存储/检索方面,您没有提到的一个关键方面是老化旧数据-删除不是免费的。

正常的技术是基于分区,但是,假设您必须在整个12个月的时间内获得每个匹配的值,基于GUID的查找/检索将导致性能不佳。您可以在GUID列上放置聚簇索引,以使您的关联数据聚簇以进行读/写,但是在这样的数量和插入速度下,碎片将太高而无法支撑,并且将落在地板上。

我还建议您,如果这是一个具有OLTP类型响应速度的严肃应用程序,那么您将需要非常合理的硬件预算,这是通过一些近似的猜测得出的,假设很少有开销明智地索引了大约2.7TB的数据。

在SQL Server阵营中,您唯一想看的就是新的并行数据仓库版本(madison),该版本设计用于分拆数据并对其进行并行查询,以针对大型数据集市提供高速。


3
在生物信息学中,数十亿行的数据集并不少见。但是,它们经常以纯流方式从平面文件中处理。
艾里克·加里森

3
@Erik:对于流处理(即只需要检测某些条件,但无需存储数据以供以后查询)之类的StreamInsight优于任何数据库microsoft.com/sqlserver/2008/en/us/r2 -complex-event.aspx
Remus

2

“我需要能够存储少量数据(大约50-75字节),以存储数十亿条记录(每年约30亿条/月)。

唯一的要求是对具有相同GUID的所有记录进行快速插入和快速查找,并能够从.net访问数据存储。”

我可以从经验中告诉您,这是可以在SQL Server中实现的,因为我在2009年初就已经做到了……而且直到现在,它仍然可以运行并且非常快。

该表被划分为256个分区,请记住,这是2005 SQL版本……而我们正是按照您的意思说的,即通过GUID存储信息位并通过GUID快速检索。

当我离开时,我们有大约2-3亿条记录,即使数据保留策略即将实例化,数据检索仍然相当不错(如果通过UI获得则为1-2秒,如果通过RDBMS获得则更少)。

因此,长话短说,我从GUID字符串中提取了第8个字符(即,位于中间位置的某个地方),并将SHA1对其进行哈希处理并转换为微小的int(0-255),并存储在适当的分区中,并在获取时使用了相同的函数调用数据返回。

ping我,如果您需要更多信息...


2

下面的文章讨论了Microsoft SQL中160亿行表的导入和使用。 http://sqlmag.com/t-sql/adventures-big-data-how-import-16-billion-rows-single-table

从文章:

以下是根据我的经验总结的一些技巧:

  • 具有定义的聚集索引的表中的数据越多,将未排序的记录导入到表中的速度就越慢。在某些时候,它变得太慢而无法实用。
  • 如果要将表导出到最小的文件,请使其成为本机格式。这最适合包含大多数数字列的表,因为它们在二进制字段中比字符数据更紧凑地表示。如果您所有的数据都是字母数字,那么以本机格式导出数据将不会带来很多好处。在数字字段中不允许使用空值可以进一步压缩数据。如果允许字段为空,则该字段的二进制表示形式将包含一个1字节的前缀,指示将跟随多少字节的数据。
  • 您不能将BCP用于超过2,147,483,647条记录,因为BCP计数器变量是4字节整数。我在MSDN或Internet上找不到对此的任何引用。如果您的表包含
    超过2,147,483,647条记录,则必须将其分块导出
    或编写自己的导出例程。
  • 在预填充表上定义聚簇索引会占用大量磁盘空间。在我的测试中,我的日志
    在完成之前爆炸到原始表大小的10倍。
  • 使用BULK INSERT语句导入大量记录时,请包括BATCHSIZE参数并指定
    一次要提交多少条记录。如果不包括此参数,则
    整个文件将作为单个事务导入,这
    需要大量的日志空间。
  • 将数据放入具有聚簇索引的表中的最快方法是首先对数据进行预排序。然后,可以使用
    带有ORDER参数的BULK INSERT语句导入它。

1

有一个不寻常的事实似乎被忽略了。

基本上,在一天中插入30Mil行之后,我需要使用相同的GUID(可能是20行)来获取所有行,并有理由确定我会把它们全部收回

只需要20列,GUID上的非聚集索引就可以正常工作。您可以群集在另一列上,以实现跨分区的数据分散。

我对数据插入有一个疑问:如何插入?

  • 这是按特定时间表(每分钟,每小时等)进行批量插入吗?
  • 从什么来源(平面文件,OLTP等)中提取此数据?

我认为需要回答这些问题以帮助理解方程式的一方面。


1

Amazon Redshift是一项出色的服务。该问题最初于2010年发布时不可用,但现在在2017年成为主要参与者。它是基于列的数据库,由Postgres派生,因此可以使用标准SQL和Postgres连接器库。

最好用于报告目的,尤其是汇总。单个表中的数据存储在Amazon云中的不同服务器上,并通过定义的表distkey进行分发,因此您依赖于分布式CPU功能。

因此,SELECT(尤其是聚合的SELECT)非常快。加载大数据最好使用Amazon S3 csv文件中的COPY命令完成。缺点是DELETE和UPDATE的速度比平常慢,这就是为什么Redshift不在主要是跨国数据库中,而在更多的数据仓库平台中。


0

您可以尝试使用Cassandra或HBase,尽管您需要阅读有关如何根据用例设计列族的信息。Cassandra提供了自己的查询语言,但是您需要使用HBase的Java API来直接访问数据。如果您需要使用Hbase,那么我建议使用Map-R(一个开放源代码项目)中的Apache Drill查询数据。Drill的查询语言兼容SQL(Drill中的关键字与SQL中的关键字具有相同的含义)。


0

每年有那么多记录,您最终将用尽空间。为什么不支持xfs之类的文件系统存储,它支持2 ^ 64个文件并使用较小的盒子。不管人们想要多花钱,或者最终要花多少钱,使用一个具有任何数据库SQL NoSQL ..的系统,无论花多少钱,通常都是由电力公司和气象台/提供者(如环境部)控制的,全国各地的电台。如果您正在执行存储压力..温度。风速..湿度等...之类的操作,并且guid是位置..您仍然可以按年/月/日/小时除以数据。假设每个硬盘驱动器存储4年的数据。然后,您可以在具有镜像功能的较小Nas上运行它,在该处还可以提供更好的读取速度并具有多个安装点。基于创建年份。您可以简单地通过网络界面进行搜索,因此,转储location1 / 2001/06/01 //温度和位置1/2002/06/01 // temperature只会在那两年(24h * 2)中的夏季第一天(每小时24小时* 2)中转储每小时温度的内容,而不是搜索具有数十亿条记录且可能花费数百万美元的数据库。查看事物的简单方法。与上帝一起,世界上有15亿个网站知道每个页面有多少个页面。如果像Google这样的公司必须每30亿次搜索花费数百万美元才能为此购买超级计算机,那么它们将被打破。取而代之的是,他们拥有电力账单……几百万台废话电脑。咖啡因索引...耐久..请继续添加。是的,在其中运行SQL的索引才有意义,那么就可以构建超级计算机来处理诸如天气等固定问题的繁琐任务……统计数据等,以便技术人员可以在x秒内夸大其系统崩溃xtb ...可能浪费金钱花在其他地方


-2

将记录存储在纯二进制文件中(每个GUID一个文件)不会比这更快。


5
您真的希望它执行良好吗?
ChaosPandion 2010年

3
是的,在文件系统上创建数十亿个文件可能会破坏某些文件系统。我犯了这样的错误,但是只有一百万个错误,我几乎把系统关闭了,试图打开其中一个文件夹的外壳。另外,除非您基于GUID查找,否则查询机制应该如何工作?
罗布·古德温

在不知道期望有多少唯一的GUID的情况下很难猜测它会如何执行:)但是,这并不比简单地写入普通文件更简单。快速插入和GUID查找是唯一要求。
ThomasKjørnes2010年

它可以工作,但是您必须限制每个文件夹的文件数。您必须每n个文件生成一个新文件夹。您可以使用guid的子字符串作为文件夹名称。
TTT 2010年

1
是的,很多文件系统的inode数量是有限制的,我记得在Redhat默认文件系统上达到了这个限制....限制约为1,000,000个文件左右。
迪恩·希勒

-3

您可以使用MongoDB并将GUID用作分片键,这意味着您可以将数据分布在多台计算机上,但是要选择的数据仅在一台计算机上,因为您是通过分片键进行选择的。

MongoDb中的分片尚未准备就绪。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.