【问题标题】:In a very large MySQL analytics table - should I index the timestamp?在一个非常大的 MySQL 分析表中 - 我应该索引时间戳吗?
【发布时间】:2015-09-11 20:05:45
【问题描述】:

我希望提高对我拥有的非常大的 MySQL 分析表的查询速度。该表正在跟踪游戏服务器上的玩家数量,其结构如下所示:

`server_tracker` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `ip` int(10) unsigned NOT NULL,
  `port` smallint(5) unsigned NOT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `players` tinyint(3) unsigned NOT NULL,
  `map` varchar(28) NOT NULL,
  `portjoin` smallint(5) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_tracking_ip_port` (`ip`,`port`)
) ENGINE=InnoDB AUTO_INCREMENT=310729056 DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED |

此表的插入频率很高,每小时跟踪 10k+ 台服务器 10+ 次。然而,每隔一小时,数据就会被取出并取平均值,然后放入一个结构基本相同的“平均”表中。

目前我将 IP/端口设置作为关键。但是 - 有时在进行每小时平均时可能会有点慢 - 所以我很好奇是否值得在时间戳上放置一个索引,它经常用于从特定时间范围内选择数据,如下所示:

    SELECT  `players`
    FROM  `server_tracker`
    WHERE  `ip` = x
      AND  `port` = x
      AND  `date` > NOW()
      AND  `date` < NOW() + INTERVAL 60 MINUTE
    ORDER BY  `id` DESC

这是在此表上运行的唯一查询类型。该表仅用于在特定时间范围内从游戏服务器获取玩家人数。数据永远不会更新或更改。

但是,我对这一切有点陌生——我不确定在时间戳上放置索引是否能起到很多作用。只是在寻找一些友好的建议。

EXPLAIN SELECT players FROM server_tracker WHERE ip = x AND port = x AND date &gt; NOW() AND date &lt; NOW() + INTERVAL 60 MINUTE ORDER BY id DESC的结果

+----+-------------+-----------------+------+----------------------+----------------------+---------+-------------+-------+-------------+
| id | select_type | table           | type | possible_keys        | key                  | key_len | ref         | rows  | Extra       |
+----+-------------+-----------------+------+----------------------+----------------------+---------+-------------+-------+-------------+
|  1 | SIMPLE      | server_tracker  | ref  | idx_tracking_ip_port | idx_tracking_ip_port | 6       | const,const | 15354 | Using where |
+----+-------------+-----------------+------+----------------------+----------------------+---------+-------------+-------+-------------+

【问题讨论】:

  • 是的,您可能需要在 WHERE 子句中使用的任何内容的索引。
  • 重要的是要了解所有查询的访问路径,这些查询是尝试制作索引(单列、复合、覆盖)的瓶颈。否则,我们只能给出广泛的笔触答复。如果采取错误的方式,会让你的情况更糟
  • @ceejayoz 我的问题是这会显着增加磁盘空间使用量吗?它是否必须将这些数百万行超时增长的所有这些日期保存到一个文件中?我不确定索引在内部是如何工作的,因为大多数解释只解释了为什么以及如何使用它们。
  • @Drew “访问路径”是什么意思?例如,我将在此表上运行的查询类型?我正在运行的唯一查询类型是 OP 中的选择查询。通过查找 IP/端口/日期来选择玩家数量。这些数据永远不会更新或更改 - 但它确实会经常被删除。
  • 正确。你的情况很好,因为没有什么其他查询......索引更改会影响。

标签: mysql database indexing


【解决方案1】:

MySQL 和脚本中最重要的信息之一是了解 MySQL 很少有例外情况,在查询中始终只能使用 ONE INDEX。 因此,当 where 子句中的所有 4 个都使用 verfelder 时,它不会根据索引来设置一个列。

这些字段上只有一个组合索引柄。 字段的顺序很重要,这个索引也可以用于其他查询。

一个例子:

当您有 WHERE FIELD1 或 FIELD1 和 FIELD2 或 field1、field2 和 FIELD3 时,使用 field1、field2 和 field3 的索引。如果您在 WHERE FIELD2 或使用 FIELD3 或 FIELD2 并字段,则不使用此索引。 3 所以总是使用第一个字段。

如果不喜欢 QUERY 工作太容易发现,您可以直接运行查询和 EXPALIN 并 beommst 直接获取是否使用以及使用哪个索引的信息。如果有几行可以作为指标,将行下的各个值叠加在一起。这个数字越小,查询的执行效果就越好。

MariaDB [tmp]> EXPLAIN select * from content;
+------+-------------+---------+------+---------------+------+---------+------+------+-------+
| id   | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+---------+------+---------------+------+---------+------+------+-------+
|    1 | SIMPLE      | content | ALL  | NULL          | NULL | NULL    | NULL |   13 |       |
+------+-------------+---------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

MariaDB [tmp]>

Anternativ,您可以查看分析器多久 QUERY 的容量取决于优化服务器

一个例子:

MariaDB [(none)]> use tmp
Database changed
MariaDB [tmp]> SET PROFILING=ON;
Query OK, 0 rows affected (0.00 sec)

MariaDB [tmp]>
MariaDB [tmp]> SELECT * FROM content;
+----+------+---------------------+--------+------+--------------+------+------+------+------+
| id | Wert | Zeitstempel         | WertID | aaa  | d            | e    | wwww | n    | ddd  |
+----+------+---------------------+--------+------+--------------+------+------+------+------+
|  1 |   10 | 2001-01-01 00:00:00 |      1 | NULL |       1.5000 | NULL | NULL |    1 | NULL |
|  2 | 12.3 | 2001-01-01 00:01:00 |      2 | NULL |       2.5000 | NULL | NULL |    2 | NULL |
|  3 | 17.4 | 2001-01-01 00:02:00 |      3 | NULL |  123456.1250 | NULL | NULL |    3 | NULL |
|  4 | 10.9 | 2001-01-01 01:01:00 |      1 | NULL | 1000000.0000 | NULL | NULL |    4 | NULL |
|  5 | 15.4 | 2001-01-01 01:02:00 |      2 | NULL |         NULL | NULL | NULL |    5 | NULL |
|  6 | 20.9 | 2001-01-01 01:03:00 |      3 | NULL |         NULL | NULL | NULL |    6 | NULL |
|  7 |   22 | 2001-01-02 00:00:00 |      1 | NULL |         NULL | NULL | NULL |    7 | NULL |
|  8 | 12.3 | 2001-01-02 00:01:00 |      2 | NULL |         NULL | NULL | NULL |    8 | NULL |
|  9 | 17.4 | 2001-01-02 00:02:00 |      3 | NULL |         NULL | NULL | NULL |    
+----+------+---------------------+--------+------+--------------+------+------+------+------+
13 rows in set (0.00 sec)

MariaDB [tmp]>
MariaDB [tmp]> SHOW PROFILE;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000031 |
| checking permissions | 0.000005 |
| Opening tables       | 0.000036 |
| After opening tables | 0.000004 |
| System lock          | 0.000003 |
| Table lock           | 0.000002 |
| After opening tables | 0.000005 |
| init                 | 0.000013 |
| optimizing           | 0.000006 |
| statistics           | 0.000013 |
| preparing            | 0.000010 |
| executing            | 0.000002 |
| Sending data         | 0.000073 |
| end                  | 0.000003 |
| query end            | 0.000003 |
| closing tables       | 0.000006 |
| freeing items        | 0.000003 |
| updating status      | 0.000012 |
| cleaning up          | 0.000003 |
+----------------------+----------+
19 rows in set (0.00 sec)

MariaDB [tmp]>

【讨论】:

  • 我在 OP 中添加了一些新信息。您说每个查询只能使用 1 个索引?我将 IP/端口设置作为键 - 除了日期之外,这是 WHERE 子句使用的内容。没有真正在此表上运行其他类型的查询。如果您只能使用 1 个索引,那么索引日期是否有用?对不起,如果我误解了你的帖子,你的英语有点难读。
  • 对不起,我已经用谷歌翻译了:-)。使用您在查询中使用的所有字段创建一个索引“ALTER TABLE server_tracker ADD INDEX somename (ip, port, date);”那么查询可以完美地使用它。 ALTER TABLE 中字段的顺序也是重要的。女巫能降低结果的地方大多必须是第一位的。 a 样本:10k 行,5000 与端口 a 和 5000 与端口 b,以及 100 与 ip 1。然后是 ip 索引中的第一个字段。所以你可以在第一个 where ip=xx 之后将内部结果集 vom 总共减少到 100 行,而下一个 reduce 必须在 100 行中搜索
猜你喜欢
  • 2018-08-22
  • 1970-01-01
  • 2018-07-05
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多