2011-04-25 271 views
0

任何人都可以給我任何指針來優化下面的SQL查詢。我對SQL不太瞭解,但下面甚至不能有效地分頁數據,據我所知?幫助優化SQL查詢

GO 
/****** Object: StoredProcedure [dbo].[Nop_ProductLoadAllPaged] Script Date: 04/25/2011 13:26:39 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 


ALTER PROCEDURE [dbo].[Nop_ProductLoadAllPaged] 
(
    @CategoryID   int = 0, 
    @ManufacturerID  int = 0, 
    @ProductTagID  int = 0, 
    @FeaturedProducts bit = null, --0 featured only , 1 not featured only, null - load all products 
    @PriceMin   money = null, 
    @PriceMax   money = null, 
    @RelatedToProductID int = 0, 
    @Keywords   nvarchar(MAX), 
    @SearchDescriptions bit = 0, 
    @ShowHidden   bit = 0, 
    @PageIndex   int = 0, 
    @PageSize   int = 2147483644, 
    @FilteredSpecs  nvarchar(300) = null, --filter by attributes (comma-separated list). e.g. 14,15,16 
    @LanguageID   int = 0, 
    @OrderBy   int = 0, --0 position, 5 - Name, 10 - Price, 15 - creation date 
    @WarehouseCombinationID int, 
    @TotalRecords  int = null OUTPUT 
) 
AS 
BEGIN 

    --init 
    DECLARE @SearchKeywords bit 
    SET @SearchKeywords = 1 
    IF (@Keywords IS NULL OR @Keywords = N'') 
     SET @SearchKeywords = 0 

    SET @Keywords = isnull(@Keywords, '') 
    SET @Keywords = '%' + rtrim(ltrim(@Keywords)) + '%' 

    --filter by attributes 
    SET @FilteredSpecs = isnull(@FilteredSpecs, '') 
    CREATE TABLE #FilteredSpecs 
    (
     SpecificationAttributeOptionID int not null 
    ) 
    INSERT INTO #FilteredSpecs (SpecificationAttributeOptionID) 
    SELECT CAST(data as int) FROM dbo.[NOP_splitstring_to_table](@FilteredSpecs, ','); 

    DECLARE @SpecAttributesCount int  
    SELECT @SpecAttributesCount = COUNT(1) FROM #FilteredSpecs 

    --paging 
    DECLARE @PageLowerBound int 
    DECLARE @PageUpperBound int 
    DECLARE @RowsToReturn int 

    SET @RowsToReturn = @PageSize * (@PageIndex + 1)  
    SET @PageLowerBound = @PageSize * @PageIndex 
    SET @PageUpperBound = @PageLowerBound + @PageSize + 1 

    CREATE TABLE #DisplayOrderTmp 
    (
     [ID] int IDENTITY (1, 1) NOT NULL, 
     [ProductID] int NOT NULL 
    ) 

    INSERT INTO #DisplayOrderTmp ([ProductID]) 
    SELECT p.ProductID 
    FROM Nop_Product p with (NOLOCK) 
    LEFT OUTER JOIN Nop_Product_Category_Mapping pcm with (NOLOCK) ON p.ProductID=pcm.ProductID 
    LEFT OUTER JOIN Nop_Product_Manufacturer_Mapping pmm with (NOLOCK) ON p.ProductID=pmm.ProductID 
    LEFT OUTER JOIN Nop_ProductTag_Product_Mapping ptpm with (NOLOCK) ON p.ProductID=ptpm.ProductID 
    LEFT OUTER JOIN Nop_RelatedProduct rp with (NOLOCK) ON p.ProductID=rp.ProductID2 
    LEFT OUTER JOIN Nop_ProductVariant pv with (NOLOCK) ON p.ProductID = pv.ProductID 
    LEFT OUTER JOIN Nop_ProductVariant_Warehouse_Mapping wpv with (NOLOCK) ON pv.ProductVariantID = wpv.ProductVariantID 
    LEFT OUTER JOIN Nop_ProductVariantLocalized pvl with (NOLOCK) ON pv.ProductVariantID = pvl.ProductVariantID AND pvl.LanguageID = @LanguageID 
    LEFT OUTER JOIN Nop_ProductLocalized pl with (NOLOCK) ON p.ProductID = pl.ProductID AND pl.LanguageID = @LanguageID 
    WHERE 
     (
      (
       @CategoryID IS NULL OR @CategoryID=0 
       OR ([email protected] AND (@FeaturedProducts IS NULL OR [email protected])) 
      ) 
     AND (
       @ManufacturerID IS NULL OR @ManufacturerID=0 
       OR ([email protected] AND (@FeaturedProducts IS NULL OR [email protected])) 
      ) 
     AND (
       @ProductTagID IS NULL OR @ProductTagID=0 
       OR [email protected] 
      ) 
     AND (
       @RelatedToProductID IS NULL OR @RelatedToProductID=0 
       OR [email protected] 
      ) 
     AND (
       @ShowHidden = 1 OR p.Published = 1 
      ) 
     AND 
      (
       p.Deleted=0 AND wpv.Deleted=0 
      ) 
     AND 
      (
       @ShowHidden = 1 OR pv.Published = 1 
      ) 
     AND (
       @ShowHidden = 1 OR wpv.Published = 1 
      ) 
     AND 
      (
       @ShowHidden = 1 OR pv.Deleted = 0 
      ) 
     AND (
       @PriceMin IS NULL OR @PriceMin=0 
       OR wpv.Price > @PriceMin  
      ) 
     AND (
       @PriceMax IS NULL OR @PriceMax=2147483644 -- max value 
       OR wpv.Price < @PriceMax 
      ) 
     AND (
       wpv.WarehouseID IN (select WarehouseID from Nop_WarehouseCombination where UserWarehouseCombinationID = @WarehouseCombinationID) 
      ) 
     AND (
       @SearchKeywords = 0 or 
       (
        -- search standard content 
        patindex(@Keywords, p.name) > 0 
        or patindex(@Keywords, pv.name) > 0 
        or patindex(@Keywords, pv.sku) > 0 
        or (@SearchDescriptions = 1 and patindex(@Keywords, p.ShortDescription) > 0) 
        or (@SearchDescriptions = 1 and patindex(@Keywords, p.FullDescription) > 0) 
        or (@SearchDescriptions = 1 and patindex(@Keywords, pv.Description) > 0)      
        -- search language content 
        or patindex(@Keywords, pl.name) > 0 
        or patindex(@Keywords, pvl.name) > 0 
        or (@SearchDescriptions = 1 and patindex(@Keywords, pl.ShortDescription) > 0) 
        or (@SearchDescriptions = 1 and patindex(@Keywords, pl.FullDescription) > 0) 
        or (@SearchDescriptions = 1 and patindex(@Keywords, pvl.Description) > 0) 
       ) 
      ) 
     AND 
      (
       @ShowHidden = 1 
       OR 
       (getutcdate() between isnull(pv.AvailableStartDateTime, '1/1/1900') and isnull(pv.AvailableEndDateTime, '1/1/2999')) 
      ) 
     AND 
      (
       --filter by specs 
       @SpecAttributesCount = 0 
       OR 
       (
        NOT EXISTS(
         SELECT 1 
         FROM #FilteredSpecs [fs] 
         WHERE [fs].SpecificationAttributeOptionID NOT IN (
          SELECT psam.SpecificationAttributeOptionID 
          FROM dbo.Nop_Product_SpecificationAttribute_Mapping psam 
          WHERE psam.AllowFiltering = 1 AND psam.ProductID = p.ProductID 
          ) 
         ) 

       ) 
      ) 
     ) 
    ORDER BY 
     CASE WHEN @OrderBy = 0 AND @CategoryID IS NOT NULL AND @CategoryID > 0 
     THEN pcm.DisplayOrder END ASC, 
     CASE WHEN @OrderBy = 0 AND @ManufacturerID IS NOT NULL AND @ManufacturerID > 0 
     THEN pmm.DisplayOrder END ASC, 
     CASE WHEN @OrderBy = 0 AND @RelatedToProductID IS NOT NULL AND @RelatedToProductID > 0 
     THEN rp.DisplayOrder END ASC, 
     CASE WHEN @OrderBy = 0 
     THEN p.[Name] END ASC, 
     CASE WHEN @OrderBy = 5 
     THEN dbo.NOP_getnotnullnotempty(pl.[Name],p.[Name]) END ASC, 
     CASE WHEN @OrderBy = 10 
     THEN wpv.Price END ASC, 
     CASE WHEN @OrderBy = 15 
     THEN wpv.Price END DESC, 
     CASE WHEN @OrderBy = 20 
     THEN wpv.Price END DESC, 
     CASE WHEN @OrderBy = 25 
     THEN wpv.UnitPrice END ASC 

    DROP TABLE #FilteredSpecs 

    CREATE TABLE #PageIndex 
    (
     [IndexID] int IDENTITY (1, 1) NOT NULL, 
     [ProductID] int NOT NULL 
    ) 
    INSERT INTO #PageIndex ([ProductID]) 
    SELECT ProductID 
    FROM #DisplayOrderTmp with (NOLOCK) 
    GROUP BY ProductID 
    ORDER BY min([ID]) 

    --total records 
    SET @TotalRecords = @@rowcount 
    SET ROWCOUNT @RowsToReturn 

    DROP TABLE #DisplayOrderTmp 

    --return 
    SELECT 
     p.ProductId, 
     p.Name, 
     p.ShortDescription, 
     p.FullDescription, 
     p.AdminComment, 
     p.TemplateId, 
     p.ShowOnHomePage, 
     p.MetaKeywords, 
     p.MetaDescription, 
     p.MetaTitle, 
     p.SEName, 
     p.AllowCustomerReviews, 
     p.AllowCustomerRatings, 
     p.RatingSum, 
     p.TotalRatingVotes, 
     p.Published, 
     p.Deleted, 
     p.CreatedOn, 
     p.UpdatedOn 
    FROM 
     #PageIndex [pi] 
     INNER JOIN Nop_Product p with (NOLOCK) on p.ProductID = [pi].ProductID 
    WHERE 
     [pi].IndexID > @PageLowerBound AND 
     [pi].IndexID < @PageUpperBound 
    ORDER BY 
     IndexID 

    SET ROWCOUNT 0 

    DROP TABLE #PageIndex 
END 
+1

那是一隻野獸......! – clamchoda 2011-04-25 18:24:13

+0

您似乎正在使用SQL Server 2000分頁技術[2008年可能會有更好的方法](http://www.sqlservercentral.com/articles/paging/69892/)。你也有一堆可能導致問題的不可判斷的謂詞[本文可能有幫助](http://www.sommarskog.se/dyn-search-2008.html) – 2011-04-25 18:28:07

+0

@Marc,我想我已經更新了 @Martin,謝謝您的關注。 – izip 2011-04-25 18:31:07

回答

0

儘管我討厭自己這樣做,但我認爲您可能需要將其分解爲一些單獨的IF塊。

它看起來像我加入了許多不一定需要基於輸入參數的表。如果你關心速度,這是一些不必要的開銷。您可以通過創建只會加入所需表格的塊來簡化流程。它會讓你的SP變得更加混亂,並且我建議你可以創建一些函數或者其他單獨的SP來在你的case塊中調用。

如果您希望將事情保持原樣,我們需要查看實際的執行計劃,以掌握可能發生的事情。沒有這個,這只是一個猜測。

0

嘗試使用SQL Server的「顯示估計執行計劃」選項或「顯示實際執行計劃」來查看查詢的哪些部分佔用最多時間。這樣做也可能會爲您提供額外索引的建議。