优化比较两个 MySQL 大表中的数据
Posted
技术标签:
【中文标题】优化比较两个 MySQL 大表中的数据【英文标题】:Optimise comparing data in two big MySQL tables 【发布时间】:2020-01-09 17:41:27 【问题描述】:如何优化查询,它将找到所有记录,其中:
activation_request.date_confirmed 不为空和
在另一个表中没有相关的字符串值:activation_request.email = user.username 不应返回任何记录我试过了:
SELECT email
FROM activation_request l
LEFT JOIN user r ON r.username = l.email
WHERE l.date_confirmed is not null
AND r.username IS NULL
和
SELECT email
FROM activation_request
WHERE date_confirmed is not null
AND NOT EXISTS (SELECT 1
FROM user
WHERE user.username = activation_request.email
)
但两个表都有 xxx.xxx.xxx 记录,因此不幸的是,在运行这些查询之后,我没有得到任何结果。
创建语句:
CREATE TABLE `activation_request` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`version` bigint(20) NOT NULL,
`date_confirmed` datetime DEFAULT NULL,
`email` varchar(255) NOT NULL,
(...)
PRIMARY KEY (`id`),
KEY `emailIdx` (`email`),
KEY `reminderSentIdx` (`date_reminder_sent`),
KEY `idx_resent_needed` (`date_reminder_sent`,`date_confirmed`),
) ENGINE=InnoDB AUTO_INCREMENT=103011867 DEFAULT CHARSET=utf8;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`version` bigint(20) NOT NULL,
`username` varchar(255) NOT NULL,
(...)
PRIMARY KEY (`id`),
UNIQUE KEY `Q52plW9W7TJWZcLj00K3FmuhwMSw4F7vmxJGyjxz5iiINVR9fXyacEoq4rHppb` (`username`),
) ENGINE=InnoDB AUTO_INCREMENT=431400048 DEFAULT CHARSET=latin1;
解释左连接:
[[id:1, select_type:SIMPLE, table:l, type:ALL, possible_keys:null, key:null, key_len:null, ref:null, rows:49148965, Extra:Using where], [id:1, select_type:SIMPLE, table:r, type:index, possible_keys:null, 键:Q52plW9W7TJWZcLj00K3FmuhwMSw4F7vmxJGyjxz5iiINVR9fXyacEoq4rHppb, key_len:257, ref:null, rows:266045508, Extra:Using where;不存在; 使用索引;使用连接缓冲区(块嵌套循环)]] [[id:1, select_type:SIMPLE, table:l, type:ALL, possible_keys:null, key:null, key_len:null, ref:null, rows:49148965, Extra:Using where], [id:1, select_type:SIMPLE, table:r, type:index, possible_keys:null, 键:Q52plW9W7TJWZcLj00K3FmuhwMSw4F7vmxJGyjxz5iiINVR9fXyacEoq4rHppb, key_len:257, ref:null, rows:266045508, Extra:Using where;不存在; 使用索引;使用连接缓冲区(块嵌套循环)]]
在 staging db 上添加索引后(数据略少,但结构相同)查询现在运行约 24 小时,仍然没有结果):
$ show processlist;
| Id | User | Host | db | Command | Time | State | Info
| 64 | root | localhost | staging_db | Query | 110072 | Sending data | SELECT ar.email FROM activation_request ar WHERE ar.date_confirmed is not null AND NOT EXISTS (SELE |
mysql版本:
$ select version();
5.6.16-1~exp1
列表中的所有其他命令都是Sleep
,因此没有其他查询正在运行并且可能会干扰/锁定行。
【问题讨论】:
这两种方法都应该有效地完成工作。表上有索引吗?请显示两个表的创建表语句。 ...以及解释 尝试在activation_request (date_confirmed, email)
或activation_request (email, date_confirmed)
上建立索引。
我已经做到了。查询正在运行大约。现在 24 小时没有结果。
您是否估计activation_request
中的行中有多少百分比具有date_confirmed is not null
?你有多少内存?请为这两个表提供SHOW TABLE STATUS
。
【参考方案1】:
对于这个查询:
SELECT ar.email
FROM activation_request ar
WHERE ar.date_confirmed is not null AND
NOT EXISTS (SELECT 1
FROM user u
WHERE u.username = ar.email
)
我会推荐activation_request(date_confirmed, email)
和user(username)
上的索引。
但是,除非您拥有非常大量的数据,否则您的问题可能是表被锁定了。
【讨论】:
我创建了一个带有完整转储的暂存数据库,添加了这些索引,就目前而言,查询运行了 13 个小时......以上是关于优化比较两个 MySQL 大表中的数据的主要内容,如果未能解决你的问题,请参考以下文章