由于 174 个 UNION ALL 语句,SQL Server 查询 SSIS 转换超时

Posted

技术标签:

【中文标题】由于 174 个 UNION ALL 语句,SQL Server 查询 SSIS 转换超时【英文标题】:SQL Server query for SSIS transformation timing out due to 174 UNION ALL statements 【发布时间】:2020-06-12 13:01:06 【问题描述】:

我在 Hive 和 SQL Server 中有一个表,其数据存储如下。我正在使用 SSIS 将此数据移动到 SQL Server。查询时间过长。 Description 列中大约有 175 个单独的值,这会导致 174 个 UNION ALL 语句,因此查询在大约 2 小时后超时。

SQL 错误 [08S01]:org.apache.thrift.transport.TTransportException:java.net.SocketTimeoutException:读取超时*

有没有更好的方法来编写这个查询?

谢谢!

蜂巢:

ID  | Description
----+------------------------------
 1  | Desc1;Desc2;Desc3;Desc4
 2  | Desc1;Desc3;Desc4;Desc5;Desc6
 ...
230 | Desc8;Desc163;Desc9;Desc2;Desc172

SQL 服务器:

CaseID | GroupID | Description
-------+---------+--------------
   1   |    63   | Desc1
   1   |    44   | Desc2
   1   |    57   | Desc3
   1   |    78   | Desc4
   ...
   2   |    78   | Desc1
   2   |    57   | Desc3

查询:

select 
       case 
             when cas.description like '%Desc1%' then 63 
       end as groupid, -- maps to groupid
       cas.id as caseid, -- maps to caseid 
       current_timestamp as INSERT_DT
from 
       svc_case cas
inner join account acc on acc.id = cas.id
where cas.description <> 'NULL' and LENGTH(cas.description) > 0
and acc.recordid = '03443FGT'
union all 
select 
       case 
             when cas.description like '%Desc2%' then 44
       end as groupid, -- maps to groupid
       cas.id as caseid, -- maps to caseid 
       current_timestamp as INSERT_DT
from 
       svc_case cas
inner join account acc on acc.id = cas.id
where cas.description <> 'NULL' and LENGTH(cas.description) > 0
and acc.recordid = '03443FGT'
union all
select 
       case 
             when cas.description like '%Desc3%' then 57 
       end as groupid, -- maps to groupid
       cas.id as caseid, -- maps to caseid 
       current_timestamp as INSERT_DT
from 
       svc_case cas
inner join account acc on acc.id = cas.id
where cas.description <> 'NULL' and LENGTH(cas.description) > 0
and acc.recordid = '03443FGT'
union all
select 
       case 
             when cas.description like '%Desc4%' then 78 
       end as groupid, -- maps to groupid
       cas.id as caseid, -- maps to caseid 
       current_timestamp as INSERT_DT
from 
       svc_case cas
inner join account acc on acc.id = cas.id
where cas.description <> 'NULL' and LENGTH(cas.description) > 0
and acc.recordid = '03443FGT'
...
select 
       case 
             when cas.description like '%Desc175%' then 12 
       end as groupid, -- maps to groupid
       cas.id as caseid, -- maps to caseid 
       current_timestamp as INSERT_DT
from 
       svc_case cas
inner join account acc on acc.id = cas.id
where cas.description <> 'NULL' and LENGTH(cas.description) > 0
and acc.recordid = '03443FGT'

【问题讨论】:

您有 174 个 UNION ALL 语句的事实似乎是这里的真正问题。为什么你有这么多?在这里修复设计似乎是正确的选择。 很遗憾,我无法更改设计,因为 Hive DB 是第 3 方应用程序数据库,而 SQL Server 也是自定义应用程序使用的第 3 方应用程序数据库。 摆脱那些 174 UNION ALL 的解决方案。花费这么长时间的原因是您似乎要完成 348 次表扫描。难怪它会超时。 我意识到 UNION ALL 是这里的问题。试图找到一种更好的方法来编写这个查询。 我个人只会将数据传送到您的服务器,然后开始操作它。先拆分成ID,Description,然后使用引用表或Lookup添加组。 【参考方案1】:

这是在黑暗中的尝试,但您可以采取 2 项措施来改进此查询。首先,让我们解决所有这些UNION ALLs。 如果我正确理解了您的查询,您可以取消透视数据以实现相同的目的:

SELECT V.groupid,
       cas.id AS caseid,
       current_timestamp as INSERT_DT
FROM dbo.svc_case cas
     JOIN dbo.account acc on acc.id = cas.id
     CROSS APPLY (VALUES(CASE WHEN cas.description LIKE '%Desc1%' THEN 63 END),
                        (CASE WHEN cas.description LIKE '%Desc2%' THEN 44 END),
                        (CASE WHEN cas.description LIKE '%Desc3%' THEN 57 END),
                        (CASE WHEN cas.description LIKE '%Desc4%' THEN 78 END),
                        --I assume there are 174 more of these
                        (CASE WHEN cas.description LIKE '%Desc178%' THEN 1 END))V(groupid) --The last one isn't correct, but to show how the `APPLY` ends

然后你有你的WHERE,由于LENGTH,它不是SARGable。 LENGTH 实际上不是 T-SQL 运算符,所以我希望您实际上在使用 SQL Server(如果不是,这是浪费答案,因为上面是 T- SQL 特定)。考虑到LEN(NULL) 返回NULL,然后使用&lt;&gt; ''。考虑到您已经拥有&lt;&gt; 'NULL',尽管您可以使用NOT IN

WHERE cas.description NOT IN('NULL','')
  AND acc.recordid = '03443FGT'

但是,我建议不要将文字字符串值 'NULL' 存储在您的列中,您应该修复它并实际存储 NULL,而不是 'NULL';这 2 个是不同的值,并且行为非常不同。

【讨论】:

感谢您...我会尝试此查询并让您知道。非常感激。不幸的是,它们确实存储了字符串值“NULL”。我无法控制。【参考方案2】:

只运行一次查询。所以没有联合,并省略了CASE。使用多播并将其拆分到 SSIS 中。

【讨论】:

【参考方案3】:

您可以扩展代码并使用case转换为数字:

select (case when code = 'Desc1' then 63
             when code = 'Desc2' then 44
             . . .
        end) as groupid, -- maps to groupid
       cas.id as caseid, -- maps to caseid 
       current_timestamp as INSERT_DT
from svc_case cas join
     account acc
     on acc.id = cas.id lateral view
     explode(split(cas.description, ';')) codes as code
where acc.recordid = '03443FGT';

我不知道你为什么有description &lt;&gt; 'NULL'。我猜你真的想要is not null——这对于横向连接是不必要的。

另外,如果您有一个参考表,每个代码只有一行,groupid,那么可以通过加入该表来进一步简化代码。

【讨论】:

以上是关于由于 174 个 UNION ALL 语句,SQL Server 查询 SSIS 转换超时的主要内容,如果未能解决你的问题,请参考以下文章

oracle union 和 union all

sql 中union all有啥用法

sql中union 和 union all的区别

SQL语句的MINUS,INTERSECT和UNION ALL

SQL语句:使用了union all后怎么分组排序

sql语句or与union all的执行效率哪个更高