sql - 提高更新大表内容的查询性能的最佳方法

标签 sql sql-server oracle

我必须执行一个相对非常大的表(80M 条记录)Invoice_Payment 的更新。它应该更新另一个表 Invoice_Payment_updated 中的数据,该表的行数为 Invoice_Payment 的 10%-15%。 为了进行说明,请查看以下演示表:

   Invoice_Payment                         Invoice_Payment_updated
   ---------------                         -----------------------                    
   Customer_id   Invoice_no                Id   Cust_id   Invoice_no      
     10          10100001                  1     10       20200100        
     11          10100002                  2     11       20200101        
     12          10100003
     13          10100004

我知道 Merge 通常用于执行 UPSERT,其执行时间比等效的 Update 语句长几倍。但相比之下,在某些情况下,带有多个子查询的普通更新语句的性能较低。

MERGE INTO Invoice_Payment ip
USING (SELECT ipu.Cust_id, ipu.Invoice_no from Invoice_Payment_updated ipu
       INNER JOIN Invoice_Payment ip ON ip.Customer_id = ipu.Cust_id
       WHERE ipu.Cust_id = ip.Customer_id and ipu.Invoice_no <> ip.Invoice_no) t
ON (ip.Customer_id = t.Cust_id)
WHEN MATCHED THEN
UPDATE SET ip.Invoice_no = t.Invoice_no;

为了提高性能,我可以使用 ROWCOUNT 批量更新,但这不会加快执行速度,只会有助于减少整体锁定。

以下简单的 Update 语句返回相同的输出:

UPDATE Invoice_Payment 
SET Invoice_no = (SELECT ipu.Invoice_no
                  FROM Invoice_Payment_updated ipu
                  WHERE ipu.Cust_id = Invoice_Payment.Customer_id 
                  AND ipu.Invoice_no <> Invoice_Payment.Invoice_no)

WHERE EXISTS (SELECT 1
              FROM Invoice_Payment_updated ipu
              WHERE ipu.Cust_id = Invoice_Payment.Customer_id
              AND ipu.Invoice_no <> Invoice_Payment.Invoice_no);

使用 SQL 合并和更新的想法是一个非常聪明的想法,但我听说当我需要更新一个又大又宽的表中的许多记录(即超过 75M)时,它们都会因性能问题而失败。此外,重新创建全表会产生大量的 IO 负载,更不用说由于使用子查询而基本上将表临时存储多次会占用大量空间。

使用临时表解决此问题的另一种方法:

CREATE TABLE tmp (
    Cust_id int,
    Invoice_no int);

INSERT INTO tmp_stage VALUES
(SELECT ipu.Cust_id, ipu.Invoice_no FROM Invoice_Payment_updated ipu
 INNER JOIN Invoice_Payment ip ON ip.Customer_id = ipu.Cust_id
 WHERE ipu.Cust_id = ip.Customer_id and ipu.Invoice_no <> ip.Invoice_no);

UPDATE (SELECT tmp.Cust_id, ip.Customer_id, tmp.Invoice_no, tgt.Invoice_no
        FROM tmp INNER JOIN Invoice_Payment ip
        ON tmp.Cust_id = ip.Customer_id)
SET tmp.Invoice_no = ip.Invoice_no;

我想知道在有多个子查询的情况下使用哪一个更好?

欢迎任何想法,并且非常感谢对原始问题的完全不同的解决方案。

最佳答案

UPDATE i
SET i.Invoice_no = io.Invoice_no
FROM Invoice_Payment i
   INNER JOIN Invoice_Payment_updated io on i.Customer_id = io.cust_id
WHERE i.Invoice_no <> iu.Invoice_no    -- assuming Invoice_no cannot be NULL

如果更新花费太多时间,请添加 WHILE 循环并更新 TOP (10000) 直到 @@ROWCOUNT = 0。批处理模式可以提高性能。

关于sql - 提高更新大表内容的查询性能的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38887682/

相关文章:

sql-server - 保护级别在项目中更改 - 现在项目将无法构建

SQL 条件/案例连接/多态关联?

mysql - #Sql比较一张表的数据和select查询结果的数据

sql - Excel VBA - 存储过程 (SQL Server)

oracle - schema_version 没有选择权限?

Java double 据类型不应该用于精确值,例如货币?

sql - 如何在 SQL 中查询具有相同值的组

sql - 计算外环的角度 PostGIS(多边形和多边形)

mysql - 在mysql中合并两个表

sql - 我可以将 SQL Server 排序顺序存储在变量中吗?