3

我继承了一个 SQL Server 2008 R2 项目,其中包括从另一个表更新表:

  • Table1(大约 150,000 行)有 3 个电话号码字段(Tel1, Tel2, Tel3
  • Table2(大约 20,000 行)有 3 个电话号码字段(Phone1, Phone2, Phone3

..当这些数字中的任何一个匹配时,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 多分钟才能运行。

执行计划表明主要瓶颈是Nested Loop围绕聚集索引扫描Table1。两个表的列都有聚集索引ID

由于我的 DBA 技能非常有限,任何人都可以提出提高此查询性能的最佳方法吗?Tel1为,Tel2和为每一列添加索引Tel3是最好的选择,还是可以更改查询以提高性能?

4

4 回答 4

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);
于 2013-05-30T11:16:59.790 回答
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

请注意,这并不能解决数据中被骗的根本问题 - 例如,如果您的数据中的 Joe 和 Jane Bloggs 具有相同的电话号码(即使在不同的字段中),您会将两条记录更新为相同.

于 2013-05-30T12:01:30.767 回答
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 应该更快。去尝试一下。

于 2013-05-30T12:02:00.260 回答
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
于 2013-05-30T12:12:32.123 回答