7

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

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

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

谢谢,

乔什

4

6 回答 6

9

您可以做几件事:

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

  2. 分区你的表。分区是一种通过特定(聚合)键将大表拆分为几个较小表的技术。MySQL 从版本内部支持这一点。5.1 .

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

于 2009-01-14T18:34:13.940 回答
2

3条建议:

  1. 指数
  2. 指数
  3. 指数

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

于 2009-01-14T18:29:08.223 回答
2

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

于 2009-01-14T18:29:36.787 回答
1

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

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

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

于 2009-01-14T18:36:18.350 回答
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 倍(如果涉及复杂的连接,差异会大得多)。

于 2011-04-30T10:16:09.627 回答
0
  1. 解释您的 SELECT 查询
  2. LIMIT 1 获取唯一行时 SELECT * FROM user WHERE state = 'Alabama' // 错误 SELECT 1 FROM user WHERE state = 'Alabama' LIMIT 1

  3. 索引搜索字段索引不仅用于主键或唯一键。如果您要搜索的表中有任何列,您几乎应该始终为它们编制索引。

  4. 为连接建立索引并使用相同的列类型 如果您的应用程序包含许多 JOIN 查询,则需要确保您连接所依据的列在两个表上都有索引。这会影响 MySQL 内部如何优化连接操作。

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

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

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

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

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

于 2017-10-12T04:20:45.573 回答