使用SELECT子查询中的值有效地更新查询

时间:2015-03-26 00:54:57

标签: mysql database performance optimization query-optimization

我试图提出一个查询,使用同一个表中的其他记录来更新MySQL表中的记录,但是我在本地测试和生产之间得到了混合的结果。我对子查询了解不多,所以我想在这里提出这个问题。在MySQL InnoDB 5.6.23的本地开发中,对大约180k记录的数据集的查询需要25到30秒。在具有MySQL InnoDB 5.5.32的登台服务器和254k记录的数据集上,查询似乎停止了几个小时,直到它停止,占用了100%的CPU核心。

这是我提出的查询:

UPDATE
    `product_lang` AS `pl1`
SET
    pl1.`name` = (
        SELECT pl2.`name` FROM (SELECT `name`, `id_product`, `id_lang` FROM `product_lang`) AS `pl2`
        WHERE pl1.`id_product` = pl2.`id_product`
        AND pl2.`id_lang` = 1
    )
WHERE
    pl1.`id_lang` != 1

目标是将name不为1(默认语言为了解释)的产品记录中的id_lang值替换为记录值name的值{默认id_lang为1。

我知道子查询是低效的,但我真的不知道如何解决这个问题,将它留在SQL-land而不是使用app层来完成繁重工作将是一个很大的好处。 / p>

4 个答案:

答案 0 :(得分:2)

如果您编写如下查询:

UPDATE product_lang pl1
    SET pl1.name = (SELECT pl2.`name`
                    FROM (SELECT `name`, `id_product`, `id_lang`
                          FROM `product_lang`
                         ) `pl2`
                    WHERE pl1.`id_product` = pl2.`id_product` AND pl2.`id_lang` = 1
                   )
WHERE pl1.`id_lang` <> 1

然后你有问题。可以提供帮助的唯一索引是product_lang(id_lang)

我建议将其写为join

UPDATE product_lang pl1 join
       (select id_product, pl.name
        from product_lang
        where id_lang = 1
       ) pl2
       on pl1.id_lang <> 1 and pl2.id_product = pl1.id_product
    SET pl1.name =  pl2.name
WHERE pl1.id_lang <> 1

此查询所需的索引为product_lang(id_lang, id_product)product_lang(id_product)。但是,这似乎是一个奇怪的update,因为它会将所有名称设置为语言1中的名称。

答案 1 :(得分:1)

UPDATE product_lang AS pl1
  JOIN product_lang AS pl2
      ON pl1.`id_product` =
         pl2.`id_product`
  SET pl1.name = pl2.name
  WHERE pl2.`id_lang`  = 1
    AND pl1.`id_lang` != 1;

并拥有INDEX(id_lang, id_product)

答案 2 :(得分:0)

确保有一个索引指定列id _ product和id_lang。

答案 3 :(得分:0)

更新pl1 设置pl1.name = pl2.name 来自product_lang pl1 ,product_lang pl2 其中pl1。id_product = pl2。id_product AND pl2。id_lang = 1 和pl1。id_lang&lt;&gt; 1

将需要的composit索引为

的id_product和id_lang