#sql-server-2008-r2
#sql-server-2008-r2
Вопрос:
Это в хранимой процедуре..Это утверждение if, после чего я немного поработаю. @AsOfDate — это переданная переменная типа данных date. У меня вопрос в том, почему я получаю лучшую производительность, удаляя inner-most exists, но ТОЛЬКО тогда, когда весь оператор находится в IF EXISTS?
Две таблицы:
- dbo.TXXX_InventoryDetail — 1,3 миллиарда записей .. статистика обновлена
- dbo.TXXX_InventoryFull — 9,8 миллионов записей .. статистика обновлена
Инструкция:
if exists (select 1
from dbo.TXXX_InventoryDetail o
where exists (select 1
from dbo.TXXX_InventoryFull i
where i.C001_AsOfDate= o.C001_AsOfDate
and i.C001_ProductID=o.C001_ProductID
and i.C001_StoreNumber=o.C001_StoreNumber
and i.C001_AsOfDate=@AsOfDate
and (i.C001_LastModelDate!=o.C001_LastModelDate
or o.C001_InventoryQty!=o.C001_InventoryQty
or i.C001_OnOrderQty!=o.C001_OnOrderQty
or i.C001_TBOQty!=o.C001_TBOQty
or i.C001_ModelQty!=o.C001_ModelQty
or i.C001_TBOAdjustQty!=o.C001_TBOAdjustQty
or i.C001_ReturnQtyPending!=o.C001_ReturnQtyPending
or i.C001_ReturnQtyInProcess!=o.C001_ReturnQtyInProcess
or i.C001_ReturnQtyDueOut!=o.C001_ReturnQtyDueOut))
and o.C001_AsOfDate=@AsOfDate)
вывод ввода-вывода:
- Таблица ‘TXXX_InventoryFull’. Количество сканирований 9240262, логические чтения 29548864
- Таблица ‘T001_InventoryDetail’. Количество проверок 1, логические чтения 17259
Если я удалю второе, где существует, и выполню объединение:
if exists (select 1
from dbo.TXXX_InventoryDetail o,
dbo.TXXX_InventoryFull i
where i.C001_AsOfDate= o.C001_AsOfDate
and i.C001_ProductID=o.C001_ProductID
and i.C001_StoreNumber=o.C001_StoreNumber
and i.C001_AsOfDate=@AsOfDate
and (i.C001_LastModelDate!=o.C001_LastModelDate
or o.C001_InventoryQty!=o.C001_InventoryQty
or i.C001_OnOrderQty!=o.C001_OnOrderQty
or i.C001_TBOQty!=o.C001_TBOQty
or i.C001_ModelQty!=o.C001_ModelQty
or i.C001_TBOAdjustQty!=o.C001_TBOAdjustQty
or i.C001_ReturnQtyPending!=o.C001_ReturnQtyPending
or i.C001_ReturnQtyInProcess!=o.C001_ReturnQtyInProcess
or i.C001_ReturnQtyDueOut!=o.C001_ReturnQtyDueOut)
and o.C001_AsOfDate=@AsOfDate)
вывод ввода-вывода:
- Таблица ‘TXXX_InventoryDetail’. Количество проверок 0, логические чтения 333952
- Таблица ‘TXXX_InventoryFull’. Количество проверок 1, логические чтения 630
Теперь .. причина, по которой я думаю, что это if exists, заключается в том, что если я удалю его и выполню select count (*) следующим образом:
select COUNT(*)
from dbo.T001_InventoryDetail o
where exists (select 1
from dbo.TXXX_InventoryFull i
where i.C001_AsOfDate= o.C001_AsOfDate
and i.C001_ProductID=o.C001_ProductID
and i.C001_StoreNumber=o.C001_StoreNumber
and i.C001_AsOfDate=@AsOfDate
and (i.C001_LastModelDate!=o.C001_LastModelDate
or o.C001_InventoryQty!=o.C001_InventoryQty
or i.C001_OnOrderQty!=o.C001_OnOrderQty
or i.C001_TBOQty!=o.C001_TBOQty
or i.C001_ModelQty!=o.C001_ModelQty
or i.C001_TBOAdjustQty!=o.C001_TBOAdjustQty
or i.C001_ReturnQtyPending!=o.C001_ReturnQtyPending
or i.C001_ReturnQtyInProcess!=o.C001_ReturnQtyInProcess
or i.C001_ReturnQtyDueOut!=o.C001_ReturnQtyDueOut))
and o.C001_AsOfDate=@AsOfDate
- TXXX_InventoryFull’. Количество проверок 41, логические чтения 692
- T001_InventoryDetail’. Количество проверок 65, логические чтения 17477
- Рабочий стол’. Количество проверок 0, логические чтения 0
Ответ №1:
Обычно говорят, что следует избегать выполнения скоординированных подзапросов в предикате, поскольку они имеют тенденцию вызывать соединения с вложенным циклом. При запросе больших наборов данных, особенно когда кто-то пытается обнаружить разницу между наборами, важно разрешить оптимизатору запросов динамически выбирать между алгоритмами хэша, слияния и вложенного цикла, что может быть невозможно, если запрос структурирован с использованием скоординированного подзапроса. Лучше создавать их как производные таблицы в предложении FROM .
Ответ №2:
Я обнаружил похожие проблемы при использовании инструкции EXISTS на сервере SQL 08 R2, где точно такая же инструкция отлично выполняется на SQL 08 и SQL 05.
Я обнаружил, что изменение чего-то вроде
WHILE EXISTS(SELECT * FROM X)
Было бы очень медленно, но:
WHILE ISNULL((SELECT TOP 1 ID FROM X), 0) <> 0
Снова работает идеально быстро.
Мне кажется, что это проблема R2…
Ответ №3:
Я бы предположил, что план, который вы получаете, сильно отличается при использовании join. Возможно, дисбаланс в количестве строк (очень большая внешняя таблица, внутренняя таблица меньшего размера) затрудняет работу оптимизатора, но, вероятно, с помощью join можно намного проще удалять строки (вероятно, вы увидите дополнительные операторы цикла с худшим запросом). Сложно предположить, не видя планов или не имея возможности воспроизвести, но вы всегда должны стремиться к удалению большинства строк как можно раньше в плане. Удаление миллионов строк с помощью нескольких операторов / подзапросов только для того, чтобы исключить большинство из них позже в плане, почти наверняка приведет к снижению производительности.