1

以下のストアド プロシージャがあります。合計レコードを返さずにうまく機能しますが、別のクエリで合計レコードを返すと、非常に遅くなります。

より高速な方法で合計レコードを返す別の方法はありますか

ビューは

SELECT     dbo.tbl_ImagesMaster.ImgTitle, dbo.tbl_ImagesMaster.ImgID, dbo.tbl_ImagesMaster.ImgDate, dbo.tbl_ImagesMaster.ImgActive, 
                      dbo.tbl_ImagesMaster.ImgHits, dbo.aspnet_Users.UserName, dbo.tbl_ImagesMaster.ImgUserID, dbo.tbl_ImagesDetails.ImgDPath, 
                      dbo.tblUsersExtended.UAvatar, dbo.tbl_ImagesMaster.ImgRemarks
FROM         dbo.tbl_ImagesMaster INNER JOIN
                      dbo.aspnet_Users ON dbo.tbl_ImagesMaster.ImgUserID = dbo.aspnet_Users.UserId INNER JOIN
                      dbo.tbl_ImagesDetails ON dbo.tbl_ImagesMaster.ImgID = dbo.tbl_ImagesDetails.ImgDParentID INNER JOIN
                      dbo.tblUsersExtended ON dbo.aspnet_Users.UserId = dbo.tblUsersExtended.UUserID
WHERE     (dbo.tbl_ImagesDetails.ImgDDefault = 1)

SP

ALTER Procedure [dbo].[usp_searchImagestest] 

(
@CurrentPage As int=1,
@PageSize As int=10,
@searchType As int=1,
@Activeflag As bit=null,
@searchTerm as nvarchar(200),
@TotalRecords As int OUTPUT
)
As
begin
-- Turn off count return.
Set NoCount On


    --Full text search
    if @searchType=1
    begin
        select 
            ImgID,ImgTitle,ImgDate,imgHits,UserName,uavatar,RowRank
        from
            (Select
                ImgID,imgtitle,ImgDate,imghits,UserName,UAvatar
                , ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
            From
                 vw_MasterImagesSearch
                WHERE FREETEXT(*, @searchTerm) and (@Activeflag IS NULL or ImgActive=@Activeflag)
            ) as MyImages
        where

            RowRank > (@PageSize * (@CurrentPage-1)) AND RowRank <= (@CurrentPage * @PageSize)

-- TOTAL RECORD, WHICH SLOW DOWN THE WHOLE SP EXECUTION
        select @TotalRecords = (select COUNT(*) From vw_MasterImagesSearch 
        WHERE FREETEXT(*, @searchTerm) and (@Activeflag IS NULL or ImgActive=@Activeflag))
    end

編集

私はこれを試しました

クエリ 1

select 
        ImgID,ImgTitle,ImgDate,imgHits,RowRank,TOTALCOUNT,
        (select username from aspnet_Users where UserId=MyImages.imguserid) as username,
        (select UAvatar from tblUsersExtended where UUserID=MyImages.imguserid) as Uavatar

    from
        (Select
            ImgID,imgtitle,ImgDate,imghits,ImgUserID
            , ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
            ,COUNT(*) OVER() AS TOTALCOUNT
        From
             tbl_ImagesMaster
            WHERE FREETEXT(ImgTitle, @searchTerm) and (@Activeflag IS NULL or ImgActive=@Activeflag)
        ) as MyImages
    where

        RowRank > (@PageSize * (@CurrentPage-1)) AND RowRank <= (@CurrentPage * @PageSize)

クエリ 2

    select 
        ImgID,ImgTitle,ImgDate,imgHits,RowRank,
        (select username from aspnet_Users where UserId=MyImages.imguserid) as username,
        (select UAvatar from tblUsersExtended where UUserID=MyImages.imguserid) as Uavatar

    from
        (Select
            ImgID,imgtitle,ImgDate,imghits,ImgUserID
            , ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
        From
             tbl_ImagesMaster
            WHERE FREETEXT(ImgTitle, @searchTerm) and (@Activeflag IS NULL or ImgActive=@Activeflag)
        ) as MyImages
    where

        RowRank > (@PageSize * (@CurrentPage-1)) AND RowRank <= (@CurrentPage * @PageSize)

    select @TotalRecords = (select COUNT(*) From tbl_ImagesMaster
    WHERE FREETEXT(ImgTitle, @searchTerm) and (@Activeflag IS NULL or ImgActive=@Activeflag))

クエリ 1 は 3 秒かかりました クエリ 2 は 1 秒未満でした

テーブル内の合計行数は 100,000 行です

4

3 に答える 3

3

その2番目の選択は、検索を最初からやり直しています。ページ検索を変更するだけです:

SELECT 
    ImgID,ImgTitle,ImgDate,imgHits,UserName,uavatar,RowRank, TOTALCOUNT
FROM
    (SELECT
        ImgID,
        imgtitle,
        ImgDate,
        imghits,
        UserName,
        UAvatar, 
        ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
        COUNT(*) OVER() AS TOTALCOUNT
    FROM
         vw_MasterImagesSearch
        WHERE FREETEXT(*, @searchTerm) and (@Activeflag IS NULL or ImgActive=@Activeflag)
    ) as MyImages
WHERE
    RowRank > (@PageSize * (@CurrentPage-1)) AND RowRank 

The line

COUNT(*) OVER() AS TOTALCOUNT

ページングが発生する前の内部 SELECT の数を示します。

于 2012-06-06T20:46:07.353 に答える
0

ストアドプロシージャを使用してパラメータ付きのクエリ結果を取得すると、SQL ServerはこのSPの実行プランを生成し、後でSPを呼び出すたびにこの生成された実行プランを使用すると思います。実行プランを生成するための興味深い点は、テーブル統計です。SQLServerは、それらを使用して最適な実行プランを生成します。変更されたSPのパラメータが生成される可能性がある場合、実行計画は役に立たず、最良の実行計画ではありません。実行時間の計算にwhitdefrenceパラメーターを使用するたびに、SPを再コンパイルする必要があると思います。また、SPの内部パラメータを使用して、SPを実行するたびにSQLServerによって自動的に実行プランを生成できます。たとえば、以下のコードを使用します。

ALTER Procedure [dbo].[usp_searchImagestest]
( 
  @CurrentPage As int=1, 
  @PageSize As int=10, 
  @searchType As int=1, 
  @Activeflag As bit=null, 
  @searchTerm as nvarchar(200), 
  @TotalRecords As int OUTPUT 
) 
As begin

Declare       
  @ICurrentPage int, 
  @IPageSize int, 
  @IsearchType int, 
  @IActiveflag bit,
  @IsearchTerm nvarchar(200), 
  @ITotalRecords int 

Set @ICurrentPage = @CurrentPage
Set @IPageSize = @PageSize
Set @IsearchType = @searchType
Set @IActiveflag = Activeflag
Set @IsearchTerm = searchTerm
Set @ITotalRecords = @TotalRecords

次に、SPパラメーターの代わりにiternalパラメーターを使用します。

于 2012-06-07T12:11:34.727 に答える
0

その部分のiKnowKungFooの解決策を変えるべきだと思います

ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
COUNT(*) OVER() AS TOTALCOUNT

ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
ROW_NUMBER() OVER (ORDER BY ImgID) AS TotalRows

したがって、2 番目の部分には逆順が含まれている必要があります。この回答記事を読むことができます(最後のものへの登録が必要です)。

個人的には、サブクエリの代わりにCTEを使用します。すべての行を CTE としてメイン セットを定義できるようにします。必要なのは、getCOUNT(*)を 1 回実行し、さらに必要なデータのページを取得することです。WHERE seq BETWEEN (@PageSize * (@CurrentPage-1)) AND (@CurrentPage * @PageSize)

もう 1 つの選択肢は、 (こちらを参照)またはアプローチ (こちらCROSS JOINを参照)の代わりにアプローチを取得できます。すべての方法をテストして、最適な方法を見つけることをお勧めします。ROW_NUMBER() OVER (<reverse sort order>)UNION

UPDATED : CTE とは、ビューとして最適化する方がはるかに優れているということです。まず、次のクエリを試すことができます

WITH MasterImagesSearch AS (
    SELECT im.ImgTitle, im.ImgID, im.ImgDate, im.ImgActive,
           im.ImgHits, asp.UserName, im.ImgUserID, id.ImgDPath,
           e.UAvatar, im.ImgRemarks
    FROM dbo.tbl_ImagesMaster AS im INNER JOIN
           dbo.aspnet_Users AS asp ON im.ImgUserID = asp.UserId INNER JOIN
           dbo.tbl_ImagesDetails AS id ON im.ImgID = id.ImgDParentID INNER JOIN
           dbo.tblUsersExtended AS e ON asp.UserId = e.UUserID
    WHERE id .ImgDDefault = 1
), GetAll AS (
    SELECT ImgID,ImgTitle,ImgDate,imgHits,UserName,uavatar
    FROM MasterImagesSearch
    WHERE FREETEXT(ImgTitle, @searchTerm)
        AND (@Activeflag IS NULL or ImgActive=@Activeflag)
), MyImages AS (
    SELECT ImgID,imgtitle,ImgDate,imghitsUserName,uavatar
        ,ROW_NUMBER() OVER (ORDER BY ImgID desc) AS RowRank
        ,ROW_NUMBER() OVER (ORDER BY ImgID) AS TotalRows
    FROM GetAll
)
SELECT ImgID,imgtitle,ImgDate,imghitsUserName,uavatar
    ,RowRank + TotalRows -1 AS Total
FROM MyImages
WHERE RowRank BETWEEN (@PageSize * (@CurrentPage-1)) AND (@CurrentPage * @PageSize)

追加の最適化は行いませんでしたがINNER JOIN、サブクエリの代わりに CTE を使用しました。

于 2012-06-06T23:31:36.793 に答える