2008-08-15 64 views
19

我有一个正常化的订单数据的大型数据库,查询报告变得非常缓慢。我在报告中使用的许多查询加入了5或6个表格,并且必须检查数十或数十万行。什么是非规范化mysql数据库的好方法?

有很多查询,大多数都已尽可能优化以减少服务器负载并提高速度。我认为是时候开始以非规范化格式保存数据的副本了。

任何想法的方法?我应该从几个最糟糕的问题开始并从那里出发?

回答

10

我知道更多关于mssql的信息,但我不认为你正在谈论的连接数或行数会导致你在正确索引的地方出现太多问题。你有没有分析查询计划,看看你是否错过了?

http://dev.mysql.com/doc/refman/5.0/en/explain.html

话虽这么说,一旦你satisifed与指标,并已用尽所有其他途径,去正常化可能是正确的答案。如果您只有一个或两个查询是问题,那么手动方法可能是适当的,而某种数据仓库工具可能更适合创建开发数据立方体的平台。

这里有一个网站,我发现,关于这个问题倒是:

http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D

下面是一个简单的技术,你可以用它来保持反规范化查询简单,如果你只是做了几个在同一时间(而且我不会替换您的OLTP表格,只是为报告目的创建一个新表格)。比方说,你有这个疑问在你的应用程序:

select a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id where a.id=1 

您可以创建一个非规范化表和几乎相同的查询填充:

create table tbl_ab (a_id, a_name, b_address); 
-- (types elided) 

注意下划线匹配您使用

表的别名
insert tbl_ab select a.id, a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id 
-- no where clause because you want everything 

然后要修复您的应用程序以使用新的非规格化表格,请切换下划线的点。

select a_name as name, b_address as address 
from tbl_ab where a_id = 1; 

对于巨大的查询,这样可以节省大量的时间并明确了数据的来源,你可以重新使用已有的查询。

请记住,我只是提倡这是最后的手段。我敢打赌,有几个索引可以帮助你。并且,当您解除规范化时,请不要忘记考虑磁盘上的额外空间,并确定何时运行查询来填充新表。这可能应该是在晚上,或者活动不足的时候。而且该表中的数据当然不会完全保持最新。

[又一个编辑]不要忘了你创建的新表也需要编入索引!好处是你可以索引你的内容,而不用担心更新锁争用,因为除了你的批量插入之外,表只会看到选择。

1

我知道这是有点切线,但你有没有试过看看是否有更多的索引可以添加?

我没有太多的数据库背景,但我最近在使用数据库,我发现很多查询都可以通过添加索引来改进。

我们正在使用DB2,并且有一个叫DB2EXPLN和db2advis命令时,首先会显示是否正在使用表扫描VS索引扫描,而第二个会建议你可以添加到提高性能指标。我敢肯定,MySQL有类似的工具...

反正,如果这是你还没有考虑的事情,它一直在帮助我很多...但如果你已经走了这条路线,那么我想这不是你要找的。

另一种可能性是“物化视图”(或者他们在DB2中称之为),它允许您指定一个基本上由多个表中的部分构建的表。因此,您可以提供此视图来访问数据,而不是对实际列进行标准化,但我不知道这是否对插入/更新/删除有严重的性能影响(但如果它是“物化”的,那么它应该有助于选择,因为这些值是分开存储的)。

1

MySQL 5确实支持views,这在这种情况下可能会有帮助。这听起来像你已经做了很多优化,但是如果不是的话,你可以使用MySQL的EXPLAIN语法来查看实际正在使用的索引以及减慢查询的速度。至于对数据进行规范化(无论您是使用视图还是仅以更高效的方式复制数据),我认为从最慢的查询开始并按照您的方式进行操作是一种很好的方法。

0

您可能还想考虑选择临时表,然后在该临时表上执行查询。这样可以避免需要重新加入您发布的每个查询的表格(当然,假设您可以使用临时表格进行大量查询)。这基本上给了你非规范化的数据,但是如果你只是在做选择调用,那么不用担心数据的一致性。

2

根据其他一些评论,我肯定会看看你的索引。

我今年早些时候在MySQL数据库中发现的一件事是组合索引的力量。例如,如果您要报告日期范围内的订单号,则订单号和订单日期列上的复合索引可能会有所帮助。我相信MySQL只能使用一个索引进行查询,所以如果你在订单号和订单日期上只有单独的索引,那么它只能决定使用它们中的一个。使用EXPLAIN命令可以帮助确定这一点。

为了给出具有良好索引(包括众多复合索引)的性能指标,我可以在我们的数据库中运行查询连接3个表并在大多数情况下获得几乎即时的结果。对于更复杂的报告,大多数查询在10秒内运行。这3张表格分别有3300万,110万和140万行。请注意,我们已经对这些数据进行了标准化处理,以加快对数据库最常见的查询速度。

有关表格和报告查询类型的更多信息可能会提供更多建议。

0

除了我之前的回答,我们在某些情况下采取的另一种方法是将关键报告数据存储在单独的汇总表中。有些报告查询即使在非规格化和优化之后也会变得很慢,我们发现在整个月内创建表并存储运行总计或摘要信息时,月末报告的速度也会更快。

我们发现这种方法很容易实现,因为它不会破坏已经工作的任何东西 - 它只是在某些点插入额外的数据库。

0

我一直在玩复合索引,并看到了一些真正的好处......也许我会设置一些测试,看看是否可以救我在这里..至少再长一点。