У нас есть мультитенантная база данных, разделение данных достигается с помощью ключа, прикрепленного ко всем таблицам.Количество строк в каждой таблице может сильно отличаться для каждого арендатора (от 0 до 500000+).После перехода на SQL Server 2017 иногда используются очень плохие планы выполнения.У нас не было проблем с ранее использовавшимся SQL Server 2008.
Самая большая проблема заключается в том, что иногда некоррелированные подзапросы выполняются в цикле для каждой строки внешнего запроса.Подзапрос займет 0 секунд, а внешний запрос с использованием IN (список идентификаторов) также займет 0 секунд, но вместе они выполняются в течение нескольких минут.
Я пробовал разные решения:
OPTION(RECOMPILE)
- Изменение на
JOIN
и OPTION(FORCE ORDER)
UPDATE STATISTICS
для таблиц - Параметр Sniffing включен, но не делаетразница
Ни один из них не решил проблему.
Пример запроса:
SELECT address.adrId, address.adrCity FROM address
WHERE address.orgId=1 AND
address.adrId IN (SELECT instAddress.adrId
FROM instAddress
WHERE instAddress.instId = 12345
AND instAddress.orgId = 1)
ОБНОВЛЕНИЕ: фактический план выполнения, подсвеченное число выполненных и примерное количество выполнений,![enter image description here](https://i.stack.imgur.com/dxVXD.png)
Можно ли как-то сказать SQL Server всегда выполнять подзапрос первым и только один раз?
ОБНОВЛЕНИЕ:
Этот один запрос изменился на правильный план выполнения после последнего обновления статистики.Этот и другие похожие запросы генерируются нашим приложением динамически.Мы хотели бы помешать нам переписать весь уровень базы данных.
Я выбрал этот запрос для примера, потому что он был самым базовым при возникновении проблемы.Другой пример (выборка переводов для некоторых имен), где независимый подзапрос выполняется в циклах для доступного фактического плана выполнения внешнего запроса: https://pastebin.com/tbB0vPUZ
select institutions.inst_id , institutions.inst_nr , inst_name ,
translations1.trans_to as trans_to , translations2.trans_to as trans_to2 ,
translations3.trans_to as trans_to3 , translations4.trans_to as trans_to4
from institutions
left join translations translations1 on institutions.inst_nr = translations1.trans_from and translations1.lang_locale = @0 and translations1.org_id = @1
left join translations translations2 on institutions.inst_nr = translations2.trans_from and translations2.lang_locale = @2 and translations2.org_id = @3
left join translations translations3 on institutions.inst_name = translations3.trans_from and translations3.lang_locale = @4 and translations3.org_id = @5
left join translations translations4 on institutions.inst_name = translations4.trans_from and translations4.lang_locale = @6 and translations4.org_id = @7
where ( institutions.org_id = @8 and lcd_id = @12
and exists (
select inst_id_partner
from agreements
where agreements.inst_id_partner = institutions.inst_id and org_id = @13 and agree_id in (
select agree_id
from agreements
where org_id = @14 and pers in ( @15 , @16 ) and art in ( @17 , @18 ) and prog_id not in (
select prog_id
from programs
where org_id = @19 and is_not_part_of_all_prog = @20 )
and agree_id in (
select agree_id
from year_agree where year_id = @21 and sem_id = @22 )
and ( agree_id not in (
select agree_id
from agree_stat
where org_id = @23 )
or agree_id in (
select agree_id
from agree_stat
where org_id = @24 and agree_stat.year_id = @25 and agree_stat.sem_id = @26 and agree_stat.count1 < agreements.total ) )
and inst_id in ( @27 ) )
)
order by translations1.trans_to