Могу ли я сделать это быстрее? - PullRequest
0 голосов
/ 12 мая 2009

Что ж, у меня есть ряд sps, которые используют решение для хранилища данных, которое мы разработали на месте. Хотя по большей части он работает довольно хорошо, есть одна хранимая процедура, которая работает очень медленно. Выполнение занимает в среднем около 30 минут. Я точно знаю, где находится горлышко бутылки, я просто не знаю, как это исправить.

По сути, хранимая процедура создает последовательность переменных временных таблиц и вставляет их в эти таблицы. нет проблем там. затем он дважды объединяет временные таблицы и вставляет их в другую временную таблицу (вторая немного отличается).

это оператор, который соединяет таблицы и вставляет их во временную таблицу, и это та часть, которая занимает вечность. любая помощь будет принята с благодарностью.

; with Requested as
(
    select distinct 
        PONUMBER as PONumber, 
        min(REQSTDBY) as RequestedBy
    from dw.POP10110
    where REQSTDBY <>''
    group by PONUMBER
)
insert into @tblTableA
(
    PONumber, 
    ReceiptNumber,
    ReceiptLineNumber, 
    VendorID, 
    POType, 
    QuantityShipped, 
    QuantityInvoiced,
    ItemNumber, 
    ItemDescription, 
    UofM, 
    UnitCost, 
    ExtendedCost, 
    SiteID,
    ProjectNumber, 
    AccountID, 
    RequestedBy, 
    GLPostDate, 
    VendorName, 
    CostCategoryID
) 

select 
    a.PONUMBER, 
    a.POPRCTNM, 
    a.RCPTLNNM, 
    a.VENDORID, 
    a.POPTYPE, 
    a.QTYSHPPD, 
    a.QTYINVCD,
    b.ITEMNMBR,
    b.ITEMDESC,
    b.UOFM,
    b.UNITCOST,
    b.EXTDCOST,
    b.LOCNCODE,
    b.ProjNum,
    case i.CostCategoryID 
        when 'MISC' then isnull(i.AccountID,'N/A')

        else 
            case j.CostCategoryID 
                when 'MISC' then 
                    isnull(j.AccountID,'N/A')

                else 
                    isnull(c.PurchaseAccount,'N/A') 
            end
    end as AccountID,
    d.RequestedBy,
    coalesce(e.GLPOSTDT, f.GLPOSTDT, '') as GLPostDate,
    coalesce(e.VENDNAME, f.VENDNAME, '') as VENDNAME,
    case i.CostCategoryID when 'MISC' then i.CostCategoryID else 
        case j.CostCategoryID when 'MISC' then j.CostCategoryID else coalesce(g.CostCategoryID, h.CostCategoryID, '') end
    end as CostCategoryID

from dw.POP10500 a
    inner join dw.POP30310 b
        on a.PONUMBER=b.PONUMBER
            and a.POPRCTNM=b.POPRCTNM
            and a.RCPTLNNM=b.RCPTLNNM
    left outer join @gl00100 c
        on b.INVINDX=c.ActID
    left outer join Requested d
        on b.PONUMBER = d.PONumber
    left outer join dw.POP30300 e
        on b.POPRCTNM=e.POPRCTNM
    left outer join dw.POP10300 f
        on b.POPRCTNM=f.POPRCTNM
    left outer join @pop31310 g
        on b.POPRCTNM=g.ReceiptNumber
    left outer join @pop11310 h
        on b.POPRCTNM=h.ReceiptNumber
    left outer join @pop30390 i
        on a.POPRCTNM=i.ReceiptNumber
    left outer join @pop10390 j
        on a.POPRCTNM=j.ReceiptNumber

Насколько мне известно, соответствующие индексы на месте.

Ответы [ 4 ]

2 голосов
/ 12 мая 2009

Сколько строк в ваших временных таблицах / табличных переменных?

Похоже, вы используете переменные таблицы, но если в них много строк, рассмотрите возможность использования временных таблиц (таблицы с именем, начинающимся с #) Вы можете добавить дополнительные индексы в эти таблицы, тогда как переменные таблиц могут иметь только один кластеризованный индекс.

т.е. преобразовать переменные таблицы
@ pop31310, @ pop11310, @ pop30390, @ pop10390
во временные таблицы и присвойте каждому индекс по столбцу ReceiptNumber.

1 голос
/ 12 мая 2009

В ваших таблицах переменных (те, которые начинаются с @), вероятно, нет индексации.

Единственным индексированием, которое можно добавить в таблицу переменных, является первичный ключ кластеризованного индекса.

Физически упорядочивает таблицу переменных по OrderID.

DECLARE @Orders TABLE
(
  OrderID int PRIMARY KEY,
  CustomerID int
  OrderDate datetime
)

Это физически упорядочивает таблицу @Orders по CustomerID и разрывает связи, используя OrderID. Теперь он подходит для присоединения по CustomerID.

DECLARE @Orders TABLE
(
  OrderID int,
  CustomerID int
  OrderDate datetime,
  PRIMARY KEY(CustomerID, OrderID)
)

Также следует помнить, что в таблицах переменных отсутствует статистика во время оптимизации. Оптимизатор всегда будет рассматривать их как имеющие 0 строк и будет использовать соединения с вложенными циклами, когда другие типы соединений могут быть более подходящими.

1 голос
/ 12 мая 2009

Предостережение: большая часть моего опыта связана с Oracle, а не с SQLServer, но я считаю, что ответ верен.

Как правило, вы хотите минимизировать количество таблиц в объединении, потому что оптимизатору придется работать с перестановками и, как правило, путаться. С запросами в стиле хранилища данных я бы искал не более трех таблиц за одно соединение и строил запросы по частям.

Другой очевидный вопрос: индексируются ли эти временные таблицы? Если нет, то вам придется выполнить относительно неэффективное объединение всех строк (либо сканирование таблицы, либо объединение хешей, если поддерживается).

0 голосов
/ 12 мая 2009

добавил статистику к некоторым таблицам и индексу, что сократило время с 25 до 9 минут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...