Sql server SQL Server加入问题/替代方法
我有一个查询,我正试图找出客户id之间的连锁关系。目前,80k条记录大约需要7分钟。你能建议一些替代的改进方法吗 示例格式如下所示。在这里,我们是基于记录进行分组的,这些记录之间存在关系a=b=cSql 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),
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