mysql - 如何在大表的多个部分中查找重复的 SQL 查询

标签 mysql

我的 MySQL 数据库中有一个包含约 300 万条记录的大表。我试图使用以下查询查找此表中的重复行 -

SELECT package_id
FROM version
WHERE metadata IS NOT NULL AND metadata <> '{}'
GROUP BY package_id, metadata HAVING COUNT(package_id) > 1

此查询在数据库上运行大约需要 23 秒。然而,我们的数据库主机使用 pt-kill 终止任何耗时超过 3 秒的查询。所以我需要找到一种方法来分解这个查询,比如每个子部分都是一个单独的查询,并且每个子部分花费的时间不到 3 秒。仅添加 LIMIT 约束并不能满足查询的需要,那么如何中断查询以处理表的不同部分。

SHOW CREATE TABLE version的结果

  CREATE TABLE `version` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `package_id` bigint(20) unsigned NOT NULL,
  `version_number` int(11) unsigned NOT NULL,
  `current_state_id` tinyint(2) unsigned NOT NULL,
  `md5sum` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_cs NOT NULL DEFAULT '',
  `uri` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_cs NOT NULL DEFAULT '',
  `filename` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_cs NOT NULL DEFAULT '',
  `size` bigint(11) unsigned NOT NULL DEFAULT '0',
  `metadata` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_cs DEFAULT NULL,
  `storage_type_id` tinyint(2) unsigned NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_version_package_id_version_number` (`package_id`,`version_number`),
  KEY `idx_version_md5sum` (`md5sum`),
  KEY `idx_version_metadata` (`metadata`(255)),
  KEY `idx_version_current_state_id` (`current_state_id`),
  KEY `storage_type_id` (`storage_type_id`),
  CONSTRAINT `_fk_version_current_state_id` FOREIGN KEY (`current_state_id`) REFERENCES `state` (`id`),
  CONSTRAINT `_fk_version_package_id` FOREIGN KEY (`package_id`) REFERENCES `package` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3248761 DEFAULT CHARSET=utf8

可以看出,表上有很多索引,包括 Package_id + Version_number 字段组合的索引。问题是这个表只会变得更大,而且我认为即使优化将我拉回到 3 秒范围内也不会扩展。因此,我需要一种方法来对该表进行分区并在不同的部分上运行查询。

最佳答案

提高速度的步骤。

  1. 创建仅包含 id 列和 package_id 列的表 version_small,并在 package_id 上建立索引。
  2. 插入 version_small,从版本中选择 id 和 package_id;
  3. 在上面的优化表上运行原始查询 - 在较小的表上应该会快得多。

或者

  1. 创建仅包含 id 和 package_id 列以及一个在 package_id 上具有唯一索引的 int 计数器的表 version_small。
  2. 插入 version_small,从版本中选择 id 和 package_id,在重复键增量计数器上;
  3. counter>1 的行是包含多个条目的 package_id。

关于mysql - 如何在大表的多个部分中查找重复的 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40517054/

相关文章:

mysql - MySQL 中的随机行

mysql - 查询数据库表字段中的字符串

mysql - Ext js 4.2,网格上的本地日期时间过滤器

mysql - 问题 仅当表中尚不存在时才插入值

java - 针对 MySQL 在 Hibernate 实体中建模 UUID

MySQL JDBC 驱动程序连接字符串?

php - 如何从数据库中获取行列表

mysql - 如何统计子表中多条记录的重复次数

python - 安装 Django : Using XAMPP's MySQL, MySQL-python 1.2.3 和 1.2.4 错误?

php - 如何在 PHP 中打印元素数量未知的数组