Mysql 如何将更新分解为子查询?

Mysql 如何将更新分解为子查询?,mysql,sql-update,Mysql,Sql Update,存在一个表: CREATE TABLE person ( id INT(10) PRIMARY KEY AUTO_INCREMENT, nameFirst VARCHAR(255) DEFAULT '?', nameSecond VARCHAR(255) DEFAULT '', fatherNameFirst VARCHAR(255) DEFAULT NULL ); 注意:实际上还有其他列,总共18列,但这里不使用它们 目标是通过使用孩子的第二个名字来设置父亲的

存在一个表:

CREATE TABLE person
(
    id INT(10) PRIMARY KEY AUTO_INCREMENT,
    nameFirst VARCHAR(255) DEFAULT '?',
    nameSecond VARCHAR(255) DEFAULT '',
    fatherNameFirst VARCHAR(255) DEFAULT NULL
);
注意:实际上还有其他列,总共18列,但这里不使用它们

目标是通过使用孩子的第二个名字来设置父亲的名字。它可以从俄语的第二个名字(守护神)中预测出来,但并不总是正确的。因此,我计划做一些可以自动完成的事情,有些稍后会手工完成

因此,
更新
操作如下:

UPDATE person AS child
LEFT JOIN
  (SELECT DISTINCT nameFirst FROM person) AS parent
    ON CONCAT(parent.nameFirst,'овна')=child.nameSecond OR CONCAT(parent.nameFirst,'ович')=child.nameSecond
SET child.fatherNameFirst=parent.nameFirst;
最终,它将需要在一个有>2m个条目的表上运行,因为现在我已经尝试使用400k的样本数据。问题是,在我的计算机使用了大约一个小时后,如果它的核心是100%,那么查询还没有完成

所以我在想,如果我能把它分解成子查询,那么这些子查询可以设置为一个接一个地运行,但是每个子查询应该需要5-10分钟。这样,如果我需要做一些事情,我可以终止当前运行的一个,而不会损失一天的CPU时间


我尝试添加:
WHERE child.id您可以按字母顺序将其分解,方法是将
WHERE nameFirst(如“A%”)添加到更新查询中,然后多次运行查询

给定此示例数据:

CREATE TABLE person
(
    id INT(10) PRIMARY KEY AUTO_INCREMENT,
    nameFirst VARCHAR(255) DEFAULT '?',
    nameSecond VARCHAR(255) DEFAULT '',
    fatherNameFirst VARCHAR(255) DEFAULT NULL
) DEFAULT CHARSET=utf8;


INSERT INTO person
    (`id`, `nameFirst`, `nameSecond`)
VALUES
    (1, 'Туликович', NULL),
    (2, 'Август', 'Михайлович'),
    (3, 'Август', 'Христианович'),
    (4, 'Александр', 'Александрович'),
    (5, 'Александр', 'Христьянович'),
    (6, 'Альберт', 'Викторович'),
    (7, 'Альбрехт', 'Александрович'),
    (8, 'Амалия', 'Андреевна'),
    (9, 'Амалия', 'Ивановна'),
    (10, 'Ангелина', 'Андреевна')
;
通过您的查询,您可以得到以下
EXPLAIN
输出:

+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows | Extra                                              |
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
|  1 | PRIMARY     | child      | ALL  | NULL          | NULL | NULL    | NULL |   10 | NULL                                               |
|  1 | PRIMARY     | <derived2> | ALL  | NULL          | NULL | NULL    | NULL |   10 | Using where; Using join buffer (Block Nested Loop) |
|  2 | DERIVED     | person     | ALL  | NULL          | NULL | NULL    | NULL |   10 | Using temporary                                    |
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
这消除了使用临时
。那很好。
使用nameFirst上的索引,我们可以进一步加快速度

CREATE INDEX idx_person_nameFirst ON person(nameFirst);
然后再解释一下:

+----+-------------+--------+-------+---------------+----------------------+---------+------+------+-----------------------------------------------------------------+
| id | select_type | table  | type  | possible_keys | key                  | key_len | ref  | rows | Extra                                                           |
+----+-------------+--------+-------+---------------+----------------------+---------+------+------+-----------------------------------------------------------------+
|  1 | SIMPLE      | child  | ALL   | NULL          | NULL                 | NULL    | NULL |   10 | NULL                                                            |
|  1 | SIMPLE      | parent | index | NULL          | idx_person_nameFirst | 768     | NULL |   10 | Using where; Using index; Using join buffer (Block Nested Loop) |
+----+-------------+--------+-------+---------------+----------------------+---------+------+------+-----------------------------------------------------------------+
还不完美,但它正在使用索引。这将大大加快速度

从现在开始,很难进一步优化。您可以通过调整来进行一些试验,但我建议您仅在会话中进行此操作

SET SESSION join_buffer_size = <whatever value>;
SET SESSION join_buffer_size=;

连接到服务器的每个线程都使用自己的连接缓冲区。这就是为什么您应该只在会话中测试它。当您的服务器上有很多连接时,内存消耗可能会失控。

是否可以通过在更新查询中添加
where nameFirst(如“A%”)来分解此问题,然后多次运行查询?@bunnmatt这是个好主意。事实上,我可以通过给孩子的中间名和父亲的第一个名字加上where来优化它。将测试。@bunnmatt在2分钟内完成。33(俄语字母)*2只需一个多小时,但最初的查询时间超过了这个时间。这个查询占用了我5%的内存,所以问题可能就在那里。如果你写下来作为回答,我会接受的!
+----+-------------+--------+-------+---------------+----------------------+---------+------+------+-----------------------------------------------------------------+
| id | select_type | table  | type  | possible_keys | key                  | key_len | ref  | rows | Extra                                                           |
+----+-------------+--------+-------+---------------+----------------------+---------+------+------+-----------------------------------------------------------------+
|  1 | SIMPLE      | child  | ALL   | NULL          | NULL                 | NULL    | NULL |   10 | NULL                                                            |
|  1 | SIMPLE      | parent | index | NULL          | idx_person_nameFirst | 768     | NULL |   10 | Using where; Using index; Using join buffer (Block Nested Loop) |
+----+-------------+--------+-------+---------------+----------------------+---------+------+------+-----------------------------------------------------------------+
SET SESSION join_buffer_size = <whatever value>;