优化比较两个 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 大表中的数据的主要内容,如果未能解决你的问题,请参考以下文章

Mysql某个表有近千万数据,CRUD比较慢,如何优化?

mysql比较两个表中的某个字段大小,并取最大值

Mysql语句优化

如何优化mysql中的大表?

从 MySQL 中的大表中删除重复项的最快过程是啥

MySQL查询优化从大表中获取8-10条记录