2012-03-27 12 views
3

Ich bin Sql Abfrage optimieren und ich begrüße Ratschläge, wie diese Abfrage zu verbessern. Es ist Teil der NOPCommerce Open Source-Lösung zum Laden von Produkten in Kategorien. Zu diesem Zeitpunkt dauert es 8-9 Sekunden, um die Seite zu laden, wir wollen das auf 3-4 Sekunden bringen, wenn wir können. HierOptimierung SQL-Abfrage in NOPCommerce

ist die Abfrage, ich jeden Rat bin freundlich, wie ich das verbessern können:

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 
        ([email protected]) 
        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 
        ([email protected]) 
        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 
        ([email protected]) 
        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 

Vielen Dank im Voraus, Laziale

+0

beliebt ist Kannst du den Ausführungsplan posten? Die Indizes für die Tabellen, die an der Abfrage beteiligt sind? Was bekommen Sie in SQL Profiler für Lese-, Schreib-, CPU- und Dauer? – EBarr

+0

@EBarr danke für deine Antwort. Hier ist die sql Profiler Daten: http://gyazo.com/3a67497c0e07bca17a04d19a52bbf2f6. Wie kann ich nach Indizes für die Tabellen suchen, die in der Abfrage enthalten sind? Danke – Laziale

+0

FYI ..editing Ihren Beitrag, um Updates zu Kommentaren hinzuzufügen, wird empfohlen. Das Einbetten Ihres Bilds in die Post wird eher als gute Form betrachtet. – EBarr

Antwort

0

OK, also Sie haben 45.000 liest und 2000 CPU. Diese Zahlen sind im Allgemeinen hoch und die Abfrage kann wahrscheinlich optimiert werden. Der Profiler-Screenshot ist abgeschnitten. Wie viele Zeilen werden zurückgegeben?

Können Sie Ihre Frage bearbeiten & den Ausführungsplan veröffentlichen?

Beachten Sie jedoch, dass SQL nur annimmt, dass die Abfrage 651 Millisekunden dauerte. Wenn Sie eine Verzögerung von 8-9 Sekunden sehen, liegt das Problem wahrscheinlich im Clientcode. Das ist der erste Ort, an dem ich die Zeit optimieren würde (es sei denn, Ihre Abfrage gibt die Anzahl der Zeilen zurück, die im Client verworfen werden).

5

NopCommerce ist tödlich langsam. Wenn Sie mehr als ein paar tausend Produkte haben, sind Sie bereits in Schwierigkeiten. Sie müssen ein schweres Caching für die Home Page, Kategorie Home & Product Listing Seite vornehmen.

Wir haben das gleiche Problem, nach der Implementierung eines Caches senken wir die Ladezeit auf 1,5-2 Sekunden von den 8-10 Sekunden. Wir haben Nop Commerce 2.2/2.3/2.4/2.5 getestet, aber ehrlich gesagt ist die Leistungsverbesserung in 2.5 sehr gering und Sie sollten sich das aggressive Caching ansehen, um die Leistung der Website zu verbessern. Ohne Cache werden auf Ihrer Website nur wenige hundert gleichzeitige Anfragen angezeigt.

EBarr ist richtig, es ist nicht die SQL, die langsam ist, die Anwendung ist auch sehr langsam, wenn Sie es mit einem guten Profiler profilieren. Beachten Sie, dass NopCommerce bereits einen Mini-Profiler implementiert hat, den Sie von der Admin-Seite aus aktivieren können.

-Update 30. Oktober 2015

Zahlen von neueren Versionen von nopCommerce wurde veröffentlicht, da diese Antwort ursprünglich geschrieben wurde, und es hat sich im Hinblick auf die aus der Box-Performance deutlich verbessert.

Außerdem haben wir nopCommerce mit Apache Solr integriert, so dass nopCommerce für riesige Websites mit Millionen von Produkten und Besuchern verwendet werden kann, mit schnelleren Katalognavigationsseiten, schnelleren Facetten und verbesserter und schnellerer Drilldownsuche. Die Integration erfolgt als Standard-Plugin, das als nopAccelerate http://www.nopaccelerate.com/

+1

Ich stimme Krunal darin zu, dass es nicht die SQL-Abfrage ist, die langsam ist.Es ist die Verwendung von Entity Framework und die extrem langsame Implementierung der DAL in NopCommerce. Einige Seiten übernehmen 40 separate Datenbankabfragen zum Laden. Das Optimieren nur einer Prozedur wird dir nicht wirklich helfen. Ich denke 2,65 ist merklich schneller als vorherige Versionen (fühlt sich aber immer noch nicht schnell an). Ich war ziemlich genervt, als ich sah, wie die Entwickler auf Entity Framework herabstuften, was das langsamste ORM ist, das mit einer erheblichen Marge verfügbar ist (8-10 mal langsamer als beispielsweise nHiberate). – NickG