有超过3亿条记录的MySQL表有哪些优化技术?

时间:2009-01-14 18:17:58

标签: mysql database database-design optimization jmx

我正在考虑将来自JVM的一些JMX数据存储在许多服务器上大约90天。此数据将是堆大小和线程数等统计信息。这意味着其中一个表将拥有大约3.88亿条记录。

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

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

谢谢,

约什

6 个答案:

答案 0 :(得分:9)

你可以做几件事:

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

  2. 对表格进行分区。分区是一种通过特定(聚合)密钥将大表拆分为几个较小表的技术。 MySQL在ver. 5.1内部支持此功能。

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

答案 1 :(得分:2)

3条建议:

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

如果您使用的是MYSQL 5.1,则可以使用新功能。 但要注意它们包含很多错误。

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

如果这也不起作用,您也可以尝试负载平衡。

答案 4 :(得分: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;

(系列包含16M行,n = 1 .. 16000000)

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倍(如果涉及复杂的连接,差异会大得多)。

答案 5 :(得分:0)

  1. 解析您的SELECT查询
  2. 限制1获取唯一行时 SELECT * FROM user WHERE state ='Alabama'//错误 SELECT 1 FROM user WHERE state ='Alabama'LIMIT 1

  3. 索引搜索字段 索引不仅适用于主键或唯一键。如果您要搜索的表中有任何列,则几乎总是将它们编入索引。

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

  5. 不按RAND()排序() 如果您确实需要从结果中随机排列,那么有更好的方法可以实现。虽然它需要额外的代码,但是你可以防止随着数据的增长而出现指数恶化的瓶颈。问题是,MySQL必须对表中的每一行执行RAND()操作(它需要处理能力),然后才对其进行排序,只给你一行。

  6. 在VARCHAR上使用ENUM ENUM型柱非常快速和紧凑。在内部,它们像TINYINT一样存储,但它们可以包含和显示字符串值。

  7. 如果可以,请使用NOT NULL 除非您有非常具体的理由使用NULL值,否则应始终将列设置为NOT NULL。

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

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