Sql server SQL Server加入问题/替代方法

Sql server SQL Server加入问题/替代方法,sql-server,join,Sql Server,Join,我有一个查询,我正试图找出客户id之间的连锁关系。目前,80k条记录大约需要7分钟。你能建议一些替代的改进方法吗 示例格式如下所示。在这里,我们是基于记录进行分组的,这些记录之间存在关系a=b=c Create table #chaintable ( CustID int, MatchCustID int, FN varchar(10), LN varchar(10), PhoneNo int, Email varchar(50),

我有一个查询,我正试图找出客户id之间的连锁关系。目前,80k条记录大约需要7分钟。你能建议一些替代的改进方法吗

示例格式如下所示。在这里,我们是基于记录进行分组的,这些记录之间存在关系a=b=c

Create table #chaintable
(
    CustID int, 
    MatchCustID int, 
    FN varchar(10), 
    LN varchar(10), 
    PhoneNo int, 
    Email varchar(50), 
    dtAppointment int
)

insert into #chaintable
Select 1,2,'Global','Chain',123,'',1
union all
Select 2,3,'Global','Chain',123,'a@a.com',2
union all
Select 3,2,'Global','Chain',567,'a@a.com',3
union all
Select 4,5,'Global1','Chain1',123,'a@a.com',1
union all
Select 5,4,'Global1','Chain1',123,'a@a.com',2

Select distinct 
    A.CustID, A.MatchCustID, A.GroupID  
from 
    (select 
         c1.CustID, c1.MatchCustID, C1.dtAppointment,
         case 
            when C1.CustID = C2.MatchCustID and C1.MatchCustID <> C2.CustID 
               then C1.CustID
            when C1.CustID <> C2.MatchCustID and C1.MatchCustID = C2.CustID 
               then c1.MatchCustID
            when C1.CustID = C2.MatchCustID and C1.MatchCustID = C2.CustID 
               then 
                  case 
                     when c1.CustID < C1.MatchCustID 
                        then c1.CustID
                        else c1.MatchCustID
                  end
         end GroupID
     from 
         #chaintable C1, #chaintable C2
     where 
         c1.CustID = c2.MatchCustID 
         or c1.MatchCustID = c2.CustID) A

首先,在不知道执行计划的情况下,不可能帮助提高查询的性能

这里有一些我不明白的问题。例如,为什么有一个表本身的连接,并且所有输出都是第一个表的值。加入真的有必要吗?还是仅仅为了测试

我建议使用下面的逻辑等效方法重写查询,而无需在连接中使用OR,并且对人类理解查询的工作量更少,如果计算机感觉相同,则可能会有所改进

SELECT DISTINCT c1.CustID, c1.MatchCustID,
CASE WHEN (C1.MatchCustID <> c2.CustID) 
       OR (c1.CustID < c1.MatchCustID) THEN c1.CustID
     ELSE c1.MatchCustID END AS GroupID
FROM #chaintable C1 JOIN  #chaintable C2
ON c1.CustID = c2.MatchCustID

UNION

SELECT c1.CustID, c1.MatchCustID,
   c1.MatchCustID AS GroupID
FROM #chaintable C1 JOIN  #chaintable C2
ON c2.CustID = c1.MatchCustID AND C1.CustID<>C2.MatchCustID

首先,在向表中添加行时,尽量遵守标准。虽然UNIONALL可能足够有效地处理简单的行,但对于您提到的大量插入,它似乎相当冗长。无论如何,要确保将它们视为关系数据集,并避免不必要的步骤

此外,笛卡尔连接是古老的SQL语法,今天的外部连接和内部连接更加熟练,因此这种老式的连接只有在特殊情况下才真正有用。这不是其中之一

查看您的表格和结果,可以观察到以下关于表格结构的信息:

CustID独立于此表。 MatchCustID对订单没有限制 任命是持久的关键。 FN和LN一起构成一个ID,该ID指示GROUPID 因此,解决方案可能如下所示:

Create table #chaintable
(
    CustID int, MatchCustID int, FN varchar(10), LN varchar(10)
  , PhoneNo, Email varchar(50), dtAppointment int
) 

INSERT INTO #chaintable
VALUES (1,2,'Global','Chain',123,'',1)
     , (2,3,'Global','Chain',123,'a@a.com',2)
     , (3,2,'Global','Chain',567,'a@a.com',3)
     , (4,5,'Global1','Chain1',123,'a@a.com',1)
     , (5,4,'Global1','Chain1',123,'a@a.com',2)

SELECT CustID
      ,MatchCustID
      ,dtAppointment
      , FN
      , LN
      , DENSE_RANK() OVER (ORDER BY FN + LN DESC ) AS GroupID
FROM #chaintable
结果:

CustID  MatchCustID dtAppointment     FN       LN   GroupID
1               2         1         Global    Chain     1
2               3         2         Global    Chain     1
3               2         3         Global    Chain     1
4               5         1         Global1   Chain1    2
5               4         2         Global1   Chain1    2
这里唯一的问题是如何使用唯一ID。在本例中,由于我没有唯一标识事件链的值,所以我使用FN+LN返回订单

这有几个优点:

通过一次通过行,可以避免代价高昂的笛卡尔连接。 对于最终表中的每个组,GROUPID始终相同。 进行预检查并不困难: 在运行insert语句以添加前面在insert语句中检查的pre值之前:

DECLARE @GROUPID = (SELECT ISNULL(MAX(GROUPID), 0) FROM <SourceTable> )
INSERT INTO FINAL_TABLE (CustID, MatchCustID, FN, LN, PhoneNo, Email, dtAppointment)
SELECT  CustID
      , MatchCustID
      , FN
      , LN
      , PhoneNo
      , Email
      , dtAppointment
      , @GROUPID + DENSE_RANK() OVER (ORDER BY FN + LN DESC ) AS GroupID
FROM #chaintable_sub
这将始终导致下一个GROUPID的数量大于上一个条目的数量


最后,我建议您按实际情况对待这些数据:脏数据。您必须对它执行ETL转换,特别是因为您有一个带有复合ID密钥的持久密钥……因此本质上是一个事实表。

@DVT执行计划将是相同的。这也没用,为什么要使用工会呢?只需正确操作:插入COL_1、COL_2值等-25年前,在ANSI-92 SQL标准中,旧样式的逗号分隔表列表样式被正确的ANSI连接语法所取代,不鼓励使用它,因为查询成本=25%。您的查询成本=75%。请参见执行计划。这并不能提高性能:@MegaTron你有80k记录版本的执行计划吗?如果是的话,你能把它寄出去吗?它不合适。看看你们使用union时的操作。联合进行多表扫描和哈希match@MegaTron您是否在OP post中看到外部查询的SELECT DISTINCT?这也是一种排序。因此,如果您在一些数据上有如此糟糕的成本,那么为什么您认为它对80k记录有好处请注意,有许多方法可以实现这一点,因此一定要测试不同的方法。请注意,运算符用于表之间的大量数据。希望我能给您一些关于如何继续ETL过程的见解。当做
DECLARE @GROUPID = (SELECT MAX(GROUPID) FROM <SourceTable> )
SELECT FN + LN FROM #chaintable A
WHERE NOT EXISTS (SELECT 1
                  FROM #chaintable
                  WHERE A.FN = FN
                    AND A.LN = LN)
DECLARE @GROUPID = (SELECT ISNULL(MAX(GROUPID), 0) FROM <SourceTable> )
INSERT INTO FINAL_TABLE (CustID, MatchCustID, FN, LN, PhoneNo, Email, dtAppointment)
SELECT  CustID
      , MatchCustID
      , FN
      , LN
      , PhoneNo
      , Email
      , dtAppointment
      , @GROUPID + DENSE_RANK() OVER (ORDER BY FN + LN DESC ) AS GroupID
FROM #chaintable_sub