请注意,为了便于阅读,我修改了表/字段名称等。有些原来的名字很混乱。
\n\n我有三个不同的表:
\n\nRetailer (Id+Code is a unique key)\n- Id\n- Code\n- LastReturnDate\n- ...\n\nDelivery/DeliveryHistory (combination of Date+RetailerId is unique)\n- Date\n- RetailerId\n- HasReturns\n- ...\nRun Code Online (Sandbox Code Playgroud)\n\nDelivery并且DeliveryHistory几乎完全相同。数据会定期移动到历史表中,并且没有可靠的方法可以知道最后一次发生这种情况的时间。一般来说,Delivery 表非常小——通常少于 100,000 行——而历史表通常有数百万行。
LastReturnDate我的任务是根据HasReturnsDelivery或DeliveryHistory 中当前最高日期值更新每个零售商的字段。
以前这个问题已经通过定义如下的视图来解决:
\n\nRetailer (Id+Code is a unique key)\n- Id\n- Code\n- LastReturnDate\n- ...\n\nDelivery/DeliveryHistory (combination of Date+RetailerId is unique)\n- Date\n- RetailerId\n- HasReturns\n- ...\nRun Code Online (Sandbox Code Playgroud)\n\n以及以下 UPDATE 语句:
\n\nSELECT Id, Code, MAX(Date) Date\n FROM Delivery\n WHERE HasReturns = 1\n GROUP BY Id, Code\nUNION\nSELECT Id, Code, MAX(Date) Date\n FROM DeliveryHistory\n WHERE HasReturns = 1\n GROUP BY Id, Code\nRun Code Online (Sandbox Code Playgroud)\n\nEXISTS 子句防止更新当前值大于新值的字段,但这实际上不是一个重要问题,因为很难看出在正常程序执行期间如何发生这种情况。另请注意该AND Max(Date) IS NOT NULL部分实际上是多余的,因为 DeliveryView 中的 Date 不可能为 null。但 EXISTS 子句似乎实际上略微提高了性能。
然而,最近 UPDATE 的性能却很糟糕。在 Retailer 表仅包含 1000-2000 个相关条目的数据库中,UPDATE 的运行时间超过五分钟。请注意,即使我删除整个 EXISTS 子句,它也会执行此操作,即使用以下非常简单的语句:
\n\nUPDATE Retailer SET LastReturnDate = (\n SELECT MAX(Date) FROM DeliveryView\n WHERE Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code)\nWHERE Code = :Code AND EXISTS (\n SELECT * FROM DeliveryView\n WHERE Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code\n HAVING\n MAX(Date) > LastReturnDate OR\n (LastReturnDate IS NULL AND MAX(Date) IS NOT NULL))\nRun Code Online (Sandbox Code Playgroud)\n\n因此我一直在寻找更好的解决方案。我的第一个想法是创建一个临时表,但过了一会儿我尝试将其写为 MERGE 语句:
\n\nUPDATE Retailer SET LastReturnDate = (\n SELECT MAX(Date) FROM DeliveryView\n WHERE Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code)\nWHERE Code = :Code\nRun Code Online (Sandbox Code Playgroud)\n\n这似乎有效,而且比 UPDATE 快一个数量级以上。
\n\n我有三个问题:
\n\n成本:25,831,字节:1,143,828
\n\nPlan Cardinality Distribution\n14 MERGE STATEMENT REMOTE ALL_ROWS\nCost: 25\xc2\xa0831 Bytes: 1\xc2\xa0143\xc2\xa0828 3\xc2\xa0738 \n 13 MERGE SCHEMA.Retailer ORCL \n 12 VIEW SCHEMA. \n 11 HASH JOIN \n Cost: 25\xc2\xa0831 Bytes: 1\xc2\xa0192\xc2\xa0422 3\xc2\xa0738 \n 9 VIEW SCHEMA. \n Cost: 25\xc2\xa0803 Bytes: 194\xc2\xa0350 7\xc2\xa0475 \n 8 SORT GROUP BY \n Cost: 25\xc2\xa0803 Bytes: 194\xc2\xa0350 7\xc2\xa0475 \n 7 VIEW VIEW SCHEMA.DeliveryView ORCL\n Cost: 25\xc2\xa0802 Bytes: 194\xc2\xa0350 7\xc2\xa0475 \n 6 SORT UNIQUE \n Cost: 25\xc2\xa0802 Bytes: 134\xc2\xa0550 7\xc2\xa0475 \n 5 UNION-ALL \n 2 SORT GROUP BY \n Cost: 97 Bytes: 25\xc2\xa0362 1\xc2\xa0409 \n 1 TABLE ACCESS FULL TABLE SCHEMA.Delivery [Analyzed] ORCL\n Cost: 94 Bytes: 210\xc2\xa0654 11\xc2\xa0703 \n 4 SORT GROUP BY \n Cost: 25\xc2\xa0705 Bytes: 109\xc2\xa0188 6\xc2\xa0066 \n 3 TABLE ACCESS FULL TABLE SCHEMA.DeliveryHistory [Analyzed] ORCL\n Cost: 16\xc2\xa0827 Bytes: 39\xc2\xa0333\xc2\xa0636 2\xc2\xa0185\xc2\xa0202 \n 10 TABLE ACCESS FULL TABLE SCHEMA.Retailer [Analyzed] ORCL\n Cost: 27 Bytes: 653\xc2\xa0390 2\xc2\xa0230\nRun Code Online (Sandbox Code Playgroud)\n\n成本:101,492,字节:272,060
\n\nPlan Cardinality Distribution\n14 UPDATE STATEMENT REMOTE ALL_ROWS\nCost: 101\xc2\xa0492 Bytes: 272\xc2\xa0060 1\xc2\xa0115 \n 13 UPDATE SCHEMA.Retailer ORCL \n 1 TABLE ACCESS FULL TABLE SCHEMA.Retailer [Analyzed] ORCL\n Cost: 27 Bytes: 272\xc2\xa0060 1\xc2\xa0115 \n 12 VIEW SCHEMA. \n Cost: 90 Bytes: 52 2 \n 11 SORT GROUP BY \n Cost: 90 Bytes: 52 2 \n 10 VIEW VIEW SCHEMA.DeliveryView ORCL\n Cost: 90 Bytes: 52 2 \n 9 SORT UNIQUE \n Cost: 90 Bytes: 36 2 \n 8 UNION-ALL \n 4 SORT GROUP BY \n Cost: 15 Bytes: 18 1 \n 3 TABLE ACCESS BY INDEX ROWID TABLE SCHEMA.Delivery [Analyzed] ORCL\n Cost: 14 Bytes: 108 6 \n 2 INDEX RANGE SCAN INDEX SCHEMA.DeliveryHasReturns [Analyzed] ORCL\n Cost: 2 12 \n 7 SORT GROUP BY \n Cost: 75 Bytes: 18 1 \n 6 TABLE ACCESS BY INDEX ROWID TABLE SCHEMA.DeliveryHistory [Analyzed] ORCL\n Cost: 74 Bytes: 4\xc2\xa0590 255 \n 5 INDEX RANGE SCAN INDEX SCHEMA.DeliveryHistoryHasReturns [Analyzed] ORCL\n Cost: 6 509\nRun Code Online (Sandbox Code Playgroud)\n