Медленный ответ при запросе View - Использование Linq to SQL - PullRequest
0 голосов
/ 08 января 2010

У меня есть следующий вид:

SELECT     
poHeader.No_ AS PONumber, 
poHeader.[Buy-from Vendor No_] AS VendorNumber, 
poHeader.[Document Date] AS DocumentDate, 
vendor.Name AS VendorName, 
vendor.Contact AS VendorContact, 
vendor.[E-Mail] AS VendorEmail, 
vendor.Address AS VendorAddress, 
vendor.[Address 2] AS VendorAddress2, 
vendor.City AS VendorCity, 
vendor.County AS VendorCounty, 
vendor.[Post Code] AS VendorPostCode, 
vendor.[Phone No_] AS VendorPhone, 
vendor.[Fax No_] AS VendorFax, 
salesHeader.No_ AS SONumber, 
poHeader.[Order Date] AS OrderDate, 
salesHeader.[Crocus Comment] AS CrocusComment, 
salesHeader.GiftMessage, 
salesHeader.[Delivery Comment] AS DeliveryComment, 
salesHeader.[Shipment Date] AS DeliveryDate, 
COALESCE (salesHeader.[Ship-to Name], 
poHeader.[Ship-to Name]) AS DeliveryName, 
COALESCE (salesHeader.[Ship-to Address],
poHeader.[Ship-to Address]) AS DeliveryAddress, 
COALESCE (salesHeader.[Ship-to Address 2],
poHeader.[Ship-to Address 2]) AS DeliveryAddress2,
COALESCE (salesHeader.[Ship-to City], 
poHeader.[Ship-to City]) AS DeliveryCity, COALESCE (salesHeader.[Ship-to County], 
poHeader.[Ship-to County]) AS DeliveryCounty, 
COALESCE (salesHeader.[Ship-to Post Code], 
poHeader.[Ship-to Post Code]) AS DeliveryPostcode, 
salesHeader.DeliveryPhoneNo, poForEmailing.Processed, 
poForEmailing.Copied

FROM         
Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 
INNER JOIN
Navision4.dbo.[Crocus Live$Vendor] AS vendor ON poHeader.[Buy-from Vendor No_] = vendor.No_ 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = dbo.fnGetSalesOrderNumber(poHeader.No_)

Это представление создается в базе данных под названием NavisionMeta Он запрашивает базу данных (на том же сервере) под названием Navision4

Я недавно переместил обе базы данных на новое (лучшее) оборудование. Не уверен, что это актуально, но новое оборудование имеет SQL 2008, а старое оборудование работало под управлением SQL 2000

Если я сделаю запрос с помощью этого запроса в SQL Management Studio, это займет более 2 минут:

SELECT * 
FROM [NavisionMeta].[dbo].[PurchaseOrders]
WHERE Processed=0 AND Copied=0

Что слишком долго!

Следующий запрос в LINQ полностью отключен, даже если я установил таймаут на 5 минут!

            var purchaseOrdersNotProcessed = (from p in db.PurchaseOrders
                                              where p.Copied.Equals(0)
                                              && p.Processed.Equals(0)
                                              select p).ToList();

Что меня озадачивает, так это то, что на предыдущем оборудовании все работало нормально!

На случай, если это уместно, udf используется выше:

CREATE FUNCTION [dbo].[fnGetSalesOrderNumber](@PONumber varchar(20))
RETURNS varchar(20)
AS
BEGIN

RETURN (
SELECT 
    TOP 1 [Sales Order No_]
FROM 
    Navision4.dbo.[Crocus Live$Purchase Line]
WHERE 
    [Document No_] = @PONumber
)

Ответы [ 4 ]

1 голос
/ 09 марта 2010

Left Inner Join? Хм, не уверен, поможет ли это вообще ...

Если бы этот запрос работал раньше (данные, а не производительность), то для этого запроса было бы полезно превратить все ваши объединения в ВНУТРЕННИЕ СОЕДИНЕНИЯ. Поскольку вы используете ВНУТРЕННЕГО СОЕДИНЕНИЯ по значению из poHeader (которое является внешним соединением), вы, по сути, также сделали требование внутреннего соединения для poHeader (за исключением потенциального снижения производительности для внешнего соединения). Поставщик не может вернуть значение, если только у poHeader нет значения, и поскольку vendor является внутренним соединением, вся строка будет проигнорирована, если в poHeader нет значения. То же самое с salesHeader. Функция, используемая в соединении, требует значения в poHeader (которое должно иметь значение в соответствии с приведенной выше логикой), поэтому это объединение также выиграет от превращения в явное INNER JOIN вместо просто подразумеваемого.

Кроме этого, я согласен с утверждениями об индексах (за исключением того, что редко требуется внешнее соединение. Это все равно, что сказать, что вам не нужна отвертка, если у вас есть молоток). Индексирование звучит как наиболее логичное объяснение более слабой производительности. В частности, вы должны проверить, имеет ли ваша таблица псевдонимов poForEmailing индекс ([обработано], [скопировано]). Без этого индекса вы можете ожидать, что время вашего запроса удвоится, так как размер данных удваивается, потому что каждую запись в этой таблице нужно будет проверять на соответствие этим предикатам. Что касается вашего исходного вопроса, я не заметил ничего в SQL Server 2008, который бы предлагал такое изменение производительности при прочих равных условиях.

1 голос
/ 08 января 2010

Вы также можете рассмотреть возможность обновления статистики.

0 голосов
/ 08 января 2010

EDIT

Я не уверен, что вы пытаетесь сделать, но если вы пытаетесь получить информацию о ПО, я думаю, что приведенные ниже изменения помогут, у вас есть

FROM Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
  LEFT OUTER JOIN Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 
  INNER JOIN Navision4.dbo.[Crocus Live$Vendor] AS vendor ON poHeader.[Buy-from Vendor No_] = vendor.No_ 
  LEFT OUTER JOIN Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = dbo.fnGetSalesOrderNumber(poHeader.No_)

Попробуйте это:

FROM Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
  LEFT JOIN Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 
  LEFT JOIN Navision4.dbo.[Crocus Live$Vendor] AS vendor ON poHeader.[Buy-from Vendor No_] = vendor.No_ 
  LEFT JOIN Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = dbo.fnGetSalesOrderNumber(poHeader.No_)

Что касается скорости, вам, вероятно, нужно обновить некоторые индексы ... особенно в поле No_. Кроме того, сделайте следующее изменение, чтобы избавиться от fuGetSalesOrderNumber (), вызываемого в каждой строке:

;WITH PurchaseLineByPO AS
(
  SELECT MAX([Sales Order No_]) as SO, [Document No_] as DNum
  FROM Navision4.dbo.[Crocus Live$Purchase Line]
  Group By [Document No_]
)
--blah blah whole select goes here.. with
JOIN PurchaseLineByPO ON DNum = poHeader.No_
--in the join and 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Sales Header] AS salesHeader ON salesHeader.No_ = PurchaseLineByPO.SO
--replaces what you had

Посмотрите, работает ли это для вас.

Игнорировать старые вещи ниже ...

Мне трудно точно понять, что вы здесь делаете, но редко нужны ВНЕШНИЕ соединения - действительно ли это то, что вы хотите сделать? Если это так, вы можете изменить порядок и получить внутреннее соединение. Например, вы говорите:

FROM         
Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing 
LEFT OUTER JOIN
Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader ON poForEmailing.No_ = poHeader.No_ 

и вы могли бы сказать

FROM         
Navision4.dbo.[Crocus Live$Purchase Header] AS poHeader 
LEFT INNER JOIN
Navision4.dbo.[Crocus Live$Purch_ orders for e-mailing] AS poForEmailing ON poForEmailing.No_ = poHeader.No_ 

В зависимости от ваших данных это может оказать существенное влияние на время выполнения.

0 голосов
/ 08 января 2010

Отправной точкой может быть просмотр плана выполнения запроса на старой и новой машинах. Конечно, будут различия в оптимизации с более новыми версиями SQL Server. План выполнения может показать, что необходим индекс, который по какой-то причине не был столь критичным в предыдущей версии.

...