我有一张包含超过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 - 重新分区后仍然相同,因此尝试识别缺失的行以建立模式。
答案 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分钟,并且我在此测试服务器上运行的查询时间比此长,但我有我的解决方案,所以我将会这样做关闭这个,即使潜在的原因仍然不清楚。