У меня есть запрос, который имеет соответствующие индексы и показан в плане запроса с оценочной стоимостью поддерева около 1,5. План показывает поиск по индексу, за которым следует поиск по ключу, что нормально для запроса, который, как ожидается, вернет 1 строку из набора от 5 до 20 строк (т. е. поиск по индексу должен найти от 5 до 20 строк, а после 5–20 строк). Key Lookups, мы должны вернуть 1 строку).
При интерактивном выполнении запрос возвращается почти сразу. Тем не менее, утренние трассировки БД показывают, что время выполнения в реальном времени (веб-приложение) сильно различается; обычно запрос занимает ‹ 100 чтений БД и фактически 0 времени выполнения... но мы получаем несколько запусков, которые потребляют> 170 000 чтений БД и время выполнения до 60 с (больше, чем наше значение тайм-аута).
Чем можно объяснить такую изменчивость в чтении с диска? Я пробовал сравнивать запросы в интерактивном режиме и использовать планы фактического выполнения из двух параллельных прогонов со значениями фильтра, взятыми из быстрых и медленных прогонов, но в интерактивном режиме они практически не показывают разницы в используемом плане.
Я также попытался определить другие запросы, которые могли блокировать этот, но я не уверен, что это так сильно повлияет на чтение БД... и в любом случае этот запрос, как правило, был худшим для времени выполнения в моих журналах трассировки.
Обновление. Вот пример плана, созданного при интерактивном выполнении запроса:
Пожалуйста игнорируйте текст "отсутствует индекс". Верно, что изменения в текущих индексах могут обеспечить более быстрый запрос с меньшим количеством операций поиска, но здесь проблема не в этом (уже есть соответствующие индексы). Это фактический план выполнения, в котором мы видим такие цифры, как фактическое количество строк. Например, при поиске по индексу фактическое количество строк равно 16, а стоимость ввода-вывода равна 0,003. Стоимость ввода-вывода такая же, как и при поиске ключа.
Обновление 2. Результаты трассировки этого запроса:
exec sp_executesql N'select [...column list removed...] from ApplicationStatus where ApplicationGUID = @ApplicationGUID and ApplicationStatusCode = @ApplicationStatusCode;',N'@ApplicationGUID uniqueidentifier,@ApplicationStatusCode bigint',@ApplicationGUID='ECEC33BC-3984-4DA4-A445-C43639BF7853',@ApplicationStatusCode=10
Запрос создается с использованием класса Gentle.Framework SqlBuilder, который строит параметризованные запросы следующим образом:
SqlBuilder sb = new SqlBuilder(StatementType.Select, typeof(ApplicationStatus));
sb.AddConstraint(Operator.Equals, "ApplicationGUID", guid);
sb.AddConstraint(Operator.Equals, "ApplicationStatusCode", 10);
SqlStatement stmt = sb.GetStatement(true);
IList apps = ObjectFactory.GetCollection(typeof(ApplicationStatus), stmt.Execute());