8

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

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

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

对不起,我应该提到这一点,我正在使用 mysql。

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

我知道我现在正在远离这个问题的目的,所以也许我应该再做一个。我的问题是EXPLAIN说查询需要 10 毫秒而不是 jprofiler 报告的 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)
4

7 回答 7

3
  1. 确保所有索引都已优化。在查询上使用explain以查看它是否有效地使用了您的索引。
  2. 如果您正在执行一些重连接,那么开始考虑在 java 中进行此计算。
  3. 考虑使用其他数据库,例如 NoSQL。您也许可以进行一些预处理并将数据放入 Memcache 以帮助您一点。
于 2011-07-28T14:37:12.687 回答
1

与其为最新结果创建单独的表,不如考虑表分区。MySQL 从 5.1 版本开始就内置了这个特性


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

于 2011-07-28T17:44:32.347 回答
1

考虑到这样的设计更改不是一个好兆头——我敢打赌,使用 EXPLAIN、调整数据库变量和改进索引和查询,您仍然有足够的性能来发挥作用。但是你可能已经过了“尝试的东西”效果很好的地步。这是一个学习如何解释分析和日志的机会,并利用所学知识对索引和查询进行具体改进。

如果您的建议很好,您应该已经能够告诉我们原因。请注意,这是一种流行的悲观主义——

你见过最可笑的悲观情绪是什么?

于 2011-07-28T17:25:27.623 回答
1

好吧,如果您已经优化了数据库和查询,我会说与其分割数据,不如下一步是查看:

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

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

于 2011-07-28T14:47:46.707 回答
0

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

那么您的问题(和解决方案)必须在 java 中,对吗?

于 2011-07-28T17:44:42.333 回答
0

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

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

于 2011-07-28T14:37:39.057 回答
0

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

于 2011-07-28T14:43:08.140 回答