2009-01-14 100 views
7

我正在寻找在90天内在很多服务器上存储来自JVM的一些JMX数据。这些数据将是统计数据,如堆大小和线程数。这意味着其中一张表格将有大约3.88亿条记录。对于拥有3亿多记录的MySQL表,有哪些优化技术?

从这些数据我建立一些图表,所以你可以比较从Mbeans检索到的统计数据。这意味着我将使用时间戳以一定的间隔抓取一些数据。

所以真正的问题是,有无论如何优化表或查询,以便您可以在合理的时间内执行这些查询?

谢谢,

约什

回答

9

有几件事情可以做:

  1. 建立你的索引来匹配您正在运行的查询。运行EXPLAIN查看运行的查询的类型,并确保它们都尽可能使用索引。

  2. 分区您的表。分区是一种通过特定(聚合)键将大型表分成几个小型表的技术。 MySQL在内部支持这个从ver. 5.1

  3. 如有必要,可以构建汇总表来缓存查询中昂贵的部分。然后针对汇总表运行查询。同样,可以使用临时内存表来将表格的简化视图存储为预处理阶段。

2

3建议:

  1. 索引
  2. 索引
  3. 索引

P.S.对于时间戳,您可能遇到性能问题 - 取决于MySQL如何在内部处理DATETIME和TIMESTAMP,将时间戳存储为整数可能会更好。 (1970年以来的秒数或其他)

2

那么,首先,我建议您使用“离线”处理来生成“图形就绪”数据(对于大多数常见情况),而不是试图查询原始数据一经请求。

1

如果您使用的是MYSQL 5.1,则可以使用新功能。 但被警告他们包含大量的错误。

首先你应该使用索引。 如果这还不够,可以尝试使用分区来分割表。

如果这也行不通,您还可以尝试负载平衡。

1

一些建议。

您可能要对这些东西运行聚合查询,所以在将数据加载到表中之后,您应该预先聚合数据,例如按小时计算预计算总数,或按用户或按星期,无论如何,你都会明白,并将其存储在用于报告图形的缓存表中。如果你能缩小你的数据集一个数量级,那么,对你有好处!

这意味着我将使用时间戳以一定间隔抓取一些数据。

那么这意味着您只能使用最近X天的数据?

从表中删除旧数据可能会非常慢,如果你有几千万行要删除,分区对于那个很好(只需删除旧分区)。它还将相同时间段内的所有记录分组在一起,因此它的缓存效率更高。

现在,如果你使用MySQL,我强烈建议使用MyISAM表。你没有得到防碰撞或事务处理,并且锁定是愚蠢的,但是表的大小比InnoDB小得多,这意味着它可以放入RAM中,这意味着更快的访问。

由于大型聚合可能涉及大量相当连续的磁盘IO,因此像RAID10(或SSD)这样的快速IO系统是一个优点。

有无论如何优化表或查询,所以你可以在合理的时间内执行这些查询 ?

这取决于表和查询;不知道更多,不能给出任何建议。

如果您需要使用大型聚合和连接进行复杂的报表查询,请记住MySQL不支持任何花哨的JOIN,哈希聚合或其他任何有用的东西,基本上它唯一能做的就是嵌套循环索引扫描在缓存的表上是好的,并且如果涉及一些随机访问,则在其他情况下非常残暴。

我建议你用Postgres进行测试。对于大集合,更智能的优化器确实运行良好。

实施例:

CREATE TABLE t (id INTEGER PRIMARY KEY AUTO_INCREMENT, category INT NOT NULL, counter INT NOT NULL) ENGINE=MyISAM; 
INSERT INTO t (category, counter) SELECT n%10, n&255 FROM serie; 

(系列包含其中n = 1 .. 16000000 16M线)

MySQL Postgres  
58 s  100s  INSERT 
75s  51s  CREATE INDEX on (category,id) (useless) 
9.3s  5s   SELECT category, sum(counter) FROM t GROUP BY category; 
1.7s  0.5s  SELECT category, sum(counter) FROM t WHERE id>15000000 GROUP BY category; 

在一个简单的查询这样PG是大约2-3倍更快(差异将如果涉及复杂的连接,则要大得多)。

0
  1. 解释你的SELECT查询
  2. LIMIT 1当获得一个唯一的行 SELECT * FROM用户WHERE状态= '阿拉巴马' //错误 SELECT 1 FROM用户WHERE状态= '阿拉巴马' LIMIT 1

  3. 索引搜索字段 索引不仅仅是主键或唯一键。如果表格中有任何要搜索的列,则应该几乎总是对它们进行索引。

  4. 索引和用法连接的相同列类型 如果您的应用程序包含许多JOIN查询,则需要确保通过两个表索引您加入的列。这会影响MySQL在内部优化连接操作的方式。

  5. 不要按ORDER BY RAND() 如果你确实需要结果中的任意行,那么有更好的方法。当然,它需要额外的代码,但是您可以防止随着数据增长而出现指数级恶化的瓶颈。问题是,在对数据进行排序并给你1行之前,MySQL必须对表中的每一行执行RAND()操作(这需要处理能力)。

  6. 使用ENUM over VARCHAR ENUM类型的列非常快速而且紧凑。它们在内部存储为TINYINT,但它们可以包含并显示字符串值。

  7. 使用NOT NULL如果您可以 除非您有一个非常具体的使用NULL值的原因,否则应始终将您的列设置为NOT NULL。 “

    ”NULL列需要额外的空间来记录它们的值是否为NULL。对于MyISAM表,每个NULL列需要一位额外的,四舍五入到最近的字节。

  8. 将IP地址存储为UNSIGNED INT 在您的查询中,您可以使用INET_ATON()将IP转换为整数,将INET_NTOA()反过来。 PHP中也有类似的函数,称为ip2long()和long2ip()。