多列UPDATE-JOIN与多ISNULL需要很长时间?

时间:2012-05-02 21:49:56

标签: sql sql-server-2008 join isnull

我们的数据库中存储了一个程序,它通过连接30个列上的2个表并使用where条件来更新表。 SQL的格式为:

UPDATE Target
SET col1 = Source.col1
INNER JOIN Source 
on 
ISNULL(Target.Col2, '') = ISNULL(Source.Col2, '') and
ISNULL(Target.Col3, '') = ISNULL(Source.Col3, '') and
.
.
.
ISNULL(Target.Col31, '') = ISNULL(Source.Col31, '') and 

这是查询计划。将其保存到您的PC并重新打开,以便更好地扩展。

enter image description here

Source表有65M记录,Target 165M。以前它曾经在很长一段时间内运行。考虑到查询的丑陋和潜在的低效率,我发现这令人惊讶。本月它运行了1.5个小时,使用了100%的处理器,我们不得不杀死它。

有任何建议如何即兴发布以下查询并使其按时运行..?

我们在30-col连接条件中使用的一些列上有单列索引。

我知道ISNULL函数和30列的连接是坚果,这是一个糟糕的设计。不要怪我,我继承了这种经济。

不幸的是,没有时间进行重新设计。有什么建议吗?

2 个答案:

答案 0 :(得分:5)

  1. 请发布估算执行计划的屏幕截图
  2. 我怀疑之前的查询使用了散列连接(它应该这样),但不知何故基数估计现在错了,你得到一个循环连接。在查询上打一个散列连接提示,看它是否修复了这个(INNER HASH JOIN)。一旦我们有了确切的计划,我们就可以说更多。
  3. 将等号更改为(A1 = A2 OR (A1 IS NULL AND A2 IS NULL))。 SQL Server实际上识别此模式并在内部将其转换为“完全等于没有愚蠢的空语义”。即使使用空值,也可以通过这种方式查找索引。
  4. 如果这没有用,请务必执行步骤(3)并在col2-col31上创建覆盖索引,包括col1。这将为您提供合并连接,这是本案例中最有效的计划。它真的很快。警告:这会使表的磁盘大小加倍并降低更新速度。

答案 1 :(得分:0)

DBa建议我们按照查询分析器的建议添加一个包含所有30列的索引,大多数是“包含”列。这允许查询完成。在我们运行的下个月,通常在1.5小时内运行的相同更新SQL在24小时内没有完成。当我们运行更新统计信息时,它在一小时内完成。