我正在考虑将来自 JVM 的一些 JMX 数据存储在许多服务器上大约 90 天。该数据将是诸如堆大小和线程数之类的统计信息。这意味着其中一张表将有大约 3.88 亿条记录。
根据这些数据,我正在构建一些图表,以便您可以比较从 Mbean 检索到的统计信息。这意味着我将使用时间戳每隔一段时间抓取一些数据。
所以真正的问题是,是否有办法优化表或查询,以便您可以在合理的时间内执行这些查询?
谢谢,
乔什
我正在考虑将来自 JVM 的一些 JMX 数据存储在许多服务器上大约 90 天。该数据将是诸如堆大小和线程数之类的统计信息。这意味着其中一张表将有大约 3.88 亿条记录。
根据这些数据,我正在构建一些图表,以便您可以比较从 Mbean 检索到的统计信息。这意味着我将使用时间戳每隔一段时间抓取一些数据。
所以真正的问题是,是否有办法优化表或查询,以便您可以在合理的时间内执行这些查询?
谢谢,
乔什
您可以做几件事:
构建索引以匹配您正在运行的查询。运行EXPLAIN以查看正在运行的查询类型,并确保它们都尽可能使用索引。
分区你的表。分区是一种通过特定(聚合)键将大表拆分为几个较小表的技术。MySQL 从版本内部支持这一点。5.1 .
如有必要,构建汇总表来缓存查询中成本较高的部分。然后针对汇总表运行查询。同样,临时内存表可用于存储表的简化视图作为预处理阶段。
3条建议:
ps 对于时间戳,您可能会遇到性能问题——取决于 MySQL 如何在内部处理 DATETIME 和 TIMESTAMP,将时间戳存储为整数可能会更好。(自 1970 年以来的 # 秒或其他时间)
好吧,首先,我建议您使用“离线”处理来生成“图形就绪”数据(对于大多数常见情况),而不是尝试按需查询原始数据。
如果您使用的是 MYSQL 5.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 倍(如果涉及复杂的连接,差异会大得多)。
LIMIT 1 获取唯一行时 SELECT * FROM user WHERE state = 'Alabama' // 错误 SELECT 1 FROM user WHERE state = 'Alabama' LIMIT 1
索引搜索字段索引不仅用于主键或唯一键。如果您要搜索的表中有任何列,您几乎应该始终为它们编制索引。
为连接建立索引并使用相同的列类型 如果您的应用程序包含许多 JOIN 查询,则需要确保您连接所依据的列在两个表上都有索引。这会影响 MySQL 内部如何优化连接操作。
不要按 RAND() 排序 如果您真的需要从结果中随机排列,有更好的方法来做。当然,它需要额外的代码,但您可以防止瓶颈随着数据的增长而呈指数级恶化。问题是,MySQL 必须对表中的每一行执行 RAND() 操作(需要处理能力),然后再对其进行排序并只给你 1 行。
在 VARCHAR 上使用 ENUM ENUM 类型的列非常快速且紧凑。在内部,它们像 TINYINT 一样存储,但它们可以包含和显示字符串值。
如果可以,请使用 NOT NULL 除非您有非常具体的原因使用 NULL 值,否则您应该始终将列设置为 NOT NULL。
“NULL 列在行中需要额外的空间来记录它们的值是否为 NULL。对于 MyISAM 表,每个 NULL 列需要额外一位,四舍五入到最接近的字节。”
将 IP 地址存储为 UNSIGNED INT 在您的查询中,您可以使用 INET_ATON() 将 IP 转换为整数,反之亦然。PHP 中也有类似的函数,称为 ip2long() 和 long2ip()。