我试图提出一个查询,使用同一个表中的其他记录来更新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>
答案 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