Доказательство скорости скрипта T-SQL - PullRequest
0 голосов
/ 19 февраля 2011

Мне нужно значительно улучшить скорость для следующего скрипта.Я думаю об удалении табличной функции и размещении всего в хранимой процедуре.Но прежде чем я сделаю это, я хотел, чтобы эксперты посмотрели и предоставили мне решение или несколько указателей.Сценарий имеет функцию подкачки, которая должна каким-то образом оставаться на месте.

Во-первых, это процедура Store:

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 голосов
/ 19 февраля 2011

Глядя на код, который вы разместили, поток в основном выглядит так:

  • сохраненный процесс вызывает UDF.
  • ---- не относится к perf, но почему эта строка отправляется в сохраненный процесс с таким же именем? IF @MODE = 'MEMBERSEARCH' в процедуре под названием [sp_MemberSearch]. Кажется излишним из этого повторного обзора кода.
  • это НЕ должно вызывать UDF. Предложите рефакторинг кода, чтобы все поиски были в сохраненном процессе. Вероятно, сегодня он используется во многих хранимых процессах, поэтому его легко использовать в текущей настройке. Не страшно, но вы можете сделать это по-другому, особенно если вы используете SQL Server 2008. Попробуйте перестроить его как собственный сохраненный процесс.

  • UDF в основном выполняет выборку с 3 важными частями / соображениями:

    1. (sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%'). Для меня это означает, что КАЖДЫЙ идентификатор члена передается в функцию и сравнивается с условием LIKE.

    2. ORDER BY 2 разных результата UDF - MemberHasAvatar и MemberHasMedia - очевидно, что они должны быть заказаны сверху.

    3. 4 таблицы: Member, State, Country, Region - правильно ли они проиндексированы в столбцах JOIN ed? Насколько хорошо это работает SELECT, когда вы выполняете этот оператор без какого-либо / некоторых / всего этого предложения WHERE и предложения ORDER BY?

  • аспекты подкачки могут быть улучшены для использования новых возможностей языка TSQL, но это может быть больше, чем вы хотели бы взять на себя. ROW_NUMBER() является частью этого улучшения.

  • непонятно, каково значение этого предложения в реальном мире: WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%') AND a.MemberID <> @MemberID Означает ли это, что мы не хотим включать @MemberID в результаты поиска, потому что они - участник, выполняющий поиск? Возможно, подходит лучшее имя переменной, например @SearchPerformedByMemberID?

Математическая часть, как вы, вероятно, уже знаете, не окажет какого-либо ощутимого влияния на производительность этой функции / процедуры.

Некоторые предложения по улучшению, YMMV!

  • Предложите сохранить DisplayName на столе Member, чтобы не вызывать sbuser.sf_DisplayName.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...