2

我们公司正在开发一个内部项目来解析文本文件。这些文本文件由使用常规表达式提取的元数据组成。十台计算机 24/7 全天候解析文本文件,并为高端 Intel Xeon SQL Server 2005 数据库提供提取的元数据。

简化的数据库模式如下所示:

项目

| 身份证 | 姓名 |
|----|--------|
| 1 | 样品 |
Items_Attributes

| 项目 ID | 属性 ID |
|--------|-------------|
| 1 | 1 |
| 1 | 2 |
属性

| 身份证 | 属性类型 ID | 价值 |
|----|-----------------|--------|
| 1 | 1 | 500MB |
| 2 | 2 | 1.0.0 |
属性类型

| 身份证 | 姓名 |
|----|---------|
| 1 | 尺寸 |
| 2 | 版本 |

有许多不同的文本文件类型,里面有不同的元数据。对于每个文本文件,我们都有一个Item,对于每个提取的元数据值,我们都有一个Attribute.

Items_Attributes allow us to avoid duplicate Attribute values which avoids database size to increase x^10.

This particular schema allows us to dynamically add new regular expressions and to obtain new metadata from new processed files no matter which internal structure they have.

Additionally this allow us to filter the data and to obtain dynamic reports based on the user criteria. We are filtering by Attribute and then pivoting the resultset (http://msdn.microsoft.com/en-us/library/ms177410.aspx). So this example pseudo-sql query

SELECT FROM Items WHERE Size = @A AND Version = @B

would return a pivoted table like this

| ItemName | Size  | Version |
|----------|-------|---------|
| Sample   | 500mB | 1.0.0   |

The application has been running for months and performance decreased terribly at the point is no longer usable. Reports should take no more than 2 seconds and Items_Attributestable 每周平均增加 10,000,000 行。一切都已正确索引,我们花费了大量时间分析和优化查询执行计划。

所以我的问题是,您将如何扩展它以减少报告执行时间?

我们提出了这个可能的解决方案:

  • 购买更多硬件并设置 SQL Server 集群。(我们需要关于正确的“集群”策略的建议)
  • 使用像 HBase 这样的键/值数据库(我们真的不知道是否能解决我们的问题)
  • 使用 ODBMS 而不是 RDBMS(我们一直在考虑 db4o)
  • 将我们的软件迁移到云端(我们的经验为零)
  • 在运行时静态生成报告。(我们真的不想)
  • 常见报表的静态索引视图(性能几乎相同)
  • 非规范化架构(我们的一些报告在单个查询中涉及多达 50 个表)
4

7 回答 7

2

大量使用此类模式。他们从来没有表现好。最好的办法是根据需要存储数据,格式为:

| 物品名称 | 尺寸 | 版本 | |---------|--------|---------| | 样品 | 500MB | 1.0.0 |

然后你不需要转动。顺便说一句,请不要将您的原始 EAV 模式称为“规范化”——它没有被规范化。

于 2009-06-16T16:26:44.693 回答
2

我将从发布准确的表元数据(以及索引详细信息)、准确的查询文本和执行计划开始。

使用您当前的表格布局,查询类似于以下内容:

SELECT FROM Items WHERE Size = @A AND Version = @B

不能从使用复合索引中受益(Size, Version),因为不可能建立这样的索引。

你甚至不能建立一个索引视图,因为它会包含一个自连接attributes

可能最好的决定是像这样对表进行非规范化:

id 名称 大小 版本

并创建一个索引(size, version)

于 2009-06-16T15:14:08.550 回答
2

SQL Server CAT 团队关于实体-属性-值数据库模型陷阱的这份白皮书或许可以提供帮助:http ://sqlcat.com/whitepapers/archive/2008/09/03/best-practices-for-semantic-data -modeling-for-performance-and-scalability.aspx

于 2009-06-16T15:15:00.203 回答
1

在我看来,就像在为 OLTP 事务优化的数据库上发出一些 OLAP 查询一样。不知道细节,我建议为您正在执行的查询类型构建一个单独的“数据仓库”。这将涉及聚合数据(如果可能)、非规范化以及拥有 1 天左右的数据库。您将每天或按您希望的任何时间间隔增量更新数据。

于 2009-06-16T15:24:14.163 回答
1

请发布准确的 DDL 和索引,如果您在 ID 列上有索引,那么您的查询将导致扫描

而不是这样的

SELECT FROM Items WHERE Size = @A AND Version = @B

你需要这样做

SELECT FROM Items WHERE ID = 1

换句话说,您需要获取文本值,找到要索引的 id,然后将其用作查询来返回结果

查看分区功能以分配数据可能也是一个好主意

集群是为了可用性而不是性能而完成的,如果一个节点(主动集群)死亡,另一个节点(被动集群)将变得活跃......当然也有主动主动集群,但那是另一回事

于 2009-06-16T15:28:07.820 回答
0

您在单个查询中提到了 50 个表。虽然 SQL Server 在单个整体查询中支持多达 256 个表,但采用这种方法会降低优化器生成有效计划的机会。

如果您对目前的模式很感兴趣,请考虑将您的报告查询分解为一系列步骤,将其结果具体化为临时 (#) 表。这种方法使您能够单独执行查询中最具选择性的部分,并且根据我的经验,可以提供很大的性能提升。查询通常也更易于维护。

另外(这个有点长镜头)你没有说你使用的是哪个 SQL Server 版本。但如果您使用的是 SQL 2005,鉴于报告中涉及的表数量和数据量,值得检查您的 SQL 服务器是否已至少修补到 SP2。

我在一个 ETL 项目中使用具有数亿行数的表,我们发现 SQL 2005 RTM/SP1 中的查询优化器无法始终如一地为连接超过 5 个表的查询生成有效计划,其中一个或多个表是这个规模的。此问题已在 SP2 中得到解决。

于 2009-06-17T07:39:29.087 回答
0

短期修复可能是使用水平分区。我假设你最大的桌子是Items_Attributes. 您可以对该表进行水平分区,将每个分区放在单独磁盘控制器上的单独文件组中。

这是假设您没有尝试同时报告所有ItemIds。

于 2009-06-16T15:20:22.533 回答