具有空间查询/索引的大数据

时间:2015-06-07 00:31:56

标签: sql-server mongodb database-design data-warehouse database-performance

目前,我正在使用SQL Server,并且在每天进行大约一百万次写入的扩展无法连接的1亿条记录时遇到问题,32 GB的ram用完了,CPU大多数时间处于80%-90%。这让我厌倦了继续使用SQL服务器,但如果可能的话,我想继续使用它。 我一直在研究mongoDB。

我有一个新项目,它需要存储大约1亿个空间记录,所有空间记录都作为折线,并且具有与几何相关联的15个左右的属性。我知道SQL Server和mongoDB都支持空间索引,mongoDB使用较低的(如我所读)Geohash与R-tree索引相比。

我认为他们在GIS数据的性能方面取得了平衡,因为我觉得即使mongoDB具有较差的空间索引,它也只会根据其读取速度与SQL Server相比的剪切性能来构成。

我所遇到的真正问题是每一条折线,都会有时间数据与每条折线相关联。这个数字在20到2000之间,取决于它的扩展程度。现在有20亿,有可能增长到2000亿。

折线数据不会超过1亿,每条记录约为1KB(100 GB)。如果我们存储所有非标准化的数据,并且不关心重复GIS数据以避免进行JOIN,那就是2-200 TB,基本上不能由我管理。

因此,我认为需要进行一些非规范化,一个表/集合中的GIS数据和另一个表中的相关时间数据。

请稍后注意,地图请求将进入并请求一个应该查询该边界框(想想空间交叉点)的所有GIS信息的图块,并使用此结果,需要查询一个时间范围内的timedata AVERAGE选定的折线。当数据集到达地图渲染器时,它必须在一起(JOINED)。当地图被平移时,所有这些将每秒发生12-20次,因为地图将根据时间数据为折线着色。

我的问题是,考虑到mongoDB的空间索引性能,使用geoIntersects时会出现1亿到250,000条记录的问题吗?

然后,一旦找到250,000个折线,我就需要查询时间数据,以获得某个WHERE子句的250,000多段线所用的时间,很可能是一个时间范围。 mongoDB可以实现这一点,因为该表将包含超过20亿条记录,并且在亚秒内完成吗?

现在,我可以使用空间索引在大约4秒内在SQL Server 2012中从200万到200,000多折线。这是可以接受的,但它并没有考虑到时间数据,而是数据的数量将会减少50倍。

我觉得使用mongoDB进行JOIN操作会破坏mongoDB的目的而不会产生比SQL Server更好的性能。

完成此任务的数据库建议是什么?

要点:

  • 支持空间索引,以便正确查询GIS数据。

  • 数据每年只会写入,基本上是100%读取。

  • 对timedata的大多数查询都需要一个时间范围内的AVERAGE

  • 低负荷,在任何给定时间仅连接2-10个用户

服务器/服务器每月的预算约为1000美元。

编辑:

时间数据包括以15分钟为间隔的道路段的报告英里/小时。用户搜索将是“我希望在过去3个月内看到这条道路的平均速度”

地图引擎然后根据基于平均速度的图例渲染它。地图引擎需要知道每条道路/折线的颜色,因此如果在地图上有X道路,则需要X值和X折线。

2 个答案:

答案 0 :(得分:3)

  

数据每年只会写入,基本上是100%读取。

     

...对timedata的大多数查询都需要一个时间范围内的AVERAGE

这两件事,100%读取和聚合听起来像数据仓库/星形结构将值得探索。要正确构建这样的结构,还有很多概念需要理解,但是我们可以找到潜在的设计。

  

时间数据包括道路段的报告英里/小时   每隔15分钟。用户搜索将是"我想看到   在过去的3个月里,这条道路的平均速度在过去3个月"

当你以15分钟的间隔说,我假设我们可能有5个人在下午1:15 - 1:30之间通过该段,因此在那个时间段内有5个记录。

对于之前从未构建过数据仓库的人来说,这将是一个令人不舒服的练习,但作为对这些方法持怀疑态度并将其付诸实践的人,我已经看到你可以得到一个巨大的性能提升。换句话说,我是一个持怀疑态度的皈依者。通常,您将规范化的数据库保留在操作事务中,然后每晚/每周从中填充数据仓库。

重要的是要知道你将使用哪种类型的查询,因为我们设计了星形结构以适应它们。虽然它并没有严格限制查询,但你仍然有很多灵活性。有很多基于星形结构的通用分析/ OLAP工具,它们的灵活性证明了这一点。

日期/时间维度 我们要做的第一件事是创建时间和日期维度。时间维度中的每一行代表15分钟的间隔。我会记录某个开始/结束包含/独占的地方,因此明显包含/排除围栏上的任何时间。它只有96行,一天每15分钟一个。

Id,StartTime(inclusive),EndTime(exclusive)
 1, 0:00, 0:15
 2, 0:15, 0:30
...
95,23:30,23:45
96,23:45,24:00

日期维度可以通过几种不同的方式设计。为了最大限度地提高分析灵活性,我们通常会在数据涵盖的每一天都有一行。这对于具有标准化数据库设计背景的人来说似乎很荒谬,但它在数据仓库中是非常标准的做法,而数据仓库书籍中的完整章节确实解释了原因。有些脚本可以帮助您在日期维度中生成条目。如果您的数据涵盖2000并且您计划在未来几年内重新加载数据库,那么您将为2000年到2020年的每一天创建条目,这些条目仅为7300行(20年* 365天)。考虑到这可以很容易地缓存在非常少量的内存中。

Id,Date(date),Year(smallint),Month(tinyint),Day(tinyint),MonthName,MonthAbbreviation,DayOfWeekNumber(tinyint),DayOfWeekName....
1000,2015,5,15,... 
1001,2015,5,16,...
1002,2015,5,17,...

所有额外列(例如DayOfWeekNumber和DayOfWeekName)的原因是支持对这些属性或组合进行非常简单的聚合。使groupby DayOfWeekNumber变得非常简单,因此您可以通过不同的方式进行趋势分析。

Poly Dimension 对于多边形维度,每个路段都有一行。我做出了这个选择,因为多个时间条目将共享一个多段,因此我们希望下面的事实表中的polyId可以分组。

速度事实表 该表将是具有大量记录的表。事实表中的每一行应尽可能小。这最大化了I / O吞吐量,聚合速度以及在内存中尽可能多地进行缓存的能力。

例如,DateId应该是smallint,因为2个字节足以表示32767个ID,远远超过20年数据所需的7300个空间60多年。 TimeId会很小。人们会说存储便宜,但这不是驱动因素。 I / O吞吐量和缓存利用率是小行大小很重要的原因(因此每页行数)。

RoadSegmentId, TimeId, DateId, Speed
1,1,1,45
1,1,1,47
1,1,1,92
1,2,1,55
1,2,1,67
1,2,1,91
2,1,1,55
2,2,1,67
2,2,1,91
...

<强>查询

&#34;我想在过去的3个月里看到这条路的平均速度,并且#34;

Select rsd.Polygon, Avg(f.Speed)
From SpeedFacts f
Inner Join DateDimension dd on f.DateId = dd.Id
Inner Join RoadSegmentDimension rsd on f.RoadSegmentId = rsd.Id
Where dd.DayOfWeekNumber = 5 and dd.Date > '3/6/2015' --you could of course get current date, subtract 3 months to make this more generic
   and rsd.Polygon.STIntersects(@boundingBox)
Group By f.RoadSegmentId, rsd.Polygon

所以有一些事情需要注意。如果没有测试,SQL服务器如何选择优化这一点很难说,但结构允许一条似乎有效的路径:

  1. 从大于3/6/2015的DateDimension行和DayOfWeekNumber中选择5.每个行都应该有一个索引,页面读取应该具有良好的利用率,因为行物理排序会将它们放在相同的页面中。这会产生12行,每周一行。
  2. 现在,SQL Server只有12个DateId,并且可以使用SpeedFacts.DateID上的索引来缩小SpeedFacts要读取的行/页面。
  3. SpeedFacts.DateId索引比我们有一个实际日期类型的SpeedFacts.Date列要小很多。因此,数百万行的索引要小得多,因此SQL Server可以更快地读取它。从而缩小了对事实表感兴趣的行数。

    唯一令我担心的是取决于您的数据模式,这可能无法消除对RoadSegmentDimension中每个多边形执行STIntersects的需要。如果你有稀疏速度测量,很多段在某些时间段内没有任何读数,那么加入RoadSegementDimension的第三步可能会消除很多多边形,然后应用StIntersects只会其余多边形上的必要条件。

    无论如何,希望它能够在执行空间比较之前非常有效地缩小事实行的数量。

    无论哪种方式,我认为你会看到这种结构在更传统的结构上的显着性能,并且打赌性能增益大于引擎之间的任何差异。

    我不太了解MongoDB,但是我已经使用过其他类型的NoSQL / document / json数据库,而且我不确定那种引擎真的很适合这个分析类型。

答案 1 :(得分:0)

如果您最终想要更深入地探索 Geohash 路线,这里是您可能感兴趣的用于 TSQL 的 Geohash 相关函数的更加充实的实现。

关于R-Tree Indexes 和Integer-based Geohashes 性能之间的争论,我对大数据场景有不同的经验。使用索引数组、哈希表和树之间的权衡与软件工程中的权衡相同。每个都有用例,在这些用例中它们优于其他两个。 R-Tree 索引与 Geohash 聚类也是如此。