mysql - 使用大型数据集提高 Run-Once 查询的 MySQL 性能

标签 mysql sql database innodb

我之前问过一个关于如何分析大型数据集的问题 (how can I analyse 13GB of data)。一个有前途的回应是使用自然键将数据添加到 MySQL 数据库中,从而利用 INNODB 的聚簇索引。

我已将数据添加到数据库中,其架构如下所示:

TorrentsPerPeer
+----------+------------------+------+-----+---------+-------+
| Field    | Type             | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+-------+
| ip       | int(10) unsigned | NO   | PRI | NULL    |       |
| infohash | varchar(40)      | NO   | PRI | NULL    |       |
+----------+------------------+------+-----+---------+-------+

这两个字段共同构成了主键。

此表代表已知的点下载种子的实例。我希望能够提供有关在同行中可以找到多少种子的信息。我将绘制我看到的种子数量的频率直方图(例如,20 个同行有 2 个种子,40 个同行有 3 个,...)。

我编写了以下查询:

SELECT `count`, COUNT(`ip`) 
    FROM (SELECT `ip`, COUNT(`infohash`) AS `count`
              FROM TorrentsPerPeer
              GROUP BY `ip`) AS `counts`
    GROUP BY `count`;

这是子选择的EXPLAIN:

+----+-------------+----------------+-------+---------------+---------+------------+--------+----------+-------------+
| id | select_type | table          | type  | possible_keys | key     | key_length | ref    | rows     | Extra       |
+----+-------------+----------------+-------+---------------+---------+------------+--------+----------+-------------+
| 1  | SIMPLE      | TorrentPerPeer | index | [Null]        | PRIMARY | 126        | [Null] | 79262772 | Using index |
+----+-------------+----------------+-------+---------------+---------+------------+--------+----------+-------------+

我似乎无法为完整查询执行 EXPLAIN,因为它花费的时间太长了。这bug表明这是因为它首先运行子查询。

此查询当前正在运行(已经运行了一个小时)。 top 报告 mysqld 仅使用了大约 5% 的可用 CPU,而其 RSIZE 正在稳步增加。我在这里的假设是服务器正在 RAM 中构建用于完成查询的临时表。

那么我的问题是;我怎样才能提高这个查询的性能?我应该以某种方式更改查询吗?我一直在更改 my.cnf 文件中的服务器设置以增加 INNODB 缓冲池大小,我应该更改任何其他值吗?

如果重要的话,该表有 79'262'772 行深,占用大约 8GB 的​​磁盘空间。我不希望这是一个简单的问题,也许“耐心”是唯一合理的答案。

编辑 只是补充一下,查询已经完成,耗时 105 分钟。这并非难以忍受,我只是希望有所改进。

最佳答案

我的直觉是,使用 unsigned int 和 varchar 40(尤其是 varchar!),您现在拥有一个巨大的主键,它使您的索引文件太大而无法容纳您为 Innodb_buffer_pool 提供的任何 RAM。这将使 InnoDB 在搜索时不得不依赖磁盘来交换索引页,这是大量的磁盘寻道而不是大量的 CPU 工作。

我为类似问题所做的一件事是使用介于真正自然键和代理键之间的东西。我们将采用实际上唯一的 2 个字段(其中一个也是 varchar),并且在应用程序层中将生成固定宽度的 MD5 哈希并将其用作键。是的,这意味着应用程序需要做更多的工作,但它会生成更小的索引文件,因为您不再使用任意长度的字段。

或者,您可以只使用具有大量 RAM 的服务器,看看这是否使索引适合内存,但我总是喜欢将“向其扔硬件”作为最后的手段:)

关于mysql - 使用大型数据集提高 Run-Once 查询的 MySQL 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11469818/

相关文章:

mysql - SQL 在不同列上多次连接表

php - 我的注册表不会将信息发送到我的数据库。

mysql - 更新条件来自另一个表的表字段

SQL Server 删除表

amazon-web-services - DynamoDB Friends 设计

mysql - 按月分组在 laravel Controller 中产生错误

mysql - 链接服务器更新mysql不工作

sql - 如何删除空字符串

php - 发布仅返回较旧的结果

database - Apriori 算法的数据集