我遇到了DB性能瓶颈,现在在哪里?

时间:2011-07-28 14:32:31

标签: mysql database database-design caching database-performance

我有一些查询花了太长时间(300毫秒),因为数据库已经增长到几百万条记录。幸运的是,对我来说,查询不需要查看大部分数据,最新的100,000条记录就足够了,所以我的计划是维护一个包含最新100,000条记录的单独表格并针对此运行查询。如果有人对更好的方法有任何建议,这将是伟大的。我真正的问题是,如果查询确实需要针对历史数据运行,有哪些选项,下一步是什么?我想到的事情:

  • 升级硬件
  • 使用内存数据库
  • 在您自己的数据结构中手动缓存对象

这些事情是否正确,还有其他选择吗?有些数据库提供商比其他数据库提供商有更多功能来处理这些问题,例如指定一个特定的表/索引完全在内存中?

抱歉,我应该提到这个,我正在使用mysql。

我忘记在上面提到索引了。到目前为止,索引是我唯一的改进来源。为了识别瓶颈,我一直在使用maatkit进行查询,以显示是否正在使用索引。

我知道我现在正在远离问题的目的,所以也许我应该再做一个问题。我的问题是EXPLAIN表示查询需要10毫秒而不是jmsofiler报告的300毫秒。如果有人有任何建议我会非常感激。查询是:

select bv.* 
from BerthVisit bv 
inner join BerthVisitChainLinks on bv.berthVisitID = BerthVisitChainLinks.berthVisitID 
inner join BerthVisitChain on BerthVisitChainLinks.berthVisitChainID = BerthVisitChain.berthVisitChainID 
inner join BerthJourneyChains on BerthVisitChain.berthVisitChainID = BerthJourneyChains.berthVisitChainID 
inner join BerthJourney on BerthJourneyChains.berthJourneyID = BerthJourney.berthJourneyID 
inner join TDObjectBerthJourneyMap on BerthJourney.berthJourneyID = TDObjectBerthJourneyMap.berthJourneyID 
inner join TDObject on TDObjectBerthJourneyMap.tdObjectID = TDObject.tdObjectID 
where 
BerthJourney.journeyType='A' and 
bv.berthID=251860 and 
TDObject.headcode='2L32' and 
bv.depTime is null and 
bv.arrTime > '2011-07-28 16:00:00'

EXPLAIN的输出为:

+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+-------------------------------------------------------+
| id | select_type | table                   | type        | possible_keys                               | key                     | key_len | ref                                            | rows | Extra                                                 |
+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+-------------------------------------------------------+
|  1 | SIMPLE      | bv                      | index_merge | PRIMARY,idx_berthID,idx_arrTime,idx_depTime | idx_berthID,idx_depTime | 9,9     | NULL                                           |  117 | Using intersect(idx_berthID,idx_depTime); Using where | 
|  1 | SIMPLE      | BerthVisitChainLinks    | ref         | idx_berthVisitChainID,idx_berthVisitID      | idx_berthVisitID        | 8       | Network.bv.berthVisitID                        |    1 | Using where                                           | 
|  1 | SIMPLE      | BerthVisitChain         | eq_ref      | PRIMARY                                     | PRIMARY                 | 8       | Network.BerthVisitChainLinks.berthVisitChainID |    1 | Using where; Using index                              | 
|  1 | SIMPLE      | BerthJourneyChains      | ref         | idx_berthJourneyID,idx_berthVisitChainID    | idx_berthVisitChainID   | 8       | Network.BerthVisitChain.berthVisitChainID      |    1 | Using where                                           | 
|  1 | SIMPLE      | BerthJourney            | eq_ref      | PRIMARY,idx_journeyType                     | PRIMARY                 | 8       | Network.BerthJourneyChains.berthJourneyID      |    1 | Using where                                           | 
|  1 | SIMPLE      | TDObjectBerthJourneyMap | ref         | idx_tdObjectID,idx_berthJourneyID           | idx_berthJourneyID      | 8       | Network.BerthJourney.berthJourneyID            |    1 | Using where                                           | 
|  1 | SIMPLE      | TDObject                | eq_ref      | PRIMARY,idx_headcode                        | PRIMARY                 | 8       | Network.TDObjectBerthJourneyMap.tdObjectID     |    1 | Using where                                           | 
+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+---------------------------------------

7 rows in set (0.01 sec)

7 个答案:

答案 0 :(得分:3)

  1. 确保所有索引都已优化。在查询上使用explain以查看它是否有效地使用了索引。
  2. 如果你正在做一些重连接,那么就开始考虑在java中进行这种计算。
  3. 考虑使用其他数据库,如NoSQL。您可以进行一些预处理并将数据放入Memcache中以帮助您。

答案 1 :(得分:1)

好吧,如果你已经优化了数据库和查询,我会说,而不是砍掉数据,下一步是看看:

a)mysql配置并确保它充分利用了硬件

b)看看硬件。你没有说你正在使用什么硬件。如果您可以购买两台或三台服务器来分配数据库中的读取,则可能会发现复制是一种选择(必须对中央服务器进行写入,但可以从任意数量的从站读取读取)

答案 2 :(得分:1)

考虑到这样的设计更改并不是一个好兆头 - 我敢打赌你仍然有足够的性能来挤出使用EXPLAIN,调整db变量并改进索引和查询。但是你可能已经超越了“尝试的东西”非常有效的地步。这是一个学习如何解释分析和日志的机会,并将您学到的知识用于索引和查询的具体改进。

如果您的建议很好,您应该能够告诉我们原因。请注意,这是一种流行的悲观情绪 -

What is the most ridiculous pessimization you've seen?

答案 3 :(得分:1)

不要为最新结果创建单独的表,而是考虑表分区。 MySQL自5.1版以来内置了此功能


只是说清楚:我不是说这是你问题的解决方案。只有一件事你可以尝试

答案 4 :(得分:0)

我首先尝试在采用您列出的任何措施之前优化表/索引/查询。你是否已经深入研究了性能不佳的查询,以至于你绝对相信你已经达到了RDBMS能力的极限?

编辑:如果您确实已经正确优化但仍有问题,请考虑为您需要的确切数据创建物化视图。基于比你提供的更多因素,这可能是也可能不是一个好主意,但我会把它放在需要考虑的事项列表的顶部。

答案 5 :(得分:0)

在最后100,000条记录中搜索应该非常快,你肯定会遇到索引问题。使用EXPLAIN并修复它。

答案 6 :(得分:0)

我知道我现在正在远离问题的目的     所以也许我应该再做一个。我的问题是EXPLAIN说的     jprofiler报告的查询需要10毫秒而不是300毫秒。

然后你的问题(和解决方案)必须在java中,对吗?