bounty将在17小时后到期。回答此问题可获得+50声望奖励。dai.hop希望引起更多关注此问题。
我有以下查询:
UPDATE
`temp_table`,
`sms`
SET
`sms`.`to` = `temp_table`.`new_value`
WHERE
`sms`.`to` = `temp_table`.`old_value`;
temp_table
有大约200,000行。sms
有大约2,000,000行。sms
. to
、temp_table
. new_value
和temp_table
. old_value
是带索引的VARCHAR(255)。
值为英国电话号码。
更新查询很慢,从来没有完成过。有人知道为什么吗?
说明:
建表文本结果:
- 来自phpMyAdmin*
CREATE TABLE `temp_table` (
`old_value` varchar(255) DEFAULT NULL,
`new_value` varchar(255) DEFAULT NULL
) ENGINE = InnoDB DEFAULT CHARSET = latin1 COLLATE = latin1_swedish_ci;
ALTER TABLE `temp_table`
ADD KEY `old_value` (`old_value`),
ADD KEY `new_value` (`new_value`);
CREATE TABLE `sms` (
`id` int(11) NOT NULL,
`branch_id` int(11) DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
`message_id` int(11) DEFAULT NULL,
`message` text DEFAULT NULL,
`from` varchar(255) DEFAULT NULL,
`to` varchar(255) DEFAULT NULL,
`status` varchar(255) DEFAULT NULL,
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL
) ENGINE = InnoDB DEFAULT CHARSET = utf8 COLLATE = utf8_general_ci;
ALTER TABLE `sms`
ADD PRIMARY KEY (`id`),
ADD KEY `idx-sms-branch_id` (`branch_id`),
ADD KEY `idx-sms-customer_id` (`customer_id`),
ADD KEY `idx-sms-message_id` (`message_id`),
ADD KEY `idx-sms-to` (`to`),
ADD KEY `idx-sms-created_at` (`created_at`),
ADD KEY `idx-sms-updated_at` (`updated_at`);
ALTER TABLE `sms`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
4条答案
按热度按时间30byixjq1#
sms
(然后JOIN
到另一个表),那么temp_table
最好使用INDEX(old_value, new_value)
_而不是INDEX(old_value)
。message_id
和消息文本都在这个表中?可能将这对放在另一个表中会使这个查询快得多。(然后在这个表中只有message_id
。如果text
通常很大,这一点尤其重要。UPDATEing
200K行一次更新需要很多时间和RAM。一个计划是一次更新1K。参见 chunking。我无法预测这三个建议中哪一个最有帮助。如果可行的话,我建议你把所有的建议都做一遍。
g6ll5ycj2#
您没有ON clause,但您使用了WHERE子句:
INNER JOIN和,(逗号)在没有连接条件的情况下在语义上等价**:两者都在指定的表之间产生笛卡尔积**(即,第一个表中的每一行都与第二个表中的每一行连接)。
...
与ON一起使用的search_condition是可以在WHERE子句中使用的形式为的任何条件表达式。通常,ON子句用于指定如何连接表的条件,WHERE子句限制结果集中包含哪些行。
在你的例子中,最终结果是相同的(but in other cases is not)。从概念上讲,“where”过滤发生在表以笛卡尔积连接之后,查询优化器肯定可以做一些事情并“下推”where predicate ,但我建议初学者使用dedicated syntax指导MySQL,以允许它构建一个明智的执行计划。
如果你注意到在documentation about update它说:
table_references子句列出了连接中涉及的表。**其语法在13.2.13.2节“JOIN子句”中进行了描述。以下是一个示例:
前面的示例显示了使用逗号运算符的内部连接,但多表UPDATE语句可以使用SELECT语句中允许的任何类型的连接,如LEFT JOIN。
因此,MySQL文档中使用的示例使用了一个可用的连接,该连接是笛卡尔积
llmtgqce3#
Update语句的解释显示了temp_table的'old_value'(possible_keys)的用法,而sms表的select_type是'UPDATE',两者都与OP输出不同。
除此之外,这两个表的COLLATE和CHARSET定义也不一致,这也可能对性能产生一些副作用。
使用20k temp_table测试大约20k sms,我的简陋机器在0.63秒内完成,其中所有记录都被更新。只有更新查询的相关字段具有唯一值。
更新:
表temp_table:
祝你好运
cnwbcb6i4#
您可以在查询中使用MySQL Update with Join。
另外,如果您可以索引搜索列**“temp_table.old_value”**,则会更好。
所以,搜索结果更快。