提高T-SQL脚本的速度

时间:2011-02-19 01:10:31

标签: sql sql-server sql-server-2005 tsql

我需要为以下脚本大幅提高速度。我正在考虑删除表值函数并将所有内容放在存储过程中。但在我这样做之前,我想让专家们看看,并为我提供解决方案或一些指示。脚本具有分页功能,需要以某种方式保留在原位。

首先是商店程序:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROC [sbuser].[sp_MemberSearch]
@UserName varchar(200) = null,
@MemberID bigint = null,
@PG int = 1,
@ROWCT numeric(18,2) = 1,
@COLCT numeric(18,2) = 1,
@MODE varchar(50)

AS

IF @MODE = 'MEMBERSEARCH'
BEGIN
    SELECT
    MemberID,       -- 0
    UserName,       -- 1
    LastLogin,      -- 2
    PrCity,         -- 3
    Abbr,           -- 4
    Country,        -- 5
    AvatarMed,      -- 6
    Gender,         -- 7
    HasImages,      -- 8
    HasVideo,       -- 9
    HasAudio,       -- 10
    Domain,         -- 11 
    DisplayName,    -- 12
    CreateDate,     -- 13
    Claimed,        -- 14
    PG,             -- 15
    MAXPG,          -- 16
    TOTALRECS,      -- 17
    ProfileTypeID,  -- 18
    Zip,            -- 19
    PhoneNbr,       -- 20
    PrPhone         -- 21
    FROM sbuser.tf_FindMember(@UserName,@MemberID,@PG,@ROWCT,@COLCT)

END

这里是上面提到的表值函数:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO

ALTER FUNCTION [sbuser].[tf_FindMember] (
    @UserName varchar(200) = null,
@MemberID bigint = null,
@PG int = 1,
@ROWCT numeric(18,2) = 1,
@COLCT numeric(18,2) = 1 )

RETURNS @OUT TABLE (
MemberID bigint,          -- 0
UserName varchar(200),    -- 1
LastLogin datetime,       -- 2
PrCity varchar(50),       -- 3
Abbr varchar(5),          -- 4
Country varchar(50),      -- 5
AvatarMed varchar(50),    -- 6
Gender varchar(50),       -- 7
HasImages bit,            -- 8
HasVideo bit,             -- 9
HasAudio bit,             -- 10
Domain varchar(100),      -- 11
DisplayName varchar(255), -- 12
CreateDate datetime,      -- 13
Claimed varchar(1),       -- 14
PG int,                   -- 15
MAXPG int,                -- 16
TOTALRECS int,            -- 17
ProfileTypeID bigint,     -- 18
Zip varchar(50),          -- 19
PhoneNbr varchar(50),     -- 20
PrPhone varchar(25))      -- 21

AS

BEGIN

DECLARE @START numeric(18,2)
DECLARE @END numeric(18,2)
DECLARE @SIZE numeric(18,2)
DECLARE @MAXPG numeric(18,2)
DECLARE @TOTALRECS numeric(18,2)    
DECLARE @TOTALRECS_INT int
DECLARE @MAXPG_INT int
DECLARE @TOTALRECS_REMAINDER numeric(18,2)
SET @SIZE = @ROWCT * @COLCT
SET @Start = (((@PG - 1) * @Size) + 1)
SET @END = (@START + @SIZE - 1)


DECLARE @TMP1 TABLE (
    TMPID bigint  primary key identity(1,1),
    MemberID bigint,
    UserName varchar(200),
    LastLogin datetime,
    PrCity varchar(50),
    Abbr varchar(5),
    Country varchar(50),
    AvatarMed varchar(50),
    Gender varchar(50),
    HasImages bit,
    HasVideo bit,
    HasAudio bit,
    Domain varchar(100),
    DisplayName varchar(255),
    CreateDate datetime,
    Claimed varchar(1),
    ProfileTypeID bigint,
    Zip varchar(50),
    PhoneNbr varchar(50),
    PrPhone varchar(25))

        BEGIN

            INSERT INTO @TMP1
            SELECT 
            a.MemberID,
            a.UserName,
            a.LastLogin,
            a.PrCity,
            b.Abbr,
            c.Country,
            a.AvatarMed,
            a.Gender,
            sbuser.sf_MemberHasImages(a.MemberID),
            sbuser.sf_MemberHasVideo(a.MemberID),
            sbuser.sf_MemberHasAudio(a.MemberID),
            d.Domain,
            sbuser.sf_DisplayName(a.MemberID),
            a.CreateDate,
            a.Claimed,
            a.ProfileTypeID,
            a.Zip,
            a.PhoneNbr,
            a.PrPhone
            FROM Member a
            LEFT JOIN State b ON b.StateID = a.StateID
            INNER JOIN Country c ON c.countryID = a.CountryID
            INNER JOIN Region d ON d.RegionID = a.MemberRegionID
            WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%')
            AND a.MemberID <> @MemberID
            ORDER BY a.Claimed DESC, sbuser.sf_MemberHasAvatar(a.MemberID) DESC, sbuser.sf_MemberHasMedia(a.MemberID) DESC
        END

    SELECT @TOTALRECS = MAX(TMPID) FROM @TMP1
    SELECT @MAXPG = @TOTALRECS / @SIZE
    SET @TOTALRECS_REMAINDER = @TOTALRECS % @SIZE
    SET @MAXPG_INT = CAST(@MAXPG AS INT)
    SET @TOTALRECS_INT = CAST(@TOTALRECS AS INT)

    IF @TOTALRECS_REMAINDER > 0 
        BEGIN
            SET @MAXPG_INT = @MAXPG_INT + 1
        END


    INSERT INTO @OUT
    SELECT
    MemberID,
    UserName,
    LastLogin,
    PrCity,
    Abbr,
    Country,
    AvatarMed,
    Gender,
    HasImages,
    HasVideo,
    HasAudio,
    Domain,
    DisplayName,
    CreateDate,
    Claimed,
    @PG,
    @MAXPG_INT,
    @TOTALRECS_INT,
    ProfileTypeID,
    Zip,
    PhoneNbr,
    PrPhone
    FROM @TMP1
    WHERE (TmpID >= @Start) AND (TmpID <= @END)

RETURN 

END

我相信这个脚本是由我的前任用软件编写的。我对T-SQL没有多少经验。我真的很感激你能提供的任何帮助来提高执行速度,因为现在我们的系统有超过40,000名成员,它已经变得非常慢。

非常感谢您一起来看看。我真的很感激!

最诚挚的问候,

保罗雅各布斯

为了进一步提供帮助,缺少sf脚本:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[sf_MemberHasImages](@MemberID bigint)

RETURNS BIT
AS
BEGIN
    DECLARE @OUT BIT
    SET @OUT = (SELECT CAST(COUNT(a.MemberImgID) AS BIT) From MemberImg a INNER JOIN MemberImgGallery b ON b.MemberImgGalleryID=a.MemberImgGalleryID
                WHERE b.MemberID = @MemberID)
    RETURN @out
END

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[sf_MemberHasAudio](@MemberID bigint)

RETURNS BIT
AS
BEGIN
DECLARE @OUT BIT
SET @OUT = (SELECT CAST(COUNT(MemberAudioID) AS BIT) FROM MemberAudio WHERE MemberID = @MemberID)
RETURN @OUT
END

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [sbuser].[sf_MemberHasVideo](@MemberID bigint)

RETURNS BIT
AS
BEGIN
DECLARE @OUT BIT
SET @OUT = (SELECT CAST(COUNT(MemberVideoID) AS BIT) FROM MemberVideo WHERE MemberID = @MemberID)
RETURN @OUT
END

1 个答案:

答案 0 :(得分:0)

查看您发布的代码,流基本上是这样的:

  • 存储过程调用UDF。
  • ----不是perf相关的,但为什么这个字符串被发送到一个名为相同的存储过程? IF @MODE = 'MEMBERSEARCH'在名为[sp_MemberSearch]的过程中(sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%')。这个曾经对代码的审查似乎是多余的。
  • 这不应该调用UDF。建议重构代码以在存储过程中进行所有搜索。今天很可能它被用于许多存储过程,所以它很容易在当前设置中重复使用。并不可怕,但你可以采取另一种方式,特别是如果你使用的是SQL Server 2008.尝试将其重新设计为自己的存储过程。

  • UDF基本上执行一个包含3个重要部分/注意事项的选择:

    1. LIKE。对我来说,这意味着将EACH成员ID传递给函数,并根据ORDER BY条件进行评估。

    2. MemberHasAvatar两种不同的UDF结果 - MemberHasMediaMember - 显然希望这些结果在顶部排序。

    3. 4个表:StateCountryRegionJOIN - 是否在SELECT ed列上正确编入索引?如果在没有WHERE子句和ORDER BY子句的任何/部分/全部的情况下运行此语句,这个WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%') AND a.MemberID <> @MemberID的执行情况如何?

  • 可以改进分页方面以使用更新的TSQL语言功能,但它可能比您想要的更多。 ROW_NUMBER()是改善的一部分。

  • 目前尚不清楚该条款的真实含义是什么:@MemberID 这是否意味着我们不希望在搜索结果中包含@SearchPerformedByMemberID,因为他们是执行搜索的成员?可能更好的变量名称适合DisplayName

您可能已经知道,数学部分对此函数/ proc不会产生任何可衡量的性能影响。

一些改进建议,YMMV!

  • 建议在Member表格中存储sbuser.sf_DisplayName,以避免拨打{{1}}。