用另一个 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;
我有一个名为 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;