什么是使MySQL数据库非规范化的好方法?

什么是使MySQL数据库非规范化的好方法?

What is a good way to denormalize a mysql database?

我有一个大型的标准化订单数据数据库,查询报表的速度变得非常慢。 我在报表中使用的许多查询联接了五个或六个表,并且不得不检查成千上万的行。

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

关于方法有什么想法吗? 我应该从几个最糟糕的查询开始,然后再去那里吗?


我对有关mysql的mssql的了解更多,但我认为所讨论的联接数或行数不会导致使用正确索引的太多问题。您是否分析了查询计划以查看是否缺少任何计划?

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表,而只是创建一个用于报告目的的新表),则可以使用它使非规范化查询保持简单。假设您在应用程序中有以下查询:

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

您可以创建一个非规范化表并使用几乎相同的查询进行填充:

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

注意下划线与您使用的表别名匹配

1
2
3
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

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

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

对于庞大的查询,这可以节省大量时间,并清楚说明数据的来源,并且您可以重复使用已有的查询。

记住,我只是提倡将此作为最后的手段。我敢打赌,有一些索引可以为您提供帮助。而且,当您进行非规范化时,请不要忘记考虑磁盘上的额外空间,并弄清楚何时运行查询来填充新表。这可能应该在晚上或活动量少的时候。而且,该表中的数据当然永远不会是最新的。

[另一个编辑]不要忘记,您创建的新表也需要建立索引!好处是您可以索引自己的内容,而不必担心更新锁争用,因为除了批量插入之外,该表仅会显示选择内容。


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

至于规范数据(无论您是使用视图还是只是以更有效的方式复制数据),我认为从最慢的查询开始并逐步进行是一个很好的方法。


对于MySQL,我喜欢这个话题:"真实世界的网络:性能和可伸缩性,MySQL版"。 这包含许多不同的建议,以提高MySQL的速度。


与其他一些评论一致,我一定会看看您的索引编制。

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

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

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


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

我没有太多的数据库背景,但是最近我正在使用很多数据库,并且我发现仅通过添加索引就可以改善很多查询。

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

无论如何,如果这是您尚未考虑的事情,它对我有很大帮助...但是,如果您已经走了这条路线,那么我想这不是您想要的。

另一种可能性是"物化视图"(或在DB2中称为"物化视图"),它使您可以指定一个基本上由多个表的零件组成的表。因此,您可以提供该视图以访问数据,而不是对实际的列进行标准化...但是我不知道这是否会对插入/更新/删除操作产生严重的性能影响(但如果它是"物化的",那么它应该会帮助选择,因为这些值在物理上是分开存储的)。


我一直在研究复合索引,并且看到了一些真正的好处...也许我将设置一些测试,看看是否可以在这里保存我..至少更长一点时间。


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

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


您可能还需要考虑选择一个临时表,然后对该临时表执行查询。这样就避免了针对发出的每个查询重新连接表的需求(当然,假设您可以将临时表用于多个查询)。这基本上为您提供了非规范化的数据,但是,如果您仅执行选择调用,则无需担心数据的一致性。


推荐阅读