2

I have to rewrite a huge SQL query that gets data from around 10 tables using Entity Framework and Linq. In short, the query gets a list of products from the main table, then fetches other information like download count, sales count, author, etc. from other tables for those products.

What I decided to do was break it down into parts so that its easy for others to understand and edit.

First, I get the list of products. Then, I get a list data for the other columns and I merge everything together in the last step.

 var mainTableQuery = from p in context.mains
                      select new
                      {
                         p.ProductID,
                         p.title,
                          p.department_id,
                         p.TotalInStock                                        
                       };
 //Getting the top author by priority for every product ID
 var authorLinkQuery= from authorLink in context.AuthorLinks
                      group authorLink by authorLink.ProductID
                         into groups
                      select groups.OrderBy(p=>p.Priority).FirstOrDefault();

 // Link productIDs with primary author names
 var authorsFinalQuery = from author in context.Authors
                         join authorLink in authorLinkQuery
                         on author.AuthorID equals authorLink.AuthorID
                         select new
                         {
                             authorLink.ProductID,
                             Name = (String.IsNullOrEmpty(author.Company) ? author.FirstName + " " + author.LastName : author.Company)
                         };
 var finalQuery = from main in mainTableQuery
                             join author in authorsFinalQuery
                             on main.ProductID equals author.ProductID                                 
                             select new
                             {
                                 main,
                                 author.Name
                             };

This final query gets the correct data but it takes around 30s. The original SQL server query took only 6s. The problem is that the SQL server query that is generated by entity framework is very inefficient. Is there a way to optimize this?

EDIT: The complete stored procedure that I'm trying to replace is:

CREATE PROCEDURE [dbo].[usp_AllProducts] (@ProgramAreaID int,
@CustomDateStart datetime,
@CustomDateEnd datetime,
@ShowNLA nvarchar(50))
AS
BEGIN 
  SET NOCOUNT ON;
  IF @ProgramAreaID = 1000
  BEGIN
    SELECT TOP (100) PERCENT
      BaseInventory.ProductID,
      BaseInventory.ReferenceNumber,
      BaseInventory.Title,
      BaseInventory.StoredBy,
      BaseInventory.TotalInStock,
      BaseInventory.StockAtEDC,
      BaseInventory.Cost,
      BaseInventory.RetailPrice,
      BaseInventory.PubDate,
      BaseInventory.DepartmentCode,
      vwAuthor.PrimaryAuthor,
      ISNULL(Sales30Days.QuantitySold, 0) AS Last30Days,
      ISNULL(SalesPastYear.QuantitySold, 0) AS Last365Days,
      ISNULL(CustomRangeSales.QuantitySold, 0) AS CustomRange,
      ISNULL(SalesPastYear.ZeroStock, '12/31/9999') AS ZeroStock,
      ISNULL(SalesPastYear.ZeroStockFullDate, CONVERT(datetime, '12/31/9999', 102)) AS ZeroStockFullDate,
      BaseInventory.FullPubDate,
      BaseInventory.ProgramArea,
      BaseInventory.Spaces,
      BaseInventory.DigitalFileExists,
      BaseInventory.DownloadCount,
      BaseInventory.DownloadCountCustom,
      ISNULL(SalesPastYear.SpacesSold, 0.000) AS SpacesSold,
      BaseInventory.DateReceived,
      BaseInventory.ProductWeight,
      BaseInventory.NumberOfPages,
      BaseInventory.DigitalFileCount,
      BaseInventory.ActiveDigitalFileCount
    FROM (SELECT TOP (100) PERCENT
      m.ProductWeight,
      m.ProductID,
      m.reference_number AS ReferenceNumber,
      m.title AS Title,
      MAX(sb.StoredBy) AS StoredBy,
      m.TotalInStock,
      m.edc_copies AS StockAtEDC,
      m.pub_cost AS Cost,
      m.RetailPrice,
      m.pub_date AS PubDate,
      d.department_code AS DepartmentCode,
      m.department_id AS DepartmentId,
      dg.department_group AS ProgramArea,
      m.FullPubDate,
      ISNULL(Boxes.Spaces, CASE
        WHEN sb.StoredBy = 'WWW' THEN 0
        ELSE 1
      END) AS Spaces,
      CASE
        WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
        ELSE 'Active'
      END AS DigitalFileExists,
      ISNULL(DLs.DownloadCount, 0) AS DownloadCount,
      ISNULL(DLsCustom.DownloadCountCustom, 0) AS DownloadCountCustom,
      MAX(history.DateReceived) AS DateReceived,
      ISNULL(m.number_of_pages, 'N/A') AS NumberOfPages,
      (SELECT
        COUNT(*)
      FROM tblDigitalMedia tD
      WHERE tD.ProductID = m.ProductID)
      AS DigitalFileCount,
      (SELECT
        COUNT(*)
      FROM tblDigitalMedia tD
      WHERE tD.ProductID = m.ProductID
      AND tD.Active = 1)
      AS ActiveDigitalFileCount
    FROM dbo.main m
    INNER JOIN dbo.departments d
      ON m.department_id = d.department_id
    INNER JOIN dbo.department_groups dg
      ON d.department_group_id = dg.department_group_id

    /* InventoryTemp should be called InventoryByLocation */
    LEFT OUTER JOIN (SELECT
      m1.ProductID,
      SUM(ISNULL(it.NumberOfBoxes, 0)) + 1 AS Spaces
    FROM dbo.main AS m1
    INNER JOIN dbo.InventoryTemp AS it
      ON m1.ProductID = it.ProductID
    GROUP BY m1.ProductID) AS Boxes
      ON m.ProductID = Boxes.ProductID

    /* JobsTemp should be called JobHistory */
    LEFT OUTER JOIN dbo.JobsTemp history
      ON m.ProductID = history.ProductID

    LEFT OUTER JOIN (
    /* If dates are null then fetch for previous year. */
    SELECT TOP (100) PERCENT
      dm1.ProductID,
      COUNT(dl1.TimeStamp) AS DownloadCountCustom
    FROM dbo.tblDigitalMedia AS dm1
    LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl1
      ON dm1.FileID = dl1.FileID
    WHERE ((@CustomDateStart IS NOT NULL)
    AND (dl1.TimeStamp >= @CustomDateStart)
    AND (dl1.TimeStamp <= @CustomDateEnd))
    OR ((@CustomDateStart IS NULL)
    AND (dl1.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()))
    GROUP BY dm1.ProductID) AS DLsCustom
      ON m.ProductID = DLsCustom.ProductID
    LEFT OUTER JOIN (
    /* If dates are null then fetch for previous year. */
    SELECT TOP (100) PERCENT
      dm2.ProductID,
      COUNT(dl2.TimeStamp) AS DownloadCount
    FROM dbo.tblDigitalMedia AS dm2
    LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl2
      ON dm2.FileID = dl2.FileID
    WHERE dl2.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()
    GROUP BY dm2.ProductID) AS DLs
      ON m.ProductID = DLs.ProductID

    LEFT OUTER JOIN dbo.tblDigitalMedia AS dm
      ON m.ProductID = dm.ProductID

    /* InventoryTemp should be called InventoryByLocation */
    LEFT OUTER JOIN dbo.InventoryTemp it2
      ON m.ProductID = it2.ProductID

    INNER JOIN dbo.StoredBy sb
      ON m.StoredByID = sb.StoredByID
    WHERE (m.edc_isle LIKE N'Aisle' + N'%'
    OR m.edc_isle = N'Digital Media'
    OR m.edc_isle = N'Duplicator')
    AND NOT (d.department_id BETWEEN 995 AND 999)

    GROUP BY m.ProductWeight,
             m.ProductID,
             m.reference_number,
             m.title,
             m.TotalInStock,
             dg.department_group_id,
             m.pub_date,
             m.department_id,
             d.department_code,
             m.pub_cost,
             m.RetailPrice,
             m.FullPubDate,
             m.edc_isle,
             sb.StoredBy,
             dg.department_group,
             CASE
               WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
               ELSE 'Active'
             END,
             ISNULL(DLs.DownloadCount, 0),
             ISNULL(DLsCustom.DownloadCountCustom, 0),
             ISNULL(Boxes.Spaces, CASE
               WHEN sb.StoredBy = 'WWW' THEN 0
               ELSE 1
             END),
             m.edc_copies,
             ISNULL(m.number_of_pages, 'N/A')
    HAVING (NOT (MAX(sb.StoredBy) = @ShowNLA))
    ORDER BY m.FullPubDate) AS BaseInventory /* ***** Table A ***** */

    LEFT OUTER JOIN (SELECT
      dbo.shopping_cart.ProductID,
      SUM(dbo.shopping_cart.quantity) AS QuantitySold
    FROM dbo.orders
    INNER JOIN dbo.shopping_cart
      ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
    WHERE dbo.orders.OrderTimeStamp >= DATEADD(DAY, -30, GETDATE())
    AND dbo.orders.OrderTimeStamp < GETDATE()
    AND dbo.shopping_cart.ProductID IS NOT NULL
    GROUP BY dbo.shopping_cart.ProductID) AS Sales30Days  /* ***** Table B ***** */
      ON BaseInventory.ProductID = Sales30Days.ProductID
    LEFT OUTER JOIN (SELECT
      dbo.shopping_cart.ProductID,
      SUM(dbo.shopping_cart.quantity) AS QuantitySold
    FROM dbo.orders
    INNER JOIN dbo.shopping_cart
      ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
    WHERE @CustomDateStart IS NOT NULL
    AND dbo.orders.OrderTimeStamp >= @CustomDateStart
    AND dbo.orders.OrderTimeStamp <= @CustomDateEnd
    AND dbo.shopping_cart.ProductID IS NOT NULL
    GROUP BY dbo.shopping_cart.ProductID) AS CustomRangeSales /* ***** CustomRangeSales ***** */
      ON BaseInventory.ProductID = CustomRangeSales.ProductID

    LEFT OUTER JOIN (SELECT TOP (100) PERCENT
      cart3.ProductID,
      SUM(cart3.quantity) AS QuantitySold,
      m3.TotalInStock,
      CASE
        WHEN
          CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
        ELSE CONVERT(varchar, DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE()), 101)
      END AS ZeroStock,
      CASE
        WHEN
          CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
        ELSE DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE())
      END AS ZeroStockFullDate,
      CONVERT(decimal(18, 3), SUM(cart3.quantity) / ISNULL(CONVERT(decimal(18, 2), AvgInventory.NumberPerBox), SUM(cart3.quantity) + m3.TotalInStock)) AS SpacesSold,
      AvgInventory.NumberPerBox
    FROM dbo.orders AS o1
    INNER JOIN dbo.shopping_cart AS cart3
      ON o1.receiving_number = cart3.receiving_number
    INNER JOIN dbo.main AS m3
      ON cart3.ProductID = m3.ProductID
    LEFT OUTER JOIN (SELECT TOP (100) PERCENT
      ProductID,
      AVG(NumberPerBox) AS NumberPerBox
    FROM dbo.InventoryTemp
    GROUP BY ProductID
    ORDER BY ProductID) AS AvgInventory
      ON m3.ProductID = AvgInventory.ProductID
    WHERE (o1.OrderTimeStamp BETWEEN DATEADD(DAY, -365, GETDATE()) AND GETDATE() + 1)
    GROUP BY cart3.ProductID,
             m3.TotalInStock,
             AvgInventory.NumberPerBox
    HAVING (NOT (cart3.ProductID IS NULL))) AS SalesPastYear /* ***** Table C ***** */
      ON BaseInventory.ProductID = SalesPastYear.ProductID

    LEFT OUTER JOIN (SELECT
      ProductID,
      CASE
        WHEN ((Auth.Company = '') OR
          (Auth.Company IS NULL)) THEN LTRIM(ISNULL(Auth.FirstName, '') + ' ' + ISNULL(Auth.LastName, ''))
        ELSE Auth.Company
      END AS PrimaryAuthor
    FROM dbo.Author AS Auth
    INNER JOIN (SELECT
      AUTHLINK.AuthorID,
      AUTHLINK.Priority,
      AUTHLINK.ProductID
    FROM (SELECT TOP (100) PERCENT
      ProductID,
      MIN(ISNULL(Priority, 0)) AS Priority
    FROM dbo.AuthorLink
    GROUP BY ProductID
    ORDER BY ProductID) AS AuthMinPrty
    INNER JOIN dbo.AuthorLink AS AUTHLINK
      ON (AuthMinPrty.ProductID = AUTHLINK.ProductID)
      AND (ISNULL(AuthMinPrty.Priority, 0) = ISNULL(AUTHLINK.Priority, 0))) AS PrimaryAuthor
      ON Auth.AuthorID = PrimaryAuthor.AuthorID) AS vwAuthor /* Table Author */
      ON BaseInventory.ProductID = vwAuthor.ProductID

    ORDER BY BaseInventory.ReferenceNumber
  END
  ELSE
  BEGIN
    SELECT TOP (100) PERCENT
      BaseInventory.ProductID,
      BaseInventory.ReferenceNumber,
      BaseInventory.Title,
      BaseInventory.StoredBy,
      BaseInventory.TotalInStock,
      BaseInventory.StockAtEDC,
      BaseInventory.Cost,
      BaseInventory.RetailPrice,
      BaseInventory.PubDate,
      BaseInventory.DepartmentCode,
      vwAuthor.PrimaryAuthor,
      ISNULL(Sales30Days.QuantitySold, 0) AS Last30Days,
      ISNULL(SalesPastYear.QuantitySold, 0) AS Last365Days,
      ISNULL(CustomRangeSales.QuantitySold, 0) AS CustomRange,
      ISNULL(SalesPastYear.ZeroStock, '12/31/9999') AS ZeroStock,
      ISNULL(SalesPastYear.ZeroStockFullDate, CONVERT(datetime, '12/31/9999', 102)) AS ZeroStockFullDate,
      BaseInventory.FullPubDate,
      BaseInventory.ProgramArea,
      BaseInventory.Spaces,
      BaseInventory.DigitalFileExists,
      BaseInventory.DownloadCount,
      BaseInventory.DownloadCountCustom,
      ISNULL(SalesPastYear.SpacesSold, 0.000) AS SpacesSold,
      BaseInventory.DateReceived,
      BaseInventory.ProductWeight,
      BaseInventory.NumberOfPages,
      BaseInventory.DigitalFileCount,
      BaseInventory.ActiveDigitalFileCount
    FROM (SELECT TOP (100) PERCENT
      m.ProductWeight,
      m.ProductID,
      m.reference_number AS ReferenceNumber,
      m.title AS Title,
      MAX(sb.StoredBy) AS StoredBy,
      m.TotalInStock,
      m.edc_copies AS StockAtEDC,
      m.pub_cost AS Cost,
      m.RetailPrice,
      m.pub_date AS PubDate,
      d.department_code AS DepartmentCode,
      m.department_id AS DepartmentId,
      dg.department_group AS ProgramArea,
      m.FullPubDate,
      ISNULL(Boxes.Spaces, CASE
        WHEN sb.StoredBy = 'WWW' THEN 0
        ELSE 1
      END) AS Spaces,
      CASE
        WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
        ELSE 'Active'
      END AS DigitalFileExists,
      ISNULL(DLs.DownloadCount, 0) AS DownloadCount,
      ISNULL(DLsCustom.DownloadCountCustom, 0) AS DownloadCountCustom,
      MAX(history.DateReceived) AS DateReceived,
      ISNULL(m.number_of_pages, 'N/A') AS NumberOfPages,
      (SELECT
        COUNT(*)
      FROM tblDigitalMedia tD
      WHERE tD.ProductID = m.ProductID)
      AS DigitalFileCount,
      (SELECT
        COUNT(*)
      FROM tblDigitalMedia tD
      WHERE tD.ProductID = m.ProductID
      AND tD.Active = 1)
      AS ActiveDigitalFileCount
    FROM dbo.main m
    INNER JOIN dbo.departments d
      ON m.department_id = d.department_id
    INNER JOIN dbo.department_groups dg
      ON d.department_group_id = dg.department_group_id

    /* InventoryTemp should be called InventoryByLocation */
    LEFT OUTER JOIN (SELECT
      m1.ProductID,
      SUM(ISNULL(it.NumberOfBoxes, 0)) + 1 AS Spaces
    FROM dbo.main AS m1
    INNER JOIN dbo.InventoryTemp AS it
      ON m1.ProductID = it.ProductID
    GROUP BY m1.ProductID) AS Boxes
      ON m.ProductID = Boxes.ProductID

    /* JobsTemp should be called JobHistory */
    LEFT OUTER JOIN dbo.JobsTemp history
      ON m.ProductID = history.ProductID

    LEFT OUTER JOIN (
    /* If dates are null then fetch for previous year. */
    SELECT TOP (100) PERCENT
      dm1.ProductID,
      COUNT(dl1.TimeStamp) AS DownloadCountCustom
    FROM dbo.tblDigitalMedia AS dm1
    LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl1
      ON dm1.FileID = dl1.FileID
    WHERE ((@CustomDateStart IS NOT NULL)
    AND (dl1.TimeStamp >= @CustomDateStart)
    AND (dl1.TimeStamp <= @CustomDateEnd))
    OR ((@CustomDateStart IS NULL)
    AND (dl1.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()))
    GROUP BY dm1.ProductID) AS DLsCustom
      ON m.ProductID = DLsCustom.ProductID
    LEFT OUTER JOIN (
    /* If dates are null then fetch for previous year. */
    SELECT TOP (100) PERCENT
      dm2.ProductID,
      COUNT(dl2.TimeStamp) AS DownloadCount
    FROM dbo.tblDigitalMedia AS dm2
    LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl2
      ON dm2.FileID = dl2.FileID
    WHERE dl2.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()
    GROUP BY dm2.ProductID) AS DLs
      ON m.ProductID = DLs.ProductID

    LEFT OUTER JOIN dbo.tblDigitalMedia AS dm
      ON m.ProductID = dm.ProductID

    /* InventoryTemp should be called InventoryByLocation */
    LEFT OUTER JOIN dbo.InventoryTemp it2
      ON m.ProductID = it2.ProductID

    INNER JOIN dbo.StoredBy sb
      ON m.StoredByID = sb.StoredByID
    WHERE (m.edc_isle LIKE N'Aisle' + N'%'
    OR m.edc_isle = N'Digital Media'
    OR m.edc_isle = N'Duplicator')
    AND (dg.department_group_id = @ProgramAreaID)

    GROUP BY m.ProductWeight,
             m.ProductID,
             m.reference_number,
             m.title,
             m.TotalInStock,
             dg.department_group_id,
             m.pub_date,
             m.department_id,
             d.department_code,
             m.pub_cost,
             m.RetailPrice,
             m.FullPubDate,
             m.edc_isle,
             sb.StoredBy,
             dg.department_group,
             CASE
               WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
               ELSE 'Active'
             END,
             ISNULL(DLs.DownloadCount, 0),
             ISNULL(DLsCustom.DownloadCountCustom, 0),
             ISNULL(Boxes.Spaces, CASE
               WHEN sb.StoredBy = 'WWW' THEN 0
               ELSE 1
             END),
             m.edc_copies,
             ISNULL(m.number_of_pages, 'N/A')
    HAVING (NOT (MAX(sb.StoredBy) = @ShowNLA))
    ORDER BY m.FullPubDate) AS BaseInventory /* ***** Table A ***** */

    LEFT OUTER JOIN (SELECT
      dbo.shopping_cart.ProductID,
      SUM(dbo.shopping_cart.quantity) AS QuantitySold
    FROM dbo.orders
    INNER JOIN dbo.shopping_cart
      ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
    WHERE dbo.orders.OrderTimeStamp >= DATEADD(DAY, -30, GETDATE())
    AND dbo.orders.OrderTimeStamp < GETDATE()
    AND dbo.shopping_cart.ProductID IS NOT NULL
    GROUP BY dbo.shopping_cart.ProductID) AS Sales30Days  /* ***** Table B ***** */
      ON BaseInventory.ProductID = Sales30Days.ProductID
    LEFT OUTER JOIN (SELECT
      dbo.shopping_cart.ProductID,
      SUM(dbo.shopping_cart.quantity) AS QuantitySold
    FROM dbo.orders
    INNER JOIN dbo.shopping_cart
      ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
    WHERE @CustomDateStart IS NOT NULL
    AND dbo.orders.OrderTimeStamp >= @CustomDateStart
    AND dbo.orders.OrderTimeStamp <= @CustomDateEnd
    AND dbo.shopping_cart.ProductID IS NOT NULL
    GROUP BY dbo.shopping_cart.ProductID) AS CustomRangeSales /* ***** CustomRangeSales ***** */
      ON BaseInventory.ProductID = CustomRangeSales.ProductID

    LEFT OUTER JOIN (SELECT TOP (100) PERCENT
      cart3.ProductID,
      SUM(cart3.quantity) AS QuantitySold,
      m3.TotalInStock,
      CASE
        WHEN
          CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
        ELSE CONVERT(varchar, DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE()), 101)
      END AS ZeroStock,
      CASE
        WHEN
          CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
        ELSE DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE())
      END AS ZeroStockFullDate,
      CONVERT(decimal(18, 3), SUM(cart3.quantity) / ISNULL(CONVERT(decimal(18, 2), AvgInventory.NumberPerBox), SUM(cart3.quantity) + m3.TotalInStock)) AS SpacesSold,
      AvgInventory.NumberPerBox
    FROM dbo.orders AS o1
    INNER JOIN dbo.shopping_cart AS cart3
      ON o1.receiving_number = cart3.receiving_number
    INNER JOIN dbo.main AS m3
      ON cart3.ProductID = m3.ProductID
    LEFT OUTER JOIN (SELECT TOP (100) PERCENT
      ProductID,
      AVG(NumberPerBox) AS NumberPerBox
    FROM dbo.InventoryTemp
    GROUP BY ProductID
    ORDER BY ProductID) AS AvgInventory
      ON m3.ProductID = AvgInventory.ProductID
    WHERE (o1.OrderTimeStamp BETWEEN DATEADD(DAY, -365, GETDATE()) AND GETDATE() + 1)
    GROUP BY cart3.ProductID,
             m3.TotalInStock,
             AvgInventory.NumberPerBox
    HAVING (NOT (cart3.ProductID IS NULL))) AS SalesPastYear /* ***** Table C ***** */
      ON BaseInventory.ProductID = SalesPastYear.ProductID

    LEFT OUTER JOIN (SELECT
      ProductID,
      CASE
        WHEN ((Auth.Company = '') OR
          (Auth.Company IS NULL)) THEN LTRIM(ISNULL(Auth.FirstName, '') + ' ' + ISNULL(Auth.LastName, ''))
        ELSE Auth.Company
      END AS PrimaryAuthor
    FROM dbo.Author AS Auth
    INNER JOIN (SELECT
      AUTHLINK.AuthorID,
      AUTHLINK.Priority,
      AUTHLINK.ProductID
    FROM (SELECT TOP (100) PERCENT
      ProductID,
      MIN(ISNULL(Priority, 0)) AS Priority
    FROM dbo.AuthorLink
    GROUP BY ProductID
    ORDER BY ProductID) AS AuthMinPrty
    INNER JOIN dbo.AuthorLink AS AUTHLINK
      ON (AuthMinPrty.ProductID = AUTHLINK.ProductID)
      AND (ISNULL(AuthMinPrty.Priority, 0) = ISNULL(AUTHLINK.Priority, 0))) AS PrimaryAuthor
      ON Auth.AuthorID = PrimaryAuthor.AuthorID) AS vwAuthor /* Table Author */
      ON BaseInventory.ProductID = vwAuthor.ProductID

    ORDER BY BaseInventory.ReferenceNumber
  END
END /* stored procedure */
GO
8
  • 1
    Why don't you use a Stored Proc which will be more efficient and all the operations will be performed at server level. Commented Oct 1, 2018 at 19:49
  • 1
    ISHIDA is right however are you using deferred loading? I have found that IQueryables are better for building a robust query up Commented Oct 1, 2018 at 19:58
  • Create a view, which you can use just like a table in Entity Framework. Commented Oct 1, 2018 at 20:11
  • The problem is that the SQL server query that is generated by entity framework is very inefficient <= Provide the query you would like to use in your question. Splitting a query into 4 different queries will always add overhead and never be as fast as executing 1 query. You should also profile your queries execution plan to see if there additional gains to be made. Commented Oct 1, 2018 at 20:13
  • @ISHIDA One of the reasons behind rewriting this was the difficulty in reading the query. Originally we were using a stored procedure. Its very hard to edit and debug once all the data is added in. Commented Oct 1, 2018 at 20:19

1 Answer 1

1

Ignore all the people who are telling you to do it some other way, and see whether you can tune what you have. The person who claimed this is 4 queries is incorrect. The LINQ will compose into a single SQL statement. What you need to do is to try and find out:

  • What the generated SQL looks like (try capturing it using SQL Server Profiler)
  • Why it is inefficient (again, SQL Server Profiler, or paste into SSMS and show the query plan)

Once you have done that, it may become clearer what you need to do to your LINQ to make it perform.

One thing you could try in order simplify the amount you need to look at at one time: Execute each "inner" query in isolation and see whether any of them look bad by themselves.

Sign up to request clarification or add additional context in comments.

1 Comment

Good catch all solution, the last one for isolated query is particularly useful as it will zero down on actual problematic area, the same thing you would be doing when analyzing an execution parse tree

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.