分区后“丢失”30%的记录

时间:2016-02-22 04:01:08

标签: mysql partitioning

我有一张包含超过18GB数据的9,000万条记录的MYISAM表,并且测试显示它是分区的候选者。

原始架构:

CREATE TABLE `email_tracker` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `hash` varchar(65) COLLATE utf8_unicode_ci NOT NULL,
  `userId` int(11) NOT NULL,
  `dateSent` datetime NOT NULL,
  `dateViewed` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `userId` (`userId`),
  KEY `dateSent` (`dateSent`),
  KEY `dateViewed` (`dateViewed`),
  KEY `hash` (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 1 row in set (0.01 sec)

我之前在测试服务器上使用“ALTER TABLE email_tracker PARTITION BY HASH ...”对表进行了分区,并针对它运行典型查询,并且查询没有问题。为了避免将表锁定在生产数据库上,我使用这种方法再次在测试服务器上进行测试,因为我们可以在运行时丢失一些跟踪数据:

RENAME TABLE email_tracker TO email_tracker_orig; CREATE TABLE email_tracker LIKE email_tracker_orig;
CREATE TABLE email_tracker_part LIKE email_tracker_orig;
ALTER TABLE email_tracker_part DROP PRIMARY KEY, ADD PRIMARY KEY (id, userId);
ALTER TABLE email_tracker_part PARTITION BY HASH (id + userId) partitions 30;
INSERT INTO email_tracker_part (SELECT * FROM email_tracker_orig);

_orig表有90,795,103条记录。查询后,_part表只有68,282,298。我不知道为什么会这样。有什么想法吗?

mysql> select count(*) from email_tracker_orig;
+----------+
| count(*) |
+----------+
| 90795103 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from email_tracker_part;
+----------+
| count(*) |
+----------+
| 68274818 |
+----------+
1 row in set (0.00 sec)

(在后续测试中,_part表包含略微不同数量的记录,这仍然更奇怪)

编辑#1:刚刚意识到由于自动递增 - 增量= 2进行复制,分区表的一半是空的,所以要重新分区BY KEY(userId),看看它是如何工作的。

编辑#2 - 重新分区后仍然相同,因此尝试识别缺失的行以建立模式。

2 个答案:

答案 0 :(得分:0)

我不确定您的要求,但mysql documentation声明“不特别推荐使用涉及多列的哈希表达式”。我建议你只按id进行分区。按id + userId进行分区并不能明显更好地在分区中分发元素。

答案 1 :(得分:0)

看起来INSERT查询只是过早终止 - 在这种情况下恰好40分钟。只是为缺少的记录重新运行它就是这样做的:

INSERT INTO email_tracker_part (SELECT * FROM email_tracker_orig WHERE id > 148893974);

my.cnf中没有任何内容表明超时为40分钟,并且我在此测试服务器上运行的查询时间比此长,但我有我的解决方案,所以我将会这样做关闭这个,即使潜在的原因仍然不清楚。