2013-05-30 223 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