【问题标题】:Which database for dealing with very large result-sets?哪个数据库用于处理非常大的结果集?
【发布时间】:2015-07-08 07:30:34
【问题描述】:

我目前正在开发一个 PHP 应用程序(预发布)。

背景

我们的 MySQL 数据库中有一张表,预计该表会变得非常大 - 单个用户拥有该表中的 250,000 行并不罕见。表格中的每一行都有一个金额和一个日期等。

此外,在大多数页面上,此特定表的读取(和写入)非常频繁。鉴于每一行都有一个日期,我使用GROUP BY date 来最小化 MySQL 给出的结果集的大小 - 现在可以将同一年包含的行视为一个总数。

但是,一个典型的页面仍然会有 1000-3000 个结果之间的结果集。还有一些地方执行了许多SUM(),总共有数十(如果不是数百)数千行。

试用 MySQL

在通常的页面上,MySQL 通常需要大约 600-900 毫秒。使用LIMIT 和偏移量对性能没有帮助,而且数据已经被高度规范化,因此进一步规范化似乎没有帮助。

更糟糕的是,应用程序的某些部分需要从数据库中检索 10,000-15,000 行。然后将结果用于 PHP 的计算并进行相应的格式化。鉴于此,MySQL 的性能无法接受。

尝试 MongoDB

我已将表格转换为 MongoDB,它的速度更快 - 检索 2,000 个文档通常需要大约 250 毫秒。但是,聚合管道中的 $group 命令(需要根据字段所在的年份聚合字段)会减慢速度。不幸的是,在删除/更新/插入文档时保持总计和​​更新也是不可能的,因为虽然我们可以对应用程序的某些部分使用年度总计,但在其他部分,计算要求每个金额都落在具体日期。

我也考虑过 Redis,尽管我认为数据的复杂性超出了 Redis 的设计目标。

最后一根稻草

除此之外,速度也很重要。所以性能在优先级方面是最高的。

问题:

  1. 在知道大多数查询会检索到非常大的结果集的情况下,存储频繁读取/写入和快速增长的数据的最佳方式是什么?
  2. 是否有其他解决方案?我完全愿意接受建议。

我现在有点卡住了,我无法在可接受的时间内检索到如此大的结果集。似乎大多数数据存储都非常适合小型检索 - 即使是大量数据 - 但我无法从更大的表/集合中检索大量数据。

【问题讨论】:

  • 您是否考虑过尝试一下 Elastica (elastic.co)?当谈到聚合/统计时,它真的很棒。通常,结合 MongoDB 编写 Elastica 索引并在后台保持最新是一个好主意。
  • 当您查看核心时,没有数据库,也没有一个软件项目可以做与 MySQL 不同的事情。实际上,每次 MySQL 变慢都是因为没有配置。如果您想要性能,您需要硬件资源 - 足够的 RAM、良好的 CPU 和快速的 SSD。如果您没有这些,那么在软件方面您几乎无法做任何事情来使某些东西在过时的计算机上快速运行。长话短说 - 你的 MySQL 配置是什么?您希望所有内容都适合内存,以便快速进行所有聚合。
  • @iamtankist 我没有考虑过 Elastica。人们似乎在处理this issue 的一些问题。我想知道现在情况是否仍然如此?你自己用过吗?注:我的 MySQL 服务器位于本地机器上的一个 vagrant box 上,它可以很好地处理其他情况。我并不觉得硬件一定是这里的瓶颈,但是,我可能错了。
  • 硬件永远是瓶颈。这就是 MySQL 附带默认配置的原因,因此它可以在非常非常旧且速度较慢的设备上运行。你的 MySQL 配置是什么?磁盘上的数据大小是多少?磁盘是机械的还是 SSD 的?你用的是什么存储引擎?您是否为 MySQL 所做的聚合操作分配了足够的 RAM?看到所有这些问题了吗?当 DB 很慢时,几乎总是因为它利用磁盘来查找数据或转储临时数据 - 而您的磁盘很慢。
  • @N.B.我明白你在说什么。作为预生产,数据库很小 - 我尝试保持所有表上的总行数

标签: php mysql performance mongodb scalability


【解决方案1】:

我只阅读了前两行,但您正在使用聚合 (GROUP BY),然后期望它只是实时执行?

我会说你是数据库内部的新手,不是为了破坏你,而是为了帮助你。

MySQL 和 MongoDB 中的组运算符都在内存中。换句话说,它采用您提供的任何数据结构,无论是索引还是文档(行),它将遍历每一行/文档,获取字段并将其分组。

这意味着您可以通过确保使用索引进行分组来加快 MySQL 和 MongoDB 中的速度,但这仍然只是到目前为止,即使将索引存放在 MongoDB 中的直接工作集中(内存)。

事实上,将LIMITOFFSET 一起使用,坦率地说,可能只会进一步减慢速度。因为在写出集合之后 MySQL 需要再次查询才能得到答案。

一旦完成,它将写出结果,MySQL 会将其写出到结果集(这里使用内存和 IO),如果您没有设置 $out,则 MongoDB 将内联回复,内联输出的最大大小为 16MB(文档的最大大小)。

这里要带走的最后一点是:聚合是可怕的

这里没有什么灵丹妙药可以救你,一些数据库会试图吹嘘它们的速度等等,但事实上大多数大型聚合器都使用一种叫做“预聚合报告”的东西。您可以在 MongoDB 文档中找到快速介绍:http://docs.mongodb.org/ecosystem/use-cases/pre-aggregated-reports/

这意味着您将聚合和分组的工作投入到其他一些可以轻松完成的过程中,从而允许您的阅读线程,即需要实时执行它的线程。

【讨论】:

  • 有趣。预先聚合的报告是避免聚合管道中的组的一个很好的解决方案,但是,这实际上只是我问题的一半。鉴于我正在处理具有每日“粒度”的 60 年周期,这仍然是 60 年内超过 20,000 天 - 并且鉴于此粒度不能超过此,我回到我原来的问题,因为它看来我仍然需要获取 20,000 行。如果我误解了您的答案,请纠正我。感谢帮助! :)
  • @Luke 如果你真的无法解决它,你将不得不像谷歌分析和其他分析程序那样咬紧牙关。它们以非常小的群体实时存在,通常是一分钟一分钟,但是一旦您请求报告,您就必须等待内容加载。您正在实时制作哪些页面?
  • 大多数页面都可以聚合 - 无论是通过您建议的预聚合报告还是其他方式。需要日常控制的页面是一种报告,查看频率会降低 - 但绝不会不频繁。我担心让人们等待的可扩展性。如果每个报告的加载时间超过 2 到 5 秒,我不确定这会给我留下多少并发用户。
  • @Luke 我个人会尝试一下,确保实际显示加载屏幕而不是浏览器加载图标。我个人的观点是,问题不在于并发,而只是您尝试做的事情的速度。一件事是还要将响应缓存一个小时左右,所以一旦它被处理一次,然后将它保存多久,数据可能仍然是新鲜的
  • 预聚合报告或急切聚合是要走的路!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 2011-08-25
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多