Прежде всего, немного фона.
У нас есть система обработки заказов, в которой сотрудники вводят данные о выставлении счетов в приложение, которое хранит их в базе данных sql server 2000. Эта база данных не является реальной биллинговой системой: это просто хранилище, так что записи могут быть запущены в систему мэйнфреймов через ночные пакетные процессы.
Этот пакетный процесс является стандартным сторонним пакетом, предоставленным сторонним поставщиком. Часть того, что он должен сделать, это предоставить отчет для любых записей, которые были отклонены. Отчет об отклонении обрабатывается вручную.
К сожалению, оказывается, что стороннее программное обеспечение не улавливает все ошибки. У нас есть отдельные процессы, которые возвращают данные из мэйнфрейма в другую таблицу в базе данных и загружают отклоненные сборы в еще одну таблицу.
Затем выполняется процесс аудита, чтобы убедиться, что все, что первоначально было введено персоналом, может быть где-то учтено. Этот аудит принимает форму SQL-запроса, который мы запускаем, и выглядит примерно так:
SELECT *
FROM [StaffEntry] s with (nolock)
LEFT JOIN [MainFrame] m with (nolock)
ON m.ItemNumber = s.ItemNumber
AND m.Customer=s.Customer
AND m.CustomerPO = s.CustomerPO -- purchase order
AND m.CustPORev = s.CustPORev -- PO revision number
LEFT JOIN [Rejected] r with (nolock) ON r.OrderID = s.OrderID
WHERE s.EntryDate BETWEEN @StartDate AND @EndDate
AND r.OrderID IS NULL AND m.MainFrameOrderID IS NULL
Конечно, это сильно модифицировано, но я считаю, что важные части представлены. Проблема в том, что этот запрос начинает выполняться слишком долго, и я пытаюсь выяснить, как его ускорить.
Я почти уверен, что проблема в соединении таблицы StaffEntry
с таблицей MainFrame
. Так как оба хранят данные для каждого заказа с начала времени (2003 в этой системе), они имеют тенденцию быть немного большими. Значения OrderID
и EntryDate
, используемые в таблице StaffEntry
, не сохраняются при импорте в мэйнфрейм, поэтому такое объединение немного сложнее. И наконец, так как я ищу записи в таблице MainFrame
, которые не существуют, после выполнения JOIN мы имеем этот уродливый IS NULL
в предложении where.
Таблица StaffEntry
индексируется с помощью EntryDate (кластеризовано) и отдельно для Customer / PO / rev. MainFrame
индексируется клиентом и номером платы за мэйнфрейм (кластеризовано, это необходимо для других систем) и отдельно клиентом / PO / Rev. Rejected
вообще не индексируется, но он небольшой, и тестирование показывает, что это не проблема.
Итак, мне интересно, есть ли другой (надеюсь, быстрее) способ выразить эти отношения?