Sql server 返回找到的总记录的搜索存储过程非常慢

Sql server 返回找到的总记录的搜索存储过程非常慢,sql-server,sql-server-2008,full-text-search,Sql Server,Sql Server 2008,Full Text Search,我有下面的存储过程,它在不返回总记录的情况下工作得很好,但是当我在单独的查询中返回总记录时,它变得非常慢 是否有其他方法可以更快地返回总记录 观点是 SELECT dbo.tbl_ImagesMaster.ImgTitle, dbo.tbl_ImagesMaster.ImgID, dbo.tbl_ImagesMaster.ImgDate, dbo.tbl_ImagesMaster.ImgActive, dbo.tbl_ImagesMaster

我有下面的存储过程,它在不返回总记录的情况下工作得很好,但是当我在单独的查询中返回总记录时,它变得非常慢

是否有其他方法可以更快地返回总记录

观点是

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秒的时间


表中的总行数为100000行,第二选择再次运行搜索。只需更改页面搜索:

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
线路

算作总数


在分页发生之前,为您提供内部选择的计数。

我认为应该更改iKnowKungFoo部分的解决方案

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

所以第二部分应该包含相反的顺序。您可以阅读,其中一个需要注册到最后一个

无论如何,我个人都会用它来代替子查询。通过这种方式,您可以将所有行定义为CTE的主集合。您需要的只是执行一个get COUNT*,并使用@PageSize*@CurrentPage-1和@CurrentPage*@PageSize之间的WHERE seq额外获取所需的数据页

另一种选择是交叉连接方法,而不是see上的行数或联合方法see。我建议你测试所有的方法,找到最适合你的方法

更新:我对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)

我没有做任何额外的优化,但我使用了带内部联接的CTE而不是子查询。

我认为,当您使用存储过程获取带参数的查询结果时,SQL Server会为此SP生成执行计划,并在以后调用SP时为每个SP使用生成的执行计划。生成执行计划的有趣之处在于表统计信息,即SQL Server,使用它们生成最佳执行计划。如果SP的参数发生更改,则可能会生成执行计划无效且不是最佳执行计划。我认为您必须在每次使用whit-defrence参数计算执行时间时重新编译SP。此外,您还可以使用SP中的内部参数,在每次运行SP时由SQL Server自动生成执行计划。例如,请使用以下代码:

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

然后使用iternal参数而不是SP参数。

在SQL Server中,我在针对视图创建复杂查询时遇到了很多问题。。。尤其是当该视图由其他视图组成时,这些视图通常可以由其他视图组成。我严肃的建议是:在存储过程中,或者在任何不面向最终用户的场合,如果可以的话,直接与表对抗。@Jeremy:我试图直接访问表,但查询运行得太快,它在不到1秒的时间内返回了计数结果。我尝试了您的解决方案,但仍然花费了相同的时间,问题出在计数上。我在数据库中有100000条记录,没有计数的查询只需不到1秒您是否删除了第二个查询?select@TotalRecords查询?是的,我删除了它,但是当我不通过视图直接访问表时,即使有第二个查询,结果也会在不到一秒钟的时间内返回视图在上面,但即使没有视图,count*over as totalcount比使用另一个查询获取count@Moe9977:在一个需要能够读取的寄存器中,描述了count*over缓慢的原因以及如何改进它。我试图在我的回答中简单地描述同样的情况。您的速度比iKnowKungFoo快,但当我将您的与查询2进行比较时,探查器的读取毫秒数更少,CPU低得多,您给出的是521毫秒,上面单独的查询2给出的是61毫秒MS@Moe9977:你能准确地写出你测试过的查询吗。我写过关于树版本的文章:ImgID将ROW_编号作为TotalRows,CTE一个有交叉连接,另一个有并集。在你的问题中,你写了一个问题中的第2个问题不到1秒。现在你写一些给出61毫秒的查询。你怎么能理解这一点呢?ImgID作为TotalRows的订单上的行数为521毫秒,上面的Query2为61毫秒ms@Moe9977:您应该发布您使用的完整查询。我在回答中包含了我之前描述的更详细的问题。我希望我没有打字错误。你的这一个和你的结果相比较。如果需要的话,你可以根据我写的参考文献使用并集和交叉连接。您还可以尝试使用提示选项“重新编译”,并使用不同的输入数据进行测试。有关更多详细信息,请参阅。我尝试了Query2和您发布的查询,结果如下:Query2CPU=63ms,读取:2635,,,您的查询CPU=1593,读取229658。然而,我试图通过ImgID将ROW_NUMBER作为TotalRows删除,并使用这个select@TotalRecords=select COUNT*From vw_masterimagesearch,其中FREETEXT*、@searchTerm和@Activeflag为NULL或ImgActive=@Activeflag读取配置文件
已更改为CPU=375次读取=5078@lotfi,我将测试我发布的结果shortly@Lotfi,使用内部参数仅影响CPU时间,如下所示:CPU时间为46MS,而不是62,但总读取数相同2635,因此使用内部参数时,查询执行速度更快。
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