Любое собрание строк (T.stratId = 7 AND TT.stratId = 7)
обязательно должно соответствовать (T.stratId = 7 OR TT.stratId = 7)
, поэтому логически невозможно, чтобы менее ограничительный предикат возвращал меньше результатов.
Проблема в поврежденном некластерном индексе.
И чехол
- 154 строки в
TradeCore
, соответствующих условию даты, и stratId = 7.
- Соединение
TradeTransfer
с примененными условиями stratId
и fundId
приводит к выходу 68 строк (приблизительно 34 строки)
- Все они успешно объединяются в строку в
Sec
(с использованием индекса IX_Sec_secId_sectype_Ccy_valpoint), и 68 строк возвращаются в качестве окончательного результата.

Или чехол
- 1173 строки в
TradeCore
, соответствующие условию даты, выбрасываются
- Присоединение к
TradeTransfer
с остаточным предикатом 3 in (T.fundId, TT.fundId) AND 7 in (T.stratId, TT.stratId)
приводит к уменьшению этого значения до 73 (приблизительно 297 строк)
- Затем все строки удаляются объединением на Sec - несмотря на то, что мы знаем сверху, что по крайней мере 68 из них имеют совпадение.

Количество элементов таблицы Sec
составляет 2399
строк. В плане, в котором все строки удаляются соединением, SQL Server выполняет полное сканирование на IX_Sec_idu
в качестве входных данных для зондирующей стороны хеш-соединения, но полное сканирование на этот индекс возвращает только 589 строк .
Строки, которые появляются в другом плане выполнения, извлекаются из другого индекса, содержащего эти 1810 пропущенных строк.
Вы подтвердили в комментариях, что следующие возвращают отличающиеся результаты
select count(*) from Sec with(index = IX_Sec_idul); --589
select count(*) from Sec with(index = IX_Sec_secId_sectype_Ccy_valpoint); --2399
select count(*) from Sec with(index = PK_Sec) --2399
Это никогда не должно происходить в том случае, если счетчики строк из разных индексов в одной и той же таблице не совпадают (за исключением случаев, когда индекс фильтруется и это здесь не применяется).
Причина разных индексов
Поскольку оценки строк, входящих в объединение Sec
в случае AND
, равны только 34, он выбирает план с вложенными циклами и поэтому для выполнения поиска требуется индекс с ведущим столбцом secId
. Для случая OR
он оценивает 297 строк, и вместо того, чтобы выполнить приблизительно 297 запросов, он вместо этого выбирает хеш-соединение, поэтому выбирает наименьший доступный индекс, содержащий столбец secId
.
Fix
Поскольку в кластеризованном индексе есть все строки, вы можете удалить IX_Sec_idul
и создать его снова, чтобы, надеюсь, решить эту проблему (сначала сделайте резервную копию).
Вы также должны запустить dbcc checkdb
, чтобы увидеть, не скрываются ли какие-либо другие проблемы.