我有一个更新语句,它工作正常,但需要很长时间才能完成。
我正在更新一个表中的大约 150 行,其中通过视图公开了数万行。有人建议我使用 Partition By 子句来加快该过程。
我不太熟悉 Partition By 语句,但我一直在环顾四周,我认为也许我需要使用具有可以比较的数值的字段。
这是对的吗?或者我可以用其他东西对较大的表进行分区吗?
如果是这种情况,我正在努力解决可以使用较大表中的内容。该表组成如下。
ID的类型为 NUMBER,并为特定项目创建唯一 ID。Start_Date具有日期类型,并指示 ID 有效时的开始时间。结束日期具有日期类型,指示 ID 不再有效的结束时间。ID_Type是 NVARCHAR2(30),表示我们使用的标识符类型。ID_Type2是 NVARCHAR2(30) 表示我们正在使用的标识符sub_type。标识符为 NVARCHAR2(30),任何一个 ID 都可以映射到一个或多个标识符。
所以例如 - View_ID
ID | Start_Date | End_Date | ID_Type1| ID_Type2 | Identifier
1 | 2012-01-01 | NULL | Primary | Tertiary | xyz1
1 | 2012-01-01 | NULL | Second | Alpha | abc2
2 | 2012-01-01 | 2012-01-31 | Primary | Tertiary | ghv2
2 | 2012-02-01 | NULL | Second | Alpha | mno4
是否可以按此视图的 ID 字段进行分区,只要有一个子句表明 id 在日期之前有效?
更新语句是非常基本的,尽管它针对几个可能的标识符和ID_Type1之一进行选择。
UPDATE Temp_Table t set ID =
(SELECT DISTINCT ID FROM View_ID v
WHERE inDate BETWEEN Start_Date and End_Date
AND v.Identifier = (NVL(t.ID1, NVL(t.ID2, t.ID3)))
AND v.ID_Type1 in ('Primary','Secondary'));
提前感谢您对我问题的任何方面的任何建议。
附加信息 ***
在调查并遵循戈登的建议后,我将更新更改为三个更新。这将整个更新过程减少了 75%,从一分多钟缩短到 20 多秒。这是一个很大的改进,但如果可能的话,我想进一步减少这个过程。
有没有人认为分区依据子句会进一步帮助?如果是这样,将此子句放入更新语句的正确方法是什么。老实说,我不确定我是否理解这个条款是如何运作的。
如果使用 SELECT 语句的 UPDATE 只允许选择 1 个值,这是否会排除类似以下内容的内容起作用?
UPDATE Temp_Table t SET t.ID =
(SELECT DISTINCT ID,
Row_Number () (OVER PARTITION BY ID_Type1) AS PT1
FROM View_ID v
WHERE inDate BETWEEN v.Start_Date and v.End_Date
AND v.Identifier = t.ID1
AND PT1.Row_Number = 1 )
*解决方案**
******我结合了下面两个响应者的建议,以显着提高性能。从戈登那里,我从我的更新中删除了NVL,并将其更改为三个单独的更新。(我宁愿将它们合并成一个案例,但我的试验仍然很慢。
从 Eggi 开始,我查看了某种物化视图,我实际上可以为自己编制索引,并确定了 WITH 子句。
UPDATE Temp_Table t set ID =
(WITH IDs AS (SELECT /*+ materialize */ DISTINCT ID, Identifier FROM View_ID v
WHERE inDate BETWEEN Start_Date and End_Date
AND v.Identifier = ID1)
SELECT g.ID FROM IDs g
WHERE g.Identifier = t.ID1;
再次感谢。
很难想象Windows/分析函数将如何帮助此更新。 我强烈建议您学习它们,但不是为了这个目的。
也许建议是对表使用的表空间进行分区。 请注意,这与"分区依据"语句非常不同,后者通常指窗口/分析函数。 表空间分区可能有助于提高性能。 但是,您可以尝试其他方法。
我认为您的问题是临时表和视图之间的连接。 据推测,您正在创建临时表。 您应该添加一个新列,例如 UsedID,其定义如下:
coalesce(t.ID1, t.ID2, t.ID3) as UsedId
更新中的"WHERE"子句将是:
WHERE inDate BETWEEN Start_Date and End_Date AND
v.Identifier = t.UsedId AND
v.ID_Type1 in ('Primary', 'Secondary')
我怀疑性能问题是在连接中使用 NVL,这会干扰优化策略。
回应您的评论. . .您的原始查询将具有与此版本相同的问题。 也许你想要的逻辑是:
WHERE inDate BETWEEN Start_Date and End_Date AND
v.Identifier in (t.ID1, t.ID2, t.ID3) AND
v.ID_Type1 in ('Primary', 'Secondary')
分区的最佳选项似乎是开始日期,因为它似乎总是有一个值,并且您还可以将其作为查询中的输入参数获取。
如果您还没有这样做,我会在ID_Type1上添加一个位图索引。