Как я могу улучшить производительность этой хранимой процедуры? - PullRequest
2 голосов
/ 15 декабря 2011

Хорошо, я внес некоторые изменения в хранимую процедуру, которая у нас есть, и теперь она занимает 3 часа (раньше это занимало всего 10 минут). У меня есть временная таблица с именем #tCustomersEmail. В нем есть столбец с именем OrderDate, в котором много пустых значений. Я хочу заменить эти нулевые значения данными из другой базы данных на другом сервере. Итак, вот что у меня есть:

Я создаю другую временную таблицу:

Create Table #tSouth
(
CustID char(10),
InvcDate nchar(10)
)

Которые я заполняю этими данными:

INSERT INTO #tSouth(CustID, InvcDate)
SELECT DISTINCT
      [CustID],
      max(InvcDate) as InvcDate
  FROM D3.SouthW.dbo.uc_InvoiceLine I
  where EXISTS (SELECT CustomerNumber FROM #tCustomersEmail H WHERE   I.CustID =  H.CustomerNumber) 
  group BY I.CustID

Затем я беру данные из #tSouth и обновляю OrderDate в таблице #tCustomersEmail, пока совпадает CustomerNumber, а OrderDate равно нулю:

UPDATE #tCustomersEmail  
SET OrderDate = InvcDate 
FROM #tCustomersEmail  
INNER JOIN #tSouth ON #tCustomersEmail.CustomerNumber = [#tSouth].CustID
where #tCustomersEmail.OrderDate IS null

При внесении этих изменений хранимая процедура приняла FOR-EV-ER (ссылка на Sandlot!)

Так что я делаю не так?

Кстати, я создаю индексы для своих временных таблиц после того, как создаю их следующим образом:

create clustered index idx_Customers ON #tCustomersEmail(CustomerNumber)
CREATE clustered index idx_CustSouthW ON #tSouth(CustID)

Ответы [ 4 ]

3 голосов
/ 15 декабря 2011

Может быть использовать переменную таблицы вместо временной таблицы?

declare @temp table
(
    CustID char(10),
    InvcDate nchar(10)
)

insert into @temp
...

Это определенно увеличит производительность!

3 голосов
/ 15 декабря 2011

Попробуйте пропустить таблицу #tsouth и используйте этот запрос:

UPDATE a
SET OrderDate = (select max(InvcDate) from D3.SouthW.dbo.uc_InvoiceLine I 
                 where a.customernumber = custid)  
FROM #tCustomersEmail a  
WHERE orderdate is null

Я не думаю, что индекс поможет вам в этом примере

2 голосов
/ 15 декабря 2011

Трудно предсказать поведение сложных запросов, включающих таблицы на связанном сервере, потому что локальный сервер не имеет доступа к статистике для удаленной таблицы и может в результате этого иметь плохой план запроса - он будет работать на Предположение, что удаленная таблица имеет 1 или 100 строк. Если это не было достаточно плохо, результатом плохого плана может быть перетаскивание всей удаленной таблицы по проводам в локальное временное пространство и работа над ней там. Если удаленная таблица очень большая, это может привести к значительному снижению производительности.

Возможно, стоит попытаться упростить запрос к связанному серверу, чтобы свести к минимуму шансы, что вся таблица будет возвращена по проводам (как уже упоминалось, вам не нужны ни DISTINCT, ни GROUP BY)

INSERT INTO #tSouth(CustID, InvcDate)
SELECT [CustID],
      max(InvcDate) as InvcDate
  FROM D3.SouthW.dbo.uc_InvoiceLine I
  group BY I.CustID

оставляя оставшуюся часть запроса без изменений.

Однако из-за совокупности это может привести к тому, что вся таблица вернется на локальный сервер - вам нужно проверить, чтобы выяснить это. Лучше всего заключить инкапсуляцию этой логики в представление в базе данных SouthW, если вы можете создавать в ней объекты, а затем ссылаться на это из своего кода SP.

2 голосов
/ 15 декабря 2011

Отличия не нужны, если у вас есть GROUP BY.Учитывая, что вы просматриваете базу данных, мне не нравится EXISTS.Я бы изменил эту часть, чтобы ограничить количество строк в этой точке.Измените на:

INSERT INTO #tSouth(CustID, InvcDate)
SELECT 
      [CustID],
      max(InvcDate) as InvcDate
  FROM D3.SouthW.dbo.uc_InvoiceLine I
  where I.CustID in 
       (SELECT CustomerNumber 
        FROM #tCustomersEmail H 
        WHERE H.OrderDate IS null ) 
  group BY I.CustID

РЕДАКТИРОВАТЬ: Если вы посмотрите ближе, вы уверены, что следует использовать uc_InvoiceLine?Похоже, должна быть родительская таблица для той, которая имела бы дату и имела бы меньше строк.Кроме того, вы можете пропустить одну временную таблицу, выполнив обновление напрямую:

UPDATE #tCustomersEmail  
SET OrderDate = InvcDate 
FROM #tCustomersEmail  
INNER JOIN (SELECT 
      [CustID],
      max(InvcDate) as InvcDate
  FROM D3.SouthW.dbo.uc_InvoiceLine I
  where I.CustID in 
       (SELECT CustomerNumber 
        FROM #tCustomersEmail H 
        WHERE H.OrderDate IS null ) 
  group BY I.CustID) Invoices
ON #tCustomersEmail.CustomerNumber = Invoices.CustID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...