问题描述
我有以下表格:address_table
CREATE TABLE `address` (
`id` varchar(255) NOT NULL,`city` varchar(255) DEFAULT NULL,`street` varchar(255) DEFAULT NULL,`house_number` varchar(255) DEFAULT NULL,`zip_code` varchar(255) DEFAULT NULL,`country` varchar(2) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `customer_address` (
`customer_id` int DEFAULT NULL,`address_id` varchar(255) DEFAULT NULL,`id` int NOT NULL AUTO_INCREMENT,PRIMARY KEY (`id`),KEY `address_id` (`address_id`),KEY `customer_id` (`customer_id`),CONSTRAINT `customer_address_ibfk_1` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`),CONSTRAINT `customer_address_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`id`)
) ENGINE=InnoDB;
地址表存储地址,customer_address 表存储客户和地址之间的关系。一个客户可以有多个地址,因此是第二个表。 地址表中存在重复的行(不同的id但相同的位置),并且customer_address表中的每个地址都有一个address_id引用,因此地址表中的每一行都被引用。
我想删除地址表中的重复项,因此将 customer_address 表中的引用调整为每个位置剩余的一个(最低)ID。 我写了以下有效的查询,问题是,它需要永远执行(估计 73 小时)。有大约。地址表中的 900'000 行和 ca。其中 390'000 个是唯一的(由 group by 语句过滤)。
update customer_address as ca set ca.address_id =
(select dfa.id from (select min(id) as id,zip_code,city,street,house_number from varys_dev.address group by zip_code,house_number) as dfa
join address as a on (dfa.city = a.city and dfa.zip_code = a.zip_code and dfa.street = a.street and dfa.house_number = a.house_number)
where a.id = ca.address_id limit 1);
有什么方法可以提高该查询的性能?我尝试为 join-on 子句使用的属性建立索引,但这没有任何帮助。
解决方法
如果我猜对了,您需要一个表将 id 解码为组内的最小 id
update `customer_address` as ca
join (select id,min(id) over (partition by zip_code,city,street,house_number) mid
from `address`
) as a on ca.id = a.id
set ca.address_id = a.mid
,
不要一次性完成。相反,编写一个循环(在客户端代码中)以
- 找到“下一个”重复项
- 修复它们。
- 进入下一批
这可能仍需要几天时间,但不会影响系统的其余部分。
第一步
SELECT a.id,b.id
FROM address AS a
JOIN address AS b USING(city,house_number,state,zip_code,country)
WHERE a.id BETWEEN $left_off AND $left_off + 100
步骤 2
使用这个简短的、可能为空的列表,修复链接。
第三步
$left_off = $left_off + 100
如果没有就退出。
完成后最好添加
UNIQUE(city,country)
以防止进一步的重复。如果添加索引失败,则有更多的 dup 需要清理;从上次中断的地方继续。
关于删除分块等的更多信息:http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks