mysql优化UPDATE JOIN性能索引

时间:2018-01-10 18:00:15

标签: mysql sql mariadb

我有这个问题:

"explain UPDATE requests R JOIN profile as P ON R.intern_id = P.intern_id OR R.intern_id_decoded = P.intern_id OR R.intern_id_full_decode = P.intern_id SET R.found_id=P.id WHERE R.id >= 28000001 AND R.id <= 28000001+2000000 AND R.found_id is NULL"
1       UPDATE  R       NULL    range   PRIMARY,intern_id_customer_id_batch_num,id_found_id     PRIMARY 4       NULL    3616888 10.00   Using where
1       SIMPLE  P       NULL    ALL     intern_id_dt_snapshot,intern_id NULL    NULL    NULL    179586254       27.10   Range checked for each record (index map: 0x6)

该查询执行大约需要40秒,它会从200万行的集合中更新5000-10000行。

我目前正在更新200万行“作业”,以使连接执行得更快。 整个表目前有1.7亿条记录。

EXPLAIN显示第二部分没有使用INDEX,我不确定这是否正确。 intern_id字段是varchars,found_id和id是INT

解释输出看起来是否正常工作? 我注意到第二行没有使用索引,不确定这是否正常。

2 个答案:

答案 0 :(得分:1)

我会使用多个连接来执行此逻辑:

UPDATE requests r LEFT JOIN
       profile p1
       ON r.intern_id = p1.intern_id LEFT JOIN
       profile p2
       ON r.intern_id_decoded = p2.intern_id AND p1.id IS NULL LEFT JOIN
       profile p3
       ON r.intern_id_full_decode = p3.intern_id AND p2.id IS NULL
    SET r.found_id = COALESCE(p1.id, p2.id, p3.id)
    WHERE R.id >= 28000001 AND R.id <= 28000001 + 2000000 AND
          R.found_id is NULL;

数据库在OR条件下优化JOIN非常糟糕。使用明确的JOIN s可能会更好。

ON条件也确保只有第一场比赛。

答案 1 :(得分:1)

我会为UPDATEs条件中的每个ON做3个UPDATE ... ON P.intern_id = R.intern_id SET ... WHERE ... UPDATE ... ON P.intern_id = R.intern_id_decoded SET ... WHERE ... UPDATE ... ON P.intern_id = R.intern_id_full SET ... WHERE ...

要更新的10K行过多;把它调低到大约1K。这意味着将分块降低到200K。 (速度可能甚至更快。)

INDEX(found_id)

(每组3的范围相同,从而有助于缓存R。)

可能SELECT id WHERE id > ... AND found_id IS NULL LIMIT 1000,1; 会有所帮助,但这不是给定的。

有关更多分块建议,请参阅here,尤其是在开始操作之前找到1000行的提示:

{{1}}

然后用它作为限制而不是百万分之二。这里的目标是均衡更新的行数。