SQL Server查询需要8分钟才能完成。各项指标良好

SQL Server查询需要8分钟才能完成。各项指标良好,sql,sql-server,performance,sails-mssqlserver,Sql,Sql Server,Performance,Sails Mssqlserver,下面是我正在运行的查询。执行计划在底部。完成需要8分钟,并在查询计划中显示“与批次相关的查询成本:84%”。 我已经修复了一些必需的非集群索引,但在运行时几乎没有节省一分钟 Select distinct ItemSolicitacao.IdItemSolicitacao As IdItemSolicitacao, ItemSolicitacao.IdSolicitacao As IdSolicitacao, ItemSolicitacao.IdItemAplica

下面是我正在运行的查询。执行计划在底部。完成需要8分钟,并在查询计划中显示“与批次相关的查询成本:84%”。 我已经修复了一些必需的非集群索引,但在运行时几乎没有节省一分钟

Select distinct 
    ItemSolicitacao.IdItemSolicitacao As IdItemSolicitacao, 
    ItemSolicitacao.IdSolicitacao As IdSolicitacao, 
    ItemSolicitacao.IdItemAplicacao As IdItemAplicacao, 
    ItemSolicitacao.Mapeado As Mapeado, 
    ItemSolicitacao.IdFuncao As IdFuncao, 
    ItemSolicitacao.IdDepartamento As IdDepartamento, 
    ItemSolicitacao.IdDeptoGrupo As IdDeptoGrupo, 
    ItemSolicitacao.Removido As Removido, 
    ItemSolicitacao.AtividadeNome As AtividadeNome, 
    ItemSolicitacao.Acao As Acao, 
    Aplicacao.Nome As AplicacaoNome, 
    dbo.OwnersItemAplicacao(ItemSolicitacao.IdItemAplicacao, ItemSolicitacao.IdSolicitacao) As Owner, 
    case 
        when((select count(d.codigo) from ControleXerox..departamento as d 
              where d.deptoPai = Departamento.Codigo) != 0)  
           then 1 
           else 0 
    end as Grupo, 
    Departamento.Nome As DepartamentoNome, 
    DeptoOutro.Nome As DepartamentoGrupoNome, 
    Funcao.Nome As FuncaoNome, 
    TipoAplicacao.Nome As TipoAplicacaoNome, 
    TipoItemAplicacao.Nome As TipoItemAplicacaoNome, 
    ItemAplicacao.Nome As ItemAplicacaoNome 
From 
    ItemSolicitacao 
Inner Join 
    ItemAplicacao ON ItemSolicitacao.IdItemAplicacao = ItemAplicacao.IdItemAplicacao 
Inner Join 
    Aplicacao ON ItemAplicacao.IdAplicacao = Aplicacao.IdAplicacao 
Inner Join 
    TipoAplicacao ON TipoAplicacao.IdTipoAplicacao = Aplicacao.IdTipoAplicacao 
Inner Join 
    TipoItemAplicacao ON ItemAplicacao.IdTipoItemAplicacao = TipoItemAplicacao.IdTipoItemAplicacao 
left Join 
    ControleXerox..Departamento ON Departamento.Codigo = ItemSolicitacao.IdDepartamento 
left Join 
    ControleXerox..Departamento as DeptoOutro ON DeptoOutro.Codigo = ItemSolicitacao.IdDeptoGrupo 
left Join 
    ControleXerox..Funcao ON Funcao.Codigo = ItemSolicitacao.IdFuncao 
Inner Join 
    AprovadorItemAplicacao ON AprovadorItemAplicacao.IdItemAplicacao = ItemAplicacao.IdItemAplicacao 
Inner Join 
    Aprovador on AprovadorItemAplicacao.idAprovador = Aprovador.idAprovador 
              and AprovadorItemAplicacao.IdTipoAprovador = 1

请查找标量函数的详细信息

CREATE FUNCTION [dbo].[OwnersItemAplicacao] 
(
    @IdItemAplicacao INT
    ,@IdSolicitacao INT
)
RETURNS VARCHAR(2000)
AS
BEGIN
    DECLARE @saida VARCHAR(2000)

    SET @saida = ' '

    DECLARE @owner VARCHAR(200)

    DECLARE cur CURSOR
    FOR
    SELECT DISTINCT vc.Nome
    FROM controlexerox..grupoEstacao
    INNER JOIN controlexerox..view_colaboradores vc ON grupoEstacao.codEstacao = (
            SELECT max(e.codigo)
            FROM controlexerox..workflowItem wi
            INNER JOIN controlexerox..estacao e ON e.codWorkflowItem = wi.codigo
                AND wi.codigoItem = @IdSolicitacao
            INNER JOIN controlexerox..grupoEstacao ge ON ge.codEstacao = e.codigo
                AND ge.idItemAplicacao = @IdItemAplicacao
            )
        AND grupoEstacao.LoginS3Responsavel = vc.codigo
    ORDER BY vc.Nome;

    OPEN cur

    FETCH NEXT
    FROM cur
    INTO @owner

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @saida = @saida + CHAR(10) + @owner

        FETCH NEXT
        FROM cur
        INTO @owner
    END

    CLOSE cur

    DEALLOCATE cur

    RETURN substring(@saida, 3, len(@saida))
END

这段代码是100%未经测试,因为我没有任何工作。但是沿着这条线的东西应该可以让你完全消除这个标量函数。请记住,sql是一种声明性语言,最适合于集合。处理RBAR(一行接一行)将耗尽服务器的生命

试一下这段代码,看看它是否能让你找到正确的方向

Select distinct 
    s.IdItemSolicitacao
    , s.IdSolicitacao
    , s.IdItemAplicacao
    , s.Mapeado
    , s.IdFuncao
    , s.IdDepartamento
    , s.IdDeptoGrupo
    , s.Removido
    , s.AtividadeNome
    , s.Acao
    , a.Nome As AplicacaoNome
    --, dbo.OwnersItemAplicacao(s.IdItemAplicacao, s.IdSolicitacao) As Owner
    , Owner = x.NameList
    , case when (select count(d.codigo) from ControleXerox..departamento as dept where dept.deptoPai = d.Codigo) != 0 then 1 else 0 end as Grupo,
    , d.Nome As DepartamentoNome
    , DeptoOutro.Nome As DepartamentoGrupoNome
    , f.Nome As FuncaoNome
    , Tipoa.Nome As TipoAplicacaoNome
    , Tipoia.Nome As TipoItemAplicacaoNome
    , ia.Nome As ItemAplicacaoNome 
From ItemSolicitacao s
Inner Join ItemAplicacao ia ON s.IdItemAplicacao = ia.IdItemAplicacao 
Inner Join Aplicacao a ON ia.IdAplicacao = a.IdAplicacao 
Inner Join TipoAplicacao Tipoa ON Tipoa.IdTipoAplicacao = a.IdTipoAplicacao 
Inner Join TipoItemAplicacao Tipoia ON ia.IdTipoItemAplicacao = Tipoia.IdTipoItemAplicacao 
left Join ControleXerox..Departamento d ON d.Codigo = s.IdDepartamento 
left Join ControleXerox..Departamento as DeptoOutro ON DeptoOutro.Codigo = s.IdDeptoGrupo 
left Join ControleXerox..Funcao f ON f.Codigo = s.IdFuncao 
Inner Join AprovadorItemAplicacao Aprovadoria ON Aprovadoria.IdItemAplicacao = ia.IdItemAplicacao 
Inner Join Aprovador ON Aprovadoria.idAprovador = Aprovador.idAprovador 
    and Aprovadoria.IdTipoAprovador = 1
outer apply
(
    select NameList = STUFF((select char(10) + vc.Nome
                FROM controlexerox..grupoEstacao ge
                INNER JOIN controlexerox..view_colaboradores vc ON ge.codEstacao = 
                        (
                            SELECT max(e.codigo)
                            FROM controlexerox..workflowItem wi
                            INNER JOIN controlexerox..estacao e ON e.codWorkflowItem = wi.codigo
                                        AND wi.codigoItem = s.IdSolicitacao
                            INNER JOIN controlexerox..grupoEstacao ge ON ge.codEstacao = e.codigo
                                    AND ge.idItemAplicacao = s.IdItemAplicacao
                        )
                    AND grupoEstacao.LoginS3Responsavel = vc.codigo
                group by vc.Nome
                ORDER BY vc.Nome
                FOR XML PATH('')), 1, 1, '')
) x

这段代码是100%未经测试,因为我没有任何工作。但是沿着这条线的东西应该可以让你完全消除这个标量函数。请记住,sql是一种声明性语言,最适合于集合。处理RBAR(一行接一行)将耗尽服务器的生命

试一下这段代码,看看它是否能让你找到正确的方向

Select distinct 
    s.IdItemSolicitacao
    , s.IdSolicitacao
    , s.IdItemAplicacao
    , s.Mapeado
    , s.IdFuncao
    , s.IdDepartamento
    , s.IdDeptoGrupo
    , s.Removido
    , s.AtividadeNome
    , s.Acao
    , a.Nome As AplicacaoNome
    --, dbo.OwnersItemAplicacao(s.IdItemAplicacao, s.IdSolicitacao) As Owner
    , Owner = x.NameList
    , case when (select count(d.codigo) from ControleXerox..departamento as dept where dept.deptoPai = d.Codigo) != 0 then 1 else 0 end as Grupo,
    , d.Nome As DepartamentoNome
    , DeptoOutro.Nome As DepartamentoGrupoNome
    , f.Nome As FuncaoNome
    , Tipoa.Nome As TipoAplicacaoNome
    , Tipoia.Nome As TipoItemAplicacaoNome
    , ia.Nome As ItemAplicacaoNome 
From ItemSolicitacao s
Inner Join ItemAplicacao ia ON s.IdItemAplicacao = ia.IdItemAplicacao 
Inner Join Aplicacao a ON ia.IdAplicacao = a.IdAplicacao 
Inner Join TipoAplicacao Tipoa ON Tipoa.IdTipoAplicacao = a.IdTipoAplicacao 
Inner Join TipoItemAplicacao Tipoia ON ia.IdTipoItemAplicacao = Tipoia.IdTipoItemAplicacao 
left Join ControleXerox..Departamento d ON d.Codigo = s.IdDepartamento 
left Join ControleXerox..Departamento as DeptoOutro ON DeptoOutro.Codigo = s.IdDeptoGrupo 
left Join ControleXerox..Funcao f ON f.Codigo = s.IdFuncao 
Inner Join AprovadorItemAplicacao Aprovadoria ON Aprovadoria.IdItemAplicacao = ia.IdItemAplicacao 
Inner Join Aprovador ON Aprovadoria.idAprovador = Aprovador.idAprovador 
    and Aprovadoria.IdTipoAprovador = 1
outer apply
(
    select NameList = STUFF((select char(10) + vc.Nome
                FROM controlexerox..grupoEstacao ge
                INNER JOIN controlexerox..view_colaboradores vc ON ge.codEstacao = 
                        (
                            SELECT max(e.codigo)
                            FROM controlexerox..workflowItem wi
                            INNER JOIN controlexerox..estacao e ON e.codWorkflowItem = wi.codigo
                                        AND wi.codigoItem = s.IdSolicitacao
                            INNER JOIN controlexerox..grupoEstacao ge ON ge.codEstacao = e.codigo
                                    AND ge.idItemAplicacao = s.IdItemAplicacao
                        )
                    AND grupoEstacao.LoginS3Responsavel = vc.codigo
                group by vc.Nome
                ORDER BY vc.Nome
                FOR XML PATH('')), 1, 1, '')
) x


大家好,欢迎来到SO。一张执行计划的照片几乎一文不值。太多细节遗漏了。一个更好的计划是使用像这样的网站。我还建议使用一些别名和空白,以使这堵文字墙清晰易读。谢谢Sean,查询计划已按照您的建议进行了更新。我甚至不需要深入查看该计划。这个功能正在杀死你。想知道多少钱吗?注释掉使用该函数的列。你需要彻底重写那件事。它应该是一个内联表值函数,而不是游标。此外,对于真正的优化,需要计算索引。仅仅说“他们很好”通常意味着他们真的不是很好。我不会改变这个函数,我会把它扔掉,重新开始。给我一点时间,我看看能不能拼凑些东西。在没有桌子的情况下工作会很有挑战性,但我想我能做到……或者至少离得很近。嗨,欢迎来到SO。一张执行计划的照片几乎一文不值。太多细节遗漏了。一个更好的计划是使用像这样的网站。我还建议使用一些别名和空白,以使这堵文字墙清晰易读。谢谢Sean,查询计划已按照您的建议进行了更新。我甚至不需要深入查看该计划。这个功能正在杀死你。想知道多少钱吗?注释掉使用该函数的列。你需要彻底重写那件事。它应该是一个内联表值函数,而不是游标。此外,对于真正的优化,需要计算索引。仅仅说“他们很好”通常意味着他们真的不是很好。我不会改变这个函数,我会把它扔掉,重新开始。给我一点时间,我看看能不能拼凑些东西。在没有桌子的情况下工作会很有挑战性,但我想我能做到……或者至少离得很近。谢谢你的努力。我犯了一个错误无法绑定多部分标识符“此错误出现在第行下方。”。grupoEstacao.logins3responseavel=vc.codigoBasic调试…将其更改为ge.Login等…我有点紧张,如果您找不到,那么您就不理解此代码。谢谢Sean,我做到了。之后我又犯了一个错误,但我无法解决它。Msg 8120,级别16,状态1,第1行列在select列表中无效,因为它未包含在聚合函数或GROUP BY子句中。是否需要按所有选定列分组?请忽略我的上一条评论(已调试)。您的代码现在已100%验证。我在2分钟内得到完全相同的输出,与以前的代码相比,这节省了6分钟。这对我来说已经足够了,我很高兴在Prod服务器上部署同样的功能。再次感谢您为理解我的问题并解决它所做的一切努力。我们可以将此问题标记为已解决。很高兴听到您的问题得到解决。如果这解决了你的问题,你应该把标记看作是被接受的答案。谢谢你付出了巨大的努力。我犯了一个错误无法绑定多部分标识符“此错误出现在第行下方。”。grupoEstacao.logins3responseavel=vc.codigoBasic调试…将其更改为ge.Login等…我有点紧张,如果您找不到,那么您就不理解此代码。谢谢Sean,我做到了。之后我又犯了一个错误,但我无法解决它。Msg 8120,级别16,状态1,第1行列在select列表中无效,因为它未包含在聚合函数或GROUP BY子句中。是否需要按所有选定列分组?请忽略我的上一条评论(已调试)。您的代码现在已100%验证。我在2分钟内得到完全相同的输出,与以前的代码相比,这节省了6分钟。这对我来说已经足够了,我很高兴在Prod服务器上部署同样的功能。再次感谢您为理解我的问题并解决它所做的一切努力。我们可以将此问题标记为已解决。很高兴听到您的问题得到解决。如果这解决了你的问题,你应该考虑标记为被接受的答案。