2013-03-04 31 views
-1

我们的工作场所有一个数据库,其中包含一个可存储500万条记录的客户端表。每次更新客户端时,都会将另一行添加到包含1亿条记录的client_history表中。客户表中的所有列都被编入索引。只有客户历史记录表中的主键(ID),外键(FK_Client_ID)和创建时间戳才被编入索引。更新查询使用EXISTS子句导致DB2中的表空间扫描缓慢

我被要求更新数十万条客户记录,但前提是相应的客户历史记录表明客户记录自某日期(例如2012年9月19日)以来未更新。

我写了一个使用EXISTS子句的SQL更新查询。数据库管理员告诉我,我不应该使用EXISTS子句,因为这会触发表格空间扫描,这会降低查询的执行速度。更新几十万客户记录时,这显然是一个问题 -

UPDATE Client_History SET Surname = 'MisterX', 
Update_Timestamp = CURRENT_TIMESTAMP 
WHERE (FK_Client_ID = 123 AND ID = 456) 
AND NOT EXISTS 
(SELECT * 
FROM Client 
WHERE Client.Client_Id = Client_History.FK_Client_ID 
AND Client_History.Update_Timestamp > TIMESTAMP('2012-09-21-00:00:00') 
AND Client_History.Update_Timestamp < TIMESTAMP('4000-12-31-00:00:00') 
AND Client_History.Creation_Timestamp < NAME.Update_Timestamp); 

任何人都可以想到更好的解决方案吗?

+0

你看过执行计划,看它是否正在进行全表扫描吗?我希望它可以使用索引。 – 2013-03-04 00:17:06

+0

我们已经决定从SQL更新查询中删除EXISTS子句会更容易,并且开发另一个程序来检查自某个日期以来是否更新了记录。我们首先运行该程序以删除所有更新的记录,然后我们直接运行SQL查询来更新客户端。 – Spacehamster 2013-03-05 23:53:12

回答

0

一个瞎猜:尽量提升所有的常数成主查询(属于他们的地方)

UPDATE Client_History ch 
SET Surname = 'MisterX' 
    , Update_Timestamp = CURRENT_TIMESTAMP 
WHERE ch.FK_Client_ID = 123 
    AND ch.ID = 456 
    AND ch.Update_Timestamp > TIMESTAMP('2012-09-21-00:00:00') 
    AND ch.Update_Timestamp < TIMESTAMP('4000-12-31-00:00:00') 
    AND ch.Creation_Timestamp < NAME.Update_Timestamp 
    AND NOT EXISTS (
    SELECT * 
    FROM Client cl 
    WHERE cl.Client_Id = ch.FK_Client_ID 
    ) 
    ; 

BTW:什么是NAME?某种伪表,如Oracle的dual

+0

抱歉 - “NAME。”应该用“ch”替换。因此该子句应为“ch.Creation_Timestamp Spacehamster 2013-03-04 22:34:27

+0

不是cl.update_timestamp?然后它可以留在主查询中。 ITYM:'ch.Creation_Timestamp wildplasser 2013-03-04 22:39:04