如何提高 SQL Server 中将值从非空列上移到空列的查询性能?

问题描述 投票:0回答:1

我有一张桌子

Values

Values
表:

艺术ID 变量ID 顺序 Val1 Val2 Val3 Val4 Val5 Val6 Val7 Val8 瓦尔9 Val10
1 1 1 A1-Val3
2 1 2 A2-Val6
3 2 3 A3-Val1
4 2 4 A4-Val4 A4-Val9
5 3 5 A5-Val2 A5-Val5

值根据 VarId 向上移动。对于 VarId = 1,有 2 行。 Val3 列中的条目转移到 Val1,这对于 VarId = 1 的所有记录都是相同的。因此,下一个值(即 Val6 列中的 A2-Val6)将转移到 VarId = 1 的下一个空闲列。在这种情况下,它是Val2 列。

表格的最终预期结果是

预期

Values
表:

艺术ID 变量ID 顺序 Val1 Val2 Val3 Val4 Val5 Val6 Val7 Val8 瓦尔9 Val10
1 1 1 A1-Val3
2 1 2 A2-Val6
3 2 3 A3-Val1
4 2 4 A4-Val4 A4-Val9
5 3 5 A5-Val2 A5-Val5

上表为示例。实际的表包含超过 100 万条记录,列数最多可达 100。(我知道,表中有那么多列不好,但无法更改)。

我实施了该解决方案,它返回了预期的结果。但是,我想提高数据量大时的性能。

DECLARE @start INT = 1, @end INT = 10

DECLARE @valueTable NVARCHAR(100) = N'[Values]'

DECLARE @valueColumns NVARCHAR(MAX) = N''

DECLARE @numColumns NVARCHAR(MAX)= N''
DECLARE @numColumnsWithoutNull NVARCHAR(MAX) = N''

DECLARE @attNumber NVARCHAR(3)
DECLARE @separator VARCHAR(1) = ','

WHILE @start <= @end
BEGIN
    
    SET @attNumber = CAST(@start AS NVARCHAR(3))  
    
    IF @start = @end
    BEGIN
        SET @separator = N''
    END
   
    SET @valueColumns += N'Val'+ @attNumber +''+@separator+''
            
    SET @numColumns += N'['+ @attNumber +']'+@separator+''
    SET @numColumnsWithoutNull += N'ISNULL(['+ @attNumber +'],'''') AS ['+ @attNumber +']'+@separator+''       

    SET @start = @start +1
END        

DECLARE @result NVARCHAR(MAX) =N'
DROP TABLE IF EXISTS #TempCache;
SELECT * INTO #TempCache
FROM
(
    SELECT  ArtId, VarId, Sequence, '+@numColumnsWithoutNull+'
    FROM
    (
        SELECT  VarId, ArtId, Sequence, Value, DENSE_RANK() OVER (PARTITION BY VariationGroupId ORDER BY [Cols]) AS RowId
        FROM
            (SELECT * FROM '+@valueTable+' ) AS T1
        UNPIVOT
            (value FOR [Cols] IN ('+@valueColumns+')) AS unpvt  
        WHERE Value <> ''''
    ) T
    PIVOT
    (
        MAX([value]) FOR RowId IN ('+@numColumns+')
    ) AS pvt
) Temp;
TRUNCATE TABLE '+@valueTable+';

INSERT INTO '+@valueTable+'
SELECT * FROM #TempCache 
ORDER BY Sequence
'
--SET STATISTICS XML ON;
exec sp_executesql @result
--SET STATISTICS XML OFF;
sql sql-server query-optimization sqlperformance
1个回答
0
投票

您可以利用像 json_array() 这样的函数来去除空值,算法如下: 在子查询的最内层:

select ArtId, VarId, Sequence,json_array(Val1, Val2, Val3, Val4, Val5, Val6, Val7, Val8, Val9, Val10) as js
from values 
  • 下一级,你计算数组的大小
  • 下一个级别,你“对(数组大小)求和(按变量顺序按序列分区)”
  • 下一级,您将生成 sum_array_size 为 ' ' 的“标头”数组
  • 下一个级别,您将“lag(标题)合并到(按varid order by分区) 序列)”与“js”值数组

结果应该是:

1   1   1   ["A1-Val3"]
2   1   2   [" ","A2-Val6"]
3   2   3   ["A3-Val1"]
4   2   4   [" ","A4-Val4","A4-Val9"]
5   3   5   ["A5-Val2","A5-Val5"]

然后您可以使用该查询作为 MERGE 语句中的源,使用 JSON_VALUE(result_array, '$[N]') 更新原始列,其中 N 从 0 到 N cols-1。

这样你就有了一个纯 SQL 解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.