连接sql中的行的最佳方法

时间:2018-08-14 08:23:03

标签: sql substring sql-server-2014

当前,我正在使用以下代码来总结已审核的固定资产的报告。最初,这没问题,三年后,我注意到系统现在非常慢。我重新查看该代码,然后发现该代码为何系统运行缓慢。当我删除子字符串部分时,系统运行速度更快。这附近有工作吗?

SELECT        
ENTITY
, [ASSET NUMBER]
, [YEAR AUDITED]
, SUM(COUNT) AS AUDITED
, SUBSTRING
    (
        (
            SELECT       
                ', ' + [SCANNED BY].USERNAME
            FROM  dbo.vwAUDITED as [SCANNED BY]
            WHERE vwAUDITED.[ASSET NUMBER] = [SCANNED BY].[ASSET NUMBER] 
                AND vwAUDITED.ENTITY = [SCANNED BY].ENTITY 
                AND vwAUDITED.[YEAR AUDITED] = [SCANNED BY].[YEAR AUDITED]
            ORDER BY [SCANNED BY].[ASSET NUMBER] FOR XML PATH('')
        ), 2, 1000
    ) AS [SCANNED BY]
, MAX(DATE) AS [COMPLETION DATE]
FROM dbo.vwAUDITED
GROUP BY ENTITY
    , [ASSET NUMBER]
    , [YEAR AUDITED]

2 个答案:

答案 0 :(得分:1)

一种方法是添加一个user-defined aggregate function,以替代您的MS SQL Server版本中缺少的STRING_AGG函数。然后用该函数替换该子查询。

此类功能的示例可以在herehere

中找到

不涉及数据库管理员的另一种方法是使用临时表,该临时表在用于通过FOR XML联接子查询的字段上使用复合索引。

db <>小提琴here

上进行测试
-- Just assuming the datatypes here, so change them to the correct types.
IF OBJECT_ID('tempdb..#tmpAUDITED') IS NOT NULL DROP TABLE #tmpAUDITED;
CREATE TABLE #tmpAUDITED 
(
  [ENTITY] INT NOT NULL,
  [ASSET NUMBER] INT NOT NULL,
  [YEAR AUDITED] INT NOT NULL,
  [COUNT] INT,
  [DATE] DATE,
  [USERNAME] VARCHAR(100),
  INDEX idx_1 NONCLUSTERED ([ENTITY], [ASSET NUMBER], [YEAR AUDITED])
);

INSERT INTO #tmpAUDITED (
[ENTITY], [ASSET NUMBER],[YEAR AUDITED], [COUNT], [DATE], [USERNAME]
)
SELECT 
[ENTITY], [ASSET NUMBER],[YEAR AUDITED], [COUNT], [DATE], [USERNAME]
FROM dbo.vwAUDITED;

-- Now using the temp table instead of the view.
SELECT
 [ENTITY],
 [ASSET NUMBER],
 [YEAR AUDITED],
 SUM([COUNT]) AS AUDITED,
 SUBSTRING
     (( 
        SELECT ', ' + s.[USERNAME]
        FROM #tmpAUDITED AS s
        WHERE s.[ENTITY] = [AUDITED].[ENTITY]
          AND s.[ASSET NUMBER] = [AUDITED].[ASSET NUMBER] 
          AND s.[YEAR AUDITED] = [AUDITED].[YEAR AUDITED]
        -- ORDER BY s.[ENTITY], s.[ASSET NUMBER], s.[YEAR AUDITED], s.[USERNAME]
        FOR XML PATH('')
     ), 2, 1000) AS [SCANNED BY],
 MAX([DATE]) AS [COMPLETION DATE]
FROM #tmpAUDITED AS [AUDITED]
GROUP BY [ENTITY], [ASSET NUMBER], [YEAR AUDITED];

另外,值得检查一下视图中的查询是否可以优化。或者在表上添加某些索引(用于视图中)可以提高视图本身的性能。

答案 1 :(得分:1)

最好的连接方式是:

declare @str nvarchar(max) = space(0);
select @str += [column] from [yourTable];
select @str;

但是,您的情况有所不同。 根据您的情况,串联效果很好,并且由于视图结构可能会导致性能下降。如果您看不到视图结构, 您可以通过使用主视图记录集作为CTE来最大程度地降低性能问题,然后在CTE而不是视图上执行成本高昂的资源交换操作:

;with [data] as (
    select [entity], [asset number], [year audited], [username], [date], [count] from [dbo].[vwAUDITED]
)
select 
     [entity]           =   [d].[entity]
    ,[asset number]     =   [d].[asset number]
    ,[year audited]     =   [d].[year audited]
    ,[audited]          =   sum([d].[count])
    ,[scanned by]       =   substring((
                                select 
                                    ', ' + [username]
                                from 
                                    [dbo].[vwAUDITED]
                                where 
                                        [asset number]  =   [d].[asset number]
                                    and [entity]        =   [d].[entity]
                                    and [year audited]  =   [d].[year audited]
                                order by 
                                     [asset number]
                                for xml path('')
                            ), 2, 1000) 
    ,[completion date] =    max([d].[date])
from 
    [data] as   [d]
group by 
     [d].[entity]
    ,[d].[asset number]
    ,[d].[year audited];