SQL服务器更新查询极慢
SQL Server update query extremely slow
我想在 table 上使用 c.200m 记录进行简单的更新语句。但是,它似乎需要很长时间。
UPDATE a
SET hybrid_trade_flag = CASE WHEN b.trade_id IS NOT NULL THEN 'Y' ELSE 'N' END
FROM [tbl_master_trades] a
LEFT JOIN [tbl_hybrid_trades_subset] b
ON a.trade_id = b.trade_id
第一个 table tbl_master_trades
有 c.200m 条记录,并在 trade_id
和另一列(一起)上创建了索引。第二个 table tbl_hybrid_trades_subset
大约有 200k。在我不得不取消它之前,这个查询 运行 超过 40 分钟(取消本身花了大约 30 分钟)。
我认为也许将第二个 table 转换为临时 table 并拆分语句会有所帮助,因此将其转换为以下内容:
UPDATE a
SET hybrid_trade_flag = 'Y'
FROM [tbl_master_trades] a
INNER JOIN #tmp_hybrid_trades b
ON a.trade_id = b.trade_id
UPDATE a
SET hybrid_trade_flag = 'N'
FROM [tbl_master_trades] a
WHERE hybrid_trade_flag IS NULL
甚至以上两个查询也需要 30 分钟才能 运行。我需要在 1 日 运行 几个这样的更新 (c.80) table,所以我不确定这是否可行,因为这需要几天时间!有人可以建议 if/how 我可以加快速度吗?
我将首先重写查询以使用 exists
:
update t
set hybrid_trade_flag = case
when exists(select 1 from tbl_hybrid_trades_subset ts where ts.trade_id = t.trade_id)
then 'Y'
else 'N'
end
from tbl_master_trades t
然后,我会推荐 tbl_hybrid_trades_subset(trade_id)
上的索引,以便子查询可以快速执行。
tbl_master_trades(trade_id)
上的索引也可能有帮助(索引中没有任何其他列),但子查询地址的 table 上的索引似乎更重要。
也就是说,200M 行仍然是一个很大的行数,因此查询可能会花费相当多的时间。
您 运行 遇到 2 个问题
- 您正在检查另一个 table
中是否存在 c.200m 值
- 您正在更新基础中的 c.200m 值 table
要解决此问题,您可以
- 将适当的索引添加到查找中 table
- 避免在非严格需要的地方更新
有问题的索引是
CREATE INDEX idx_trade_id ON tbl_hybrid_trades_subset (trade_id)
要限制更新量,请使用:
UPDATE a
SET hybrid_trade_flag = CASE WHEN b.trade_id IS NOT NULL THEN 'Y' ELSE 'N' END
FROM [tbl_master_trades] a
LEFT OUTER JOIN [tbl_hybrid_trades_subset] b
ON b.trade_id = a.trade_id
WHERE hybrid_trade_flag != CASE WHEN b.trade_id IS NOT NULL THEN 'Y' ELSE 'N' END
第一次可能还需要一段时间,但后续更新应该会快很多。
我想在 table 上使用 c.200m 记录进行简单的更新语句。但是,它似乎需要很长时间。
UPDATE a
SET hybrid_trade_flag = CASE WHEN b.trade_id IS NOT NULL THEN 'Y' ELSE 'N' END
FROM [tbl_master_trades] a
LEFT JOIN [tbl_hybrid_trades_subset] b
ON a.trade_id = b.trade_id
第一个 table tbl_master_trades
有 c.200m 条记录,并在 trade_id
和另一列(一起)上创建了索引。第二个 table tbl_hybrid_trades_subset
大约有 200k。在我不得不取消它之前,这个查询 运行 超过 40 分钟(取消本身花了大约 30 分钟)。
我认为也许将第二个 table 转换为临时 table 并拆分语句会有所帮助,因此将其转换为以下内容:
UPDATE a
SET hybrid_trade_flag = 'Y'
FROM [tbl_master_trades] a
INNER JOIN #tmp_hybrid_trades b
ON a.trade_id = b.trade_id
UPDATE a
SET hybrid_trade_flag = 'N'
FROM [tbl_master_trades] a
WHERE hybrid_trade_flag IS NULL
甚至以上两个查询也需要 30 分钟才能 运行。我需要在 1 日 运行 几个这样的更新 (c.80) table,所以我不确定这是否可行,因为这需要几天时间!有人可以建议 if/how 我可以加快速度吗?
我将首先重写查询以使用 exists
:
update t
set hybrid_trade_flag = case
when exists(select 1 from tbl_hybrid_trades_subset ts where ts.trade_id = t.trade_id)
then 'Y'
else 'N'
end
from tbl_master_trades t
然后,我会推荐 tbl_hybrid_trades_subset(trade_id)
上的索引,以便子查询可以快速执行。
tbl_master_trades(trade_id)
上的索引也可能有帮助(索引中没有任何其他列),但子查询地址的 table 上的索引似乎更重要。
也就是说,200M 行仍然是一个很大的行数,因此查询可能会花费相当多的时间。
您 运行 遇到 2 个问题
- 您正在检查另一个 table 中是否存在 c.200m 值
- 您正在更新基础中的 c.200m 值 table
要解决此问题,您可以
- 将适当的索引添加到查找中 table
- 避免在非严格需要的地方更新
有问题的索引是
CREATE INDEX idx_trade_id ON tbl_hybrid_trades_subset (trade_id)
要限制更新量,请使用:
UPDATE a
SET hybrid_trade_flag = CASE WHEN b.trade_id IS NOT NULL THEN 'Y' ELSE 'N' END
FROM [tbl_master_trades] a
LEFT OUTER JOIN [tbl_hybrid_trades_subset] b
ON b.trade_id = a.trade_id
WHERE hybrid_trade_flag != CASE WHEN b.trade_id IS NOT NULL THEN 'Y' ELSE 'N' END
第一次可能还需要一段时间,但后续更新应该会快很多。