什么是反规范化mysql数据库的好方法?

时间:2008-08-15 23:36:30

标签: mysql database denormalization

我有一个规范化订单数据的大型数据库,查询报告的速度变得非常慢。我在报告中使用的许多查询都会连接五到六个表,并且必须检查数十或数十万行。

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

有关方法的任何想法?我应该从几个最糟糕的问题开始,然后从那里开始吗?

8 个答案:

答案 0 :(得分:11)

我对mssql了解更多关于mysql的信息,但是我不认为你所谈论的连接数或行数应该会导致你在使用正确的索引时出现太多问题。您是否分析了查询计划以查看是否遗漏了任何问题?

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

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

这是我发现的一个涉及该主题的网站:

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 :(得分:2)

MySQL 5确实支持views,这在这种情况下可能会有所帮助。听起来你已经做了很多优化,但如果没有,你可以使用MySQL的EXPLAIN语法来查看实际使用的索引以及减慢查询的速度。

关于规范化数据(无论是使用视图还是仅以更有效的方式复制数据),我认为从最慢的查询开始并按照自己的方式进行操作是一种很好的方法。

答案 2 :(得分:1)

我知道这有点切,但您是否尝试过查看是否可以添加更多索引?

我没有很多数据库背景,但最近我正在使用数据库,而且我发现只需添加索引就可以改进很多查询。

我们正在使用DB2,并且有一个名为db2expln和db2advis的命令,第一个将指示是否正在使用表扫描与索引扫描,第二个将建议您可以添加的索引以提高性能。我确信MySQL有类似的工具......

无论如何,如果这是你还没有考虑过的事情,它对我有很多帮助......但是如果你已经走了这条路线,那么我想这不是你想要的。

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

答案 3 :(得分:1)

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

我今年早些时候在MySQL数据库中发现的一件事是复合索引的强大功能。例如,如果您在日期范围内报告订单号,则订单号和订单日期列上的复合索引可能会有所帮助。我相信MySQL只能为查询使用一个索引,所以如果您只是在订单号和订单日期上有单独的索引,则必须决定只使用其中一个。使用EXPLAIN命令可以帮助确定这一点。

为了用良好的索引(包括众多的复合索引)来表示性能,我可以运行在数据库中连接3个表的查询,并在大多数情况下获得几乎即时的结果。对于更复杂的报告,大多数查询在10秒内运行。这3个表分别有3300万行,1.1亿行和1.4亿行。请注意,我们已经将这些略微标准化,以加快我们对数据库的最常见查询。

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

答案 4 :(得分:1)

对于MySQL,我喜欢这个话题:Real World Web: Performance & Scalability, MySQL Edition。这包含许多不同的建议,可以提高MySQL的速度。

答案 5 :(得分:0)

您可能还需要考虑选择临时表,然后对该临时表执行查询。这样可以避免为您发出的每个查询重新加入表(假设您可以使用临时表进行大量查询)。这基本上为您提供了非规范化数据,但如果您只进行选择调用,则不必担心数据一致性。

答案 6 :(得分:0)

我一直在玩复合索引并且已经看到了一些真正的好处......也许我会设置一些测试,看看能不能在这里拯救我......至少再多一点。

答案 7 :(得分:0)

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

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