繁体   English   中英

为了获得SQL Server性能,我可以在INSERT到临时表中使用基于集合的SQL吗?

[英]to gain SQL Server performance can I use something like set-based SQL with INSERT to temp-table?

使用SQL Server 2008 R2

我从此函数有一个20秒的查询,该查询正在使用游标,While循环和AND调用另一个函数。

根据显示的代码-改善此瓶颈性能的最佳方法是什么?

USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[ufnGetForUser] (@UserName VARCHAR(100))
RETURNS @User TABLE (
    ID INT
    ,Name VARCHAR(40)
    ,ParentID INT
    ,CompanyID INT
    ,CompanyName VARCHAR(100)
    ,CompanyDisplayName VARCHAR(100)
    ,AnotherID INT
    ,AnotherName VARCHAR(50)
    )
AS
BEGIN
    DECLARE @List TABLE (
        ID INT
        ,Name VARCHAR(40)
        ,ParentID INT
        )

    DECLARE List CURSOR
    FOR
    SELECT ID
    FROM YourTable WITH (NOLOCK)
    WHERE CompanyID IN (
            SELECT companyid
            FROM UserToCompany
            WHERE UserName = @UserName
            )

    DECLARE @ID AS INT

    OPEN List

    FETCH List
    INTO @id

    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        INSERT INTO @List
        SELECT *
        FROM ufnIncludeWithChildren(@ID)

        FETCH List
        INTO @ID
    END

    CLOSE List

    DEALLOCATE List

    INSERT INTO @User
    SELECT DISTINCT a.ID
        ,a.Name
        ,a.ParentID
        ,c.CompanyID
        ,c.CompanyName
        ,c.CompanyDisplayName
        ,d.AnotherID
        ,d.AnotherName
    FROM @List a
    JOIN YourTable b ON a.ID = b.ID
    JOIN CompanyInfo c ON b.CompanyID = c.CompanyID
    JOIN Anothers d ON b.AnotherID = d.AnotherID

    RETURN
END

您应该可以使用一个选择。

USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[ufnGetForUser] (@UserName VARCHAR(100))
RETURNS @User TABLE (
    ID INT
    ,Name VARCHAR(40)
    ,ParentID INT
    ,CompanyID INT
    ,CompanyName VARCHAR(100)
    ,CompanyDisplayName VARCHAR(100)
    ,AnotherID INT
    ,AnotherName VARCHAR(50)
    )
AS
BEGIN
    INSERT INTO @User
        SELECT DISTINCT a.ID
            ,a.Name
            ,a.ParentID
            ,c.CompanyID
            ,c.CompanyName
            ,c.CompanyDisplayName
            ,d.AnotherID
            ,d.AnotherName
        FROM UserToCompany u
        JOIN CompanyInfo c ON u.CompanyID = c.CompanyID 
        CROSS APPLY ufnIncludeWithChildren(yt.ID) a
        JOIN YourTable b ON a.ID = b.ID
        JOIN Anothers d ON b.AnotherID = d.AnotherID
        WHERE u.UserName = @UserName
    RETURN
END

乍一看,我们绝对可以消除CURSOR 尽管用WHILE循环替换它是一种解决方案,但我们可以更进一步,通过使用APPLY子句直接针对行中的每个值调用函数,从而完全消除循环。

ALTER FUNCTION [dbo].[ufnGetForUser] (@UserName VARCHAR(100))
RETURNS @User TABLE (
    ID INT
    ,Name VARCHAR(40)
    ,ParentID INT
    ,CompanyID INT
    ,CompanyName VARCHAR(100)
    ,CompanyDisplayName VARCHAR(100)
    ,AnotherID INT
    ,AnotherName VARCHAR(50)
    )
AS
BEGIN
    DECLARE @List TABLE (
        ID INT
        ,Name VARCHAR(40)
        ,ParentID INT
        )

    INSERT INTO @List
    SELECT sfn.*
    FROM YourTable yt WITH (NOLOCK)
    CROSS APPLY ufnIncludeWithChildren(yt.ID) sfn
    WHERE yt.CompanyID IN (
            SELECT companyid
            FROM UserToCompany
            WHERE UserName = @UserName
    )

    INSERT INTO @User
    SELECT DISTINCT a.ID
        ,a.Name
        ,a.ParentID
        ,c.CompanyID
        ,c.CompanyName
        ,c.CompanyDisplayName
        ,d.AnotherID
        ,d.AnotherName
    FROM @List a
    JOIN  b ON a.ID = b.ID
    JOIN CompanyInfo c ON b.CompanyID = c.CompanyID
    JOIN Anothers d ON b.AnotherID = d.AnotherID

    RETURN
END

此代码未经测试,但应该可以工作。 如果您有任何问题,请告诉我。

另外,在您的问题中,您从第一个查询(光标所在的位置)中省略了表名,因此我将YourTable放在其中作为占位符。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM