繁体   English   中英

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

[英]What is a good way to denormalize a mysql database?

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

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

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

我更了解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;

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

请记住,我只是提倡这作为最后的手段。 我敢打赌,有一些索引可以帮到你。 当您取消规范化时,不要忘记考虑磁盘上的额外空间,并找出何时运行查询以填充新表。 这应该是在晚上,或者在活动不足时。 当然,该表中的数据永远不会是最新的。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM