2013-05-30 261 views
3

我继承了SQL Server 2008 R2的项目,除其他外,从另一个表做一个表更新:SQL查询很慢

  • Table1(含15万左右行)有3个电话号码字段(Tel1Tel2Tel3
  • Table2(具有约20,000的行)具有3个电话号码字段(Phone1Phone2Phone3

..当这些数字中的任何一个匹配时,应该更新Table1

当前的代码如下所示:

UPDATE t1 
SET surname = t2.surname, Address1=t2.Address1, DOB=t2.DOB, Tel1=t2.Phone1, Tel2=t2.Phone2, Tel3=t2.Phone3, 
FROM Table1 t1 
inner join Table2 t2 
on 
(t1.Tel1 = t2.Phone1 and t1.Tel1 is not null) or 
(t1.Tel1 = t2.Phone2 and t1.Tel1 is not null) or 
(t1.Tel1 = t2.Phone3 and t1.Tel1 is not null) or 
(t1.Tel2 = t2.Phone1 and t1.Tel2 is not null) or 
(t1.Tel2 = t2.Phone2 and t1.Tel2 is not null) or 
(t1.Tel2 = t2.Phone3 and t1.Tel2 is not null) or 
(t1.Tel3 = t2.Phone1 and t1.Tel3 is not null) or 
(t1.Tel3 = t2.Phone2 and t1.Tel3 is not null) or 
(t1.Tel3 = t2.Phone3 and t1.Tel3 is not null); 

然而,这种查询花费30分钟来运行。

执行计划建议在Table1的集群索引扫描周围的主要瓶颈是Nested Loop。这两个表在其ID列上都有聚簇索引。

由于我的DBA技能非常有限,任何人都可以提出改善此查询性能的最佳方法吗?如果将Tel1,Tel2Tel3的索引添加到每列是最佳选择,还是可以更改查询以提高性能?

+2

适用非聚集索引上的电话1,电话2,两个表 – Vishwajeet

+1

的Tel3如果字段为空,然后一个'='将不会返回true - 你并不需要所有的'和t1.Tel1是不为空“。此外,你正在更新你正在查询的字段,这可能会造成一些数据丢失(如果'Tel1 = Phone2'但'Phone1'为空]。请先尝试使电话号码正常化(即,有一个链接的表来保存电话号码) – Keith

+0

您可以添加一些测试数据(请在SQLFiddle中说) – gbn

回答

1

首先看,我会建议从选择中删除所有的OR条件。

看看这是更快(它转换您更新到3个不同的更新):

UPDATE t1 
SET surname = t2.surname, Address1=t2.Address1, DOB=t2.DOB, Tel1=t2.Phone1, Tel2=t2.Phone2, Tel3=t2.Phone3, 
FROM Table1 t1 
inner join Table2 t2 
on 
(t1.Tel1 is not null AND t1.Tel1 IN (t2.Phone1, t2.Phone2, t2.Phone3); 

UPDATE t1 
SET surname = t2.surname, Address1=t2.Address1, DOB=t2.DOB, Tel1=t2.Phone1, Tel2=t2.Phone2, Tel3=t2.Phone3, 
FROM Table1 t1 
inner join Table2 t2 
on 
(t1.Tel2 is not null AND t1.Tel2 IN (t2.Phone1, t2.Phone2, t2.Phone3); 

UPDATE t1 
SET surname = t2.surname, Address1=t2.Address1, DOB=t2.DOB, Tel1=t2.Phone1, Tel2=t2.Phone2, Tel3=t2.Phone3, 
FROM Table1 t1 
inner join Table2 t2 
on 
(t1.Tel3 is not null AND t1.Tel3 IN (t2.Phone1, t2.Phone2, t2.Phone3); 
+0

我也想到了这种方法。它不会产生完全相同的结果,但可能会足够接近。不同之处在于,第一个查询中的任何匹配都将在第二个和第三个查询中重新更新,但是由于我不明白OP查询是如何工作的,因为每个“t1”行都可能匹配多个't2 '行 – paul

+0

我看不出结果会如何冲突。第一个查询仅查找t1.Tel1列,第二个查询仅查找t1.Tel2等... –

+0

当t1.Tel1匹配第一个查询时,t1.Tel2和t1.Tel3也是更新。 't1.Tel2'和't1.Tel3'将在查询2和3中完全匹配。 – paul

1

首先规范化表数据:

insert into Table1Tel 
select primaryKey, Tel1 as 'tel' from Table1 where Tel1 is not null 
union select primaryKey, Tel2 from Table1 where Tel2 is not null 
union select primaryKey, Tel3 from Table1 where Tel3 is not null 

insert into Table2Phone 
select primaryKey, Phone1 as 'phone' from Table2 where Phone1 is not null 
union select primaryKey, Phone2 from Table2 where Phone2 is not null 
union select primaryKey, Phone3 from Table2 where Phone3 is not null 

这些归表是一种更好的方式将您的电话号码存储为其他列。

然后,你可以做这样的事情在整个表的加盟:

update t1 
set surname = t2.surname, 
    Address1 = t2.Address1, 
    DOB = t2.DOB 
from Table1 t1 
    inner join Table1Tel tel 
     on t1.primaryKey = tel.primaryKey 
    inner join Table2Phone phone 
     on tel.tel = phone.phone 
    inner join Table2 t2 
     on phone.primaryKey = t2.primaryKey 

注意,这不能解决愚弄的根本问题在您的数据 - 例如,如果你同时拥有乔和简布洛斯在您的数据具有相同的电话号码(即使在不同的字段中),您将更新两个记录都是相同的。

1

请尝试下面的查询,并告诉我需要多长时间才能完成执行。

UPDATE t1 
SET surname = t2.surname, Address1=t2.Address1, DOB=t2.DOB, Tel1=t2.Phone1, Tel2=t2.Phone2, Tel3=t2.Phone3, 
FROM Table1 t1 
inner join Table2 t2 
on (
    '|'+cast(t2.Phone1 as varchar(15)+'|'+cast(t2.Phone1 as varchar(15)+'|'+cast(t2.Phone1 as varchar(15)+'|' LIKE '%|'+cast(t1.Tel1 as varchar(15)+'|%' 
    or '|'+cast(t2.Phone1 as varchar(15)+'|'+cast(t2.Phone1 as varchar(15)+'|'+cast(t2.Phone1 as varchar(15)+'|' LIKE '%|'+cast(t1.Tel2 as varchar(15)+'|%' 
    or '|'+cast(t2.Phone1 as varchar(15)+'|'+cast(t2.Phone1 as varchar(15)+'|'+cast(t2.Phone1 as varchar(15)+'|' LIKE '%|'+cast(t1.Tel3 as varchar(15)+'|%' 
    ) 

用1 LIKE代替3 OR应该更快。去尝试一下。

1

你也可以尝试类似下面的内容,希望避免重新更新。

UPDATE t1 
SET surname = t2.surname, 
    Address1=t2.Address1, DOB=t2.DOB, 
    Tel1=t2.Phone1, Tel2=t2.Phone2, Tel3=t2.Phone3 
FROM 
    Table1 T1 
INNER JOIN 
(
SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel1 = t2.Phone1 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel1 = t2.Phone2 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel1 = t2.Phone3 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel2 = t2.Phone1 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel2 = t2.Phone2 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel2 = t2.Phone3 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel3 = t2.Phone1 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel3 = t2.Phone2 

UNION 

SELECT 
    T1.ID AS T1_ID, 
    T2.ID AS T2_ID 
FROM 
    t1.Tel3 = t2.Phone3 

) X 
ON T1.ID = X.T1_ID 
INNER JOIN Table2 T2 ON X.T2_ID = T2.TD