Optimizing sql query in nopcommerce

I am optimizing a sql query and I welcome advice on how to improve this query. It is part of nopcommerce's free solution to download products in categories. At this time, it takes about 8-9 seconds to load the page, we can bring this to 3-4 seconds if we can.

Here is a request, I welcome every piece of advice on how I can improve this:

ALTER PROCEDURE [dbo].[Nop_ProductLoadForCategory]
(
    @CategoryID         int = 0,
    @manufacturerId     int = 0,
    @PageIndex          int = 0, 
    @PageSize           int = 2147483644,   
    @TotalRecords       int = null OUTPUT,
    @VehiclesYear       varchar(4) = null,
    @VehiclesMake       varchar(20) = null,
    @VehiclesModel      varchar(50) =null,
    @VehiclesSubmodel       varchar(50) =null,
    @Universal bit = 1
)
AS
SET NOCOUNT ON
BEGIN

    --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
    )


    if isnull(@manufacturerId, 0) = 0
        if @Universal = 1
            INSERT INTO #DisplayOrderTmp ([ProductID])
            select a.ProductID from (
                SELECT TOP 100 PERCENT 
                    row_number() over(order by pv.DisplayOrder) as ID,
                    p.ProductID
                FROM dbo.Nop_Product p with (NOLOCK) 
                INNER JOIN Nop_Product_Category_Mapping pcm with (NOLOCK) ON p.ProductID=pcm.ProductID
                LEFT OUTER JOIN Nop_ProductVariant pv with (NOLOCK) ON pv.ProductID = p.ProductId
                left outer join WC_ProductVehicleApplications pva with (NOLOCK) on pva.ProductID=p.ProductId
                left outer join [WC_Vehicles] v with (NOLOCK) on pva.VehicleID = v.VehicleID
                WHERE 
                   (pcm.CategoryID=@CategoryID)
                    AND (p.Published = 1)
                    AND (p.Deleted=0)       
                    and (((@VehiclesYear between [YEAR] and YearEnd or @VehiclesYear is null)
                    and ([Make] = @VehiclesMake or @VehiclesMake is null)
                    and ([Model] = @VehiclesModel or @VehiclesModel is null)            
                    and ([SubModel] = @VehiclesSubmodel or @VehiclesSubmodel is null))
                    or p.IsUniversal = 1)
                ) a 
                GROUP BY 
                ProductID
            ORDER BY 
                min([ID])

        else
            INSERT INTO #DisplayOrderTmp ([ProductID])
            select a.ProductID from (
                SELECT TOP 100 PERCENT 
                    row_number() over(order by pv.DisplayOrder) as ID,
                    p.ProductID
                FROM dbo.Nop_Product p with (NOLOCK) 
                INNER JOIN Nop_Product_Category_Mapping pcm with (NOLOCK) ON p.ProductID=pcm.ProductID
                LEFT OUTER JOIN Nop_ProductVariant pv with (NOLOCK) ON pv.ProductID = p.ProductId
                left outer join WC_ProductVehicleApplications pva with (NOLOCK) on pva.ProductID=p.ProductId
                left outer join [WC_Vehicles] v with (NOLOCK) on pva.VehicleID = v.VehicleID
                WHERE 
                   (pcm.CategoryID=@CategoryID)
                    AND (p.Published = 1)
                    AND (p.Deleted=0)       
                    and (((@VehiclesYear between [YEAR] and YearEnd or @VehiclesYear is null)
                    and ([Make] = @VehiclesMake or @VehiclesMake is null)
                    and ([Model] = @VehiclesModel or @VehiclesModel is null)            
                    and ([SubModel] = @VehiclesSubmodel or @VehiclesSubmodel is null))
                    and p.IsUniversal <> 1)
                ) a 
                GROUP BY 
                ProductID
            ORDER BY 
                min([ID])
    else            
            INSERT INTO #DisplayOrderTmp ([ProductID])
            select a.ProductID from (
                SELECT TOP 100 PERCENT 
                    row_number() over(order by pv.DisplayOrder) as ID,
                    p.ProductID
                FROM dbo.Nop_Product p with (NOLOCK) 
                INNER JOIN Nop_Product_Category_Mapping pcm with (NOLOCK) ON p.ProductID=pcm.ProductID
                LEFT OUTER JOIN Nop_ProductVariant pv with (NOLOCK) ON pv.ProductID = p.ProductId
                left outer join WC_ProductVehicleApplications pva with (NOLOCK) on pva.ProductID=p.ProductId
                left outer join [WC_Vehicles] v with (NOLOCK) on pva.VehicleID = v.VehicleID
                WHERE 
                   (pcm.CategoryID=@CategoryID)
                    AND (p.Published = 1)
                    AND (p.Deleted=0)       
                    and (((@VehiclesYear between [YEAR] and YearEnd or @VehiclesYear is null)
                    and ([Make] = @VehiclesMake or @VehiclesMake is null)
                    and ([Model] = @VehiclesModel or @VehiclesModel is null)            
                    and ([SubModel] = @VehiclesSubmodel or @VehiclesSubmodel is null))
                    or p.IsUniversal = 1)
                ) a 
                GROUP BY 
                ProductID
            ORDER BY 
                min([ID])


    --CREATE UNIQUE NONCLUSTERED INDEX IX_1 on #DisplayOrderTmp ([ID], [ProductID])

    --CREATE TABLE #PageIndex 
    --(
    --  [IndexID] int IDENTITY (1, 1) NOT NULL,
    --  [ProductID] int NOT NULL
    --)

    --INSERT INTO #PageIndex ([ProductID])


    --SELECT TOP 100 PERCENT 
    --  Row_Number() Over(Order By min([ID])) as RowNum, ProductID
    --FROM #DisplayOrderTmp with (NOLOCK)
    --GROUP BY ProductID
    --ORDER BY min([ID])

    --select ProductID
    --FROM #DisplayOrderTmp with (NOLOCK)
    --GROUP BY ProductID

    --SELECT 
    --  ProductID
    --FROM 
    --  #DisplayOrderTmp with (NOLOCK)
    --GROUP BY 
    --  ProductID
    --ORDER BY 
    --  min([ID])

    --select ProductID from #DisplayOrderTmp with (NOLOCK) --order by min([ID])


    --CREATE UNIQUE NONCLUSTERED INDEX IX_2 on #PageIndex ([IndexID], [ProductID])

    --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,
        p.[IsUniversal],
        p.FullDescriptionSave
    FROM
        --(SELECT TOP 100 PERCENT 
        --  Row_Number() Over(Order By min([ID])) as RowNum, ProductID
        --FROM #DisplayOrderTmp with (NOLOCK)
        --GROUP BY ProductID
        --ORDER BY min([ID])
        --) [pi]
        --inner join 
        #DisplayOrderTmp [pi] 
        --on dot.ProductID = [pi].ProductID
        INNER JOIN Nop_Product p with (NOLOCK) on p.ProductID = [pi].ProductID 
        INNER JOIN Nop_Product_Category_Mapping pcm with (NOLOCK) ON p.ProductID=pcm.ProductID
    WHERE
        --[pi].IndexID > @PageLowerBound AND 
        --[pi].IndexID < @PageUpperBound
        [pi].ID > @PageLowerBound AND 
        [pi].ID < @PageUpperBound
    ORDER BY
        [pi].ID 

    SET ROWCOUNT 0


    DROP TABLE #DisplayOrderTmp
END

      

Thanks in advance, Laziale

+3


source to share


2 answers


OK, so you have 45,000 views and 2,000 CPUs. These numbers are generally high and the query can be optimized. The Profiler screenshot is cropped. How many rows are returned?

Can you change your question and post the execution plan?



Note, however, that SQL only considers the query to take 651 milliseconds . If you see a delay of 8-9 seconds, the problem is most likely in the client code. This is the first place I would spend optimizing time (unless your query is returning row gradients that are discarded on the client).

0


source


NopCommerce is deadly slow. If you have more than a few thousand products, you already have problems. You will need to do heavy caching for the home page, Home category, and product listing page.

We have the same problem, after implementing the cache, we reduce the load time to 1.5-2 seconds from 8-10 seconds. We tested Nop Commerce 2.2 / 2.3 / 2.4 / 2.5 under load, but frankly, the performance improvement is very marginal in 2.5 and you should look at aggressive caching to improve site performance. Without the cache, your site will see huge problems with only a few hundred concurrent requests.

EBarr is right, not SQL which is slow, the application is also very slow if you profile it with any good profiler. Please note that NopCommerce already has a mini profiler that you can activate from the admin side.



Update October 30, 2015

A number of new versions of nopCommerce have been released since this answer was originally written and has improved significantly in terms of out-of-the-box performance.

In addition, we have integrated nopCommerce with Apache Solr, so nopCommerce can be used for huge sites with millions of products and visitors, with a faster navigation directory page, faster facets, and an improved and faster drill search. The integration is done as a standard plugin popular as nopAccelerate http://www.nopaccelerate.com/

+5


source







All Articles