用另一个 table 中的一次性值更新一个 table 中每一行的最快方法是什么?

What is the quickest way to update each row in one table with a use-once value from another table?

我有一个名为 dbo.RecycleProductID 的 table,它只有一个主键 ProductID 列和一个 Used 列:

ProductID (pk, int) | Used (bit)
23                    1   
65                    1
68                    1
90                    NULL
104                   NULL  
...
60983471              NULL

上面的 table 有大约 6.5m ProductID 的值需要 'recycled' 并分配给不同的 table 中的产品。将 ProductID 分配给产品后,我必须将 Used 列值更新为 1 以表明它已被使用。 ProductID 序列中有间隙,有几千个(例如它可以从 1010 跳到 8055)并且这个 table 中的行比接收 table dbo.Product table。

dbo.Product table(大约 150 万行)只是一个产品列表,但没有 ProductID 值。

ProductID (pk, int)  | ProductName (varchar)
23                     Toothpaste
65                     Speakers
68                     Galaxy S8
NULL                   Plate
NULL                   Monitor
NULL                   Carpet
.....

我目前正在 运行 一个 while 循环以将 ProductID 值从 dbo.RecycleProductID 获取到 dbo.Product table:

DECLARE @Max int = (select max(ProductID) from [dbo].[RecycleProductID]);
DECLARE @Min int = (select min(ProductID) from [dbo].[RecycleProductID]);

while @Min <= @Max 
begin

UPDATE TOP (1)
[dbo].[Product]
SET ProductID = (SELECT TOP 1 ProductID FROM [dbo].[RecycleProductID] b1 WHERE b1.Used IS NULL ORDER BY ProductID ASC)
OUTPUT INSERTED.ProductID INTO dbo.UsedProductID
WHERE 
ProductID is null;

UPDATE  
    rp1
SET    
    rp1.Used = 1
FROM
    [dbo].[RecycleProductID] rp1
INNER JOIN
    dbo.UsedProductID ub1 ON 
    ub1.ProductID = rp1.ProductID

set @Min = @Min+1
end;

这基本上是一个 CURSOR,它需要很长时间。已经 运行 快两天了,只更新了大约 326515 行。有更快的方法吗?

试试这个查询:

with t1 as (
    select
        ProducID, row_number() over (order by ProducID) rn
    from 
        RecycleProductID
    where
        used is null
)
, t2 as (
    select
        ProducID, row_number() over (order by ProducID) rn
    from 
        Product
    where
        ProductID is null
)

update t2
set t2.ProducID = t1.ProducID
from
    t2
    join t1 on t2.rn = t1.rn

编辑:此查询将更新 RecycleProductID 并且可以单独执行

update RecycleProductID
set used = 1
where ProducID in (select ProductID from Product)

喜欢接受的解决方案
对于第二次更新尝试

update RecycleProductID
set used = 1 
from RecycleProductID
join Product
  on RecycleProductID.ProductID = Product.ProductID  
 and used is null 

因为 MYSQL 不允许在 WITH 上更新,您可以使用此查询在 MYSQL 上完成工作:

with t1 as (
    select
        ProducID, row_number() over (order by ProducID) rn
    from 
        RecycleProductID
    where
        used is null
)
, t2 as (
    select
        ID, ProducID, row_number() over (order by ProducID) rn
    from 
        Product
    where
        ProductID is null
)

update Product t3
join t2 on t2.ID = t3.ID
join t1 on t1.rn = t2.rn

set t3.ProducID = t1.ProducID;