10

前段时间,我想为我们的数百万用户网站建立一个新的统计系统,为我们的客户记录和报告用户操作。

数据库设计非常简单,包含一个表,带有一个 foreignId(200,000 个不同的 id)、一个 datetime 字段、一个 actionId(30 个不同的 id)和另外两个包含一些元信息(只是 smallints)的字段。对其他表没有限制。此外,我们有两个索引,每个索引包含 4 个字段,这些字段不能被删除,因为当我们拥有较小的索引时用户会超时。foreignId 是最重要的字段,因为每个查询都包含此字段。

我们选择使用 SQL 服务器,但实施后关系数据库似乎不是一个完美的选择,因为我们不能每天插入 3000 万条记录(它只是插入,我们不做任何更新),同时还要做很多随机读取数据库;因为索引的更新速度不够快。Ergo:我们有一个大问题 :-) 我们暂时解决了这个问题,但是

关系数据库似乎不适合这个问题!

像 BigTable 这样的数据库会是更好的选择吗?为什么?或者在处理这类问题时还有其他更好的选择吗?

注意。此时我们使用单 8 核 Xeon 系统,4 GB 内存和 Win 2003 32 位。据我所知,RAID10 SCSI。索引大小约为表大小的 1.5 倍。

4

8 回答 8

12

您说您的系统在没有索引的情况下每秒能够插入 3000 条记录,但在使用两个额外的非聚集索引时只能插入大约 100 条记录。如果 3k/s 是您的 I/O 允许的最大吞吐量,那么理论上添加两个索引应该会将吞吐量降低大约 1000-1500/秒。相反,您会看到恶化 10 倍的退化。正确的解决方案和答案是“It Dependts”,并且必须进行一些严重的故障排除和瓶颈识别。考虑到这一点,如果我冒险猜测,我会给出两个可能的罪魁祸首:

A. 额外的非聚集索引将脏页的写入分配到更多的分配区域。解决方案是将聚簇索引和每个非聚簇索引放置到其自己的文件组中,并将三个文件组分别放置到 RAID 上的单独 LUN 上。

B. 非聚集索引的低选择性导致读取和写入之间的高竞争(键冲突以及%lockres% 冲突)导致插入和选择的锁定等待时间较长。可能的解决方案是使用带有读取提交快照模式的 SNAPSHOT ,但我必须警告在可能已经处于高 IO 压力下的系统上的版本存储(即在 tempdb 中)中添加大量IO的危险。第二种解决方案是使用数据库快照进行报告,它们会降低 IO 压力并且可以更好地控制(不涉及 tempdb 版本存储),但报告不再是实时数据。

我倾向于相信 B) 是可能的原因,但我必须再次强调需要进行适当的调查和适当的根本案例分析。

'RAID10' 不是一个非常精确的描述。

  • RAID 0 部分中有多少个心轴?他们是短条纹的吗?
  • 多少个 LUN?
  • 数据库日志在哪里?
  • 数据库位于何处?
  • 多少个分区?
  • tempdb 位于何处?

至于关系数据库是否适合这样的问题,是的,绝对的。还有更多因素需要考虑,可恢复性、可用性、工具集生态系统、专业知识、易于开发、易于部署、易于管理等等。关系数据库可以轻松处理您的工作负载,它们只需要适当的调整。每天 3000 万次插入,每秒 350 次,对于数据库服务器来说是很小的变化。但是 32 位 4GB RAM 系统几乎不是数据库服务器,不管 CPU 的数量。

于 2009-10-04T21:53:11.560 回答
7

听起来您可能正遭受两个特定问题的困扰。您遇到的第一个问题是每次执行插入时都需要重建索引 - 您是否真的在尝试运行事务服务器的实时报告(这通常被认为是禁止的)?其次,您可能还会遇到服务器不得不调整数据库大小的问题 - 检查以确保您已分配足够的空间并且不依赖数据库为您执行此操作。

您是否考虑过在 SQL Server 中研究诸如索引视图之类的东西?它们是从主表中删除索引并将其移动到物化视图中的好方法。

于 2009-10-04T19:05:53.597 回答
3

您可以尝试将表设为分区表。这样,索引更新将影响较小的行集。可能每天分区就足够了。如果没有,请尝试按小时分区!

于 2009-10-04T19:45:50.013 回答
2

您没有提供足够的信息;除了您现在遇到性能问题之外,我不确定您为什么说关系数据库看起来不合适。RDBMS 运行在什么样的机器上?鉴于您有外国 ID,似乎关系数据库正是这里所需要的。假设 SQL Server 在足够的硬件上运行,它应该能够每天处理 3000 万次插入。

于 2009-10-04T19:01:20.877 回答
2

鉴于流量很大,复制数据库以进行报告似乎是最佳途径。但是,首先要尝试几件事...

使用单个索引,而不是两个索引。聚集索引可能会比非聚集索引更好。更少、更宽的索引通常会比更多、更窄的索引执行得更好。而且,正如您所说,正在扼杀您的应用程序的是索引。

您没有说明您使用的是什么 ID,但如果您使用的是 GUID,您可能希望将您的密钥更改为 bigint。因为 GUID 是随机的,所以它们给索引带来了沉重的负担,无论是在构建索引还是在使用它们时。使用 bigint 标识列将使索引几乎按时间顺序运行,如果您真的对实时访问最近数据的查询感兴趣,那么您的访问模式更适合单调递增的键。

于 2009-10-04T19:51:42.623 回答
0

正如我们的架构师/DBA 所指出的那样,Sybase IQ 似乎非常适合该目标(例如,他们明确地将我们所有的统计数据转移到 IQ 上,并说明该功能是原因)。不过,我无法证实自己——只是对我们公司的人点头,他们通常从过去的经验中知道他们在说什么。

但是,我想知道您是否必须存储所有 30 毫米的记录?存储一些预先聚合的数据不是更好吗?

于 2009-10-04T19:08:00.027 回答
0

不确定 SQL 服务器,但在我很久以前使用的另一个数据库系统中,这种类型活动的理想方法是存储更新,然后批量关闭索引,添加新记录,然后重新索引。我们每晚这样做一次。我不确定您的报告需求是否适合这种类型的解决方案,或者即使它可以在 MS SQL 中完成,但我认为可以。

于 2009-10-04T19:54:17.743 回答
0

您没有说如何管理插入。它们是分批的还是每个统计数据都是单独编写的?因为在单个操作中插入一千行可能比在一千个单独的操作中插入单行更有效。您仍然可以足够频繁地插入以提供或多或少的实时报告;)

于 2009-10-05T12:43:11.887 回答