Запрос выполняется медленно в одном наборе данных, но быстрее в другом, более крупном наборе данных; MSSQL-сервер; Разный план выполнения. Почему?

Вот запрос:

select nd1.ansos_id
from nursdate nd1
where nd1.division_id = 2
  and nd1.unit_id = 19
  and nd1.nursdate_start_date =
          (select min(nd2.nursdate_start_date)
           from nursdate nd2
           where nd2.ansos_id = nd1.ansos_id
                 and nd2.nursdate_start_date >= all
                      (select nd3.nursdate_start_date
                       from nursdate nd3
                       where nd3.ansos_id = nd1.ANSOS_ID
                             and nd3.nursdate_start_date <= '2017-08-13 00:00:00'))

Ниже верно для обоих наборов данных

  • Актуальная статистика;
  • Индексы дефрагментированы
  • Общие свойства для обоих наборов данных одинаковы: пример: сортировка;
  • Кроме того, два набора данных содержат примерно одинаковое количество данных. На самом деле чем быстрее, тем больше данных

Теперь для запуска одного набора данных требуется ~8 секунд, а для другого набора данных — ‹1 секунды. Вот разница в плане выполнения между двумя наборами данных.

  1. «Фактическое количество строк» ​​и «Количество выполнений» в более медленном наборе данных астрономически выше.
  2. Более быстрый также имеет дополнительный узел «Индексная катушка».

Снимок экрана № 1. Тот же запрос, план медленного выполнения в одном наборе данных введите здесь описание изображения

Снимок экрана № 2. Тот же запрос, план быстрого выполнения в другом наборе данных введите здесь описание изображения

Как решить эту проблему? Что я могу сделать, чтобы заставить его работать быстро в 1-м наборе данных? Спасибо!

[EDIT] План более медленного выполнения: (обратите внимание, что вся таблица «nursdate» содержит только 99 тыс. строк) https://www.brentozar.com/pastetheplan/?id=r1ZFFuNt-

Более быстрый план выполнения: (обратите внимание, что вся таблица «nursdate» содержит 333 000 строк. Это как-то быстрее) https://www.brentozar.com/pastetheplan/?id=rJYMc_EKb

[EDIT] Вот некоторая информация об объеме данных. Тот, что на «mmt», имеет меньше данных, но работает медленнее.

--mmt cnt: 99347
select count(*)
from mmt_sqa_v60.mmtsqav60.nursdate nd1

--heo cnt: 333275
select count(*)
from heo_sqa_v60_2k12.heosqav602k12.nursdate nd1

--mmt cnt: 2403
select count(*)
from mmt_sqa_v60.mmtsqav60.nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'


--heo cnt: 5537
select count(*)
from heo_sqa_v60_2k12.heosqav602k12.nursdate nd1
where nd1.division_id = 1
and nd1.unit_id = 20
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'

person riceball    schedule 30.08.2017    source источник
comment
Используйте этот инструмент для публикации обоих планов выполнения: brentozar.com/pastetheplan   -  person Eli    schedule 30.08.2017
comment
Что вы имеете в виду под двумя наборами данных? Если они используют разные таблицы, разве у вас не должно быть двух разных запросов? Если запрос использует разные параметры, нам также нужны два запроса, чтобы мы могли сравнить.   -  person Juan Carlos Oropeza    schedule 30.08.2017
comment
Ответ на ваш вопрос находится прямо здесь [фактическое количество строк и количество выполнений в более медленном наборе данных астрономически выше]. 4,1 миллиона строк и 9 тысяч строк. Планы выполнения, вероятно, будут разными, потому что мы говорим о величине разницы в объеме данных.   -  person Sean Lange    schedule 30.08.2017
comment
Ваши изображения показывают, что вы используете два разных экземпляра сервера и две разные версии. НИКОГДА не предполагайте, что базы данных одинаковы, если только вы не предпримете шаги, чтобы убедиться, что это так (и это можно сделать только одним способом). Кроме того, вам необходимо понимать различия в оборудовании и то, как они влияют на экземпляр сервера. Экземпляры вашего сервера настроены одинаково? Они также указывают, что вы используете RTM-версию сервера sql, так что перестаньте тратить время и обновитесь до текущей SP.   -  person SMor    schedule 30.08.2017
comment
@SeanLange Я в замешательстве. Потому что OP в заголовке говорит, что больший набор данных является самым быстрым, но затем на картинке говорится, что больший набор данных работает медленнее. И, как вы говорите, должно быть медленнее, потому что у одного 4 миллиона строк, а у другого только 900 строк.   -  person Juan Carlos Oropeza    schedule 30.08.2017
comment
@JuanCarlosOropeza, честно говоря, ОП противоречит себе. В какой-то момент они заявляют, что у более быстрого есть больше данных, но затем заявляют, что фактическое количество строк астрономически выше у более медленного.   -  person Sean Lange    schedule 30.08.2017
comment
@SeanLange Я добавил некоторую информацию об объеме данных. Я не понимаю, откуда берутся 4 миллиона строк в более медленном плане выполнения - в таблице вообще нет такого количества строк.   -  person riceball    schedule 30.08.2017
comment
@SMor Спасибо за информацию.   -  person riceball    schedule 30.08.2017
comment
@Juan Carlos Oropeza здесь 2 набора данных - одна и та же схема, но разные данные   -  person riceball    schedule 30.08.2017
comment
@Эли Спасибо за совет. Только что опубликовал оба плана выполнения с помощью инструмента   -  person riceball    schedule 30.08.2017
comment
@riceball Все еще не ясно. У вас должны быть серверы, база данных, схемы и таблицы.   -  person Juan Carlos Oropeza    schedule 30.08.2017
comment
@Juan Carlos Oropeza Только что провел несколько тестов, чтобы оба набора данных находились на одном сервере базы данных с текущим SP. Но эту проблему все еще можно воспроизвести - иногда она имеет астрономически высокое фактическое количество строк и количество выполнения. Так что я думаю, что фактор здесь, вероятно, не из-за экземпляра сервера   -  person riceball    schedule 30.08.2017
comment
Не говорите наборы данных. На сервере Sql нет набора данных. Только базы данных, схемы и таблицы.   -  person Juan Carlos Oropeza    schedule 30.08.2017
comment
@ Хуан Карлос Оропеса Спасибо за подсказку   -  person riceball    schedule 30.08.2017


Ответы (2)


Не связано с вашей проблемой, но у вашего запроса есть некоторые проблемы. Я думаю, что ваша функция запроса находит ansos_id с любой записью до @date, поправьте меня, если я ошибаюсь.

На самом глубоком уровне все даты за ansos_id предшествуют @date.

select nd3.nursdate_start_date
from nursdate nd3
where nd3.ansos_id = nd1.ANSOS_ID
  and nd3.nursdate_start_date <= '2017-08-13 00:00:00')

затем предыдущий запрос сравнивается со всеми этими датами.

and nd2.nursdate_start_date >= all ( ...)

Это очень неэффективно, потому что единственная дата, которая больше или равна всем датам, — это MAX(date).

Тогда вы (select min(nd2.nursdate_start_date) когда, как я уже объяснял, есть только одна дата >= to all

Я скажу, что ваш запрос должен быть заменен этим, чтобы вернуть последнюю запись перед @date для каждого ansos_id:

WITH cte as (    
     select nd1.ansos_id, nursdate_start_date,
            RANK() OVER (PARTITION BY ansos_id
                         ORDER BY nursdate_start_date DESC) as rn
     from nursdate nd1
     where nd1.division_id = 2
       and nd1.unit_id = 19
       and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
)
SELECT *
FROM cte
WHERE rn = 1
person Juan Carlos Oropeza    schedule 30.08.2017
comment
Спасибо за помощь здесь. Это двухэтапный запрос; Шаг 1: если есть какие-либо записи ‹= целевая дата, верните самую последнюю из них, Шаг 2: иначе, если шаг № 1 возвращает значение null, верните самую раннюю запись › целевую дату. - person riceball; 30.08.2017
comment
Мой запрос сделать Step1. Но ваш запрос, похоже, также не выполняет шаг 2? Могут быть повторяющиеся даты? - person Juan Carlos Oropeza; 30.08.2017
comment
Этот запрос выполняет шаг № 2 (это то, о чем min). Нет, речь не о повторяющихся свиданиях. Также я пробовал что-то еще (иметь оба набора данных на одном сервере базы данных). Я добавил комментарий к вопросу. - person riceball; 30.08.2017

Тайна разгадана. Это проблема данных. Вот откуда берется большое количество «плана выполнения»:

select count(*)
from mmtsqav60.NURSDATE ndArea
left outer join mmtsqav60.NURSDATE ndRelated on ndRelated.ANSOS_ID = 
ndArea.ANSOS_ID
where ndArea.DIVISION_ID=2 and ndArea.UNIT_ID=19;

В результате получается 4157613, и это именно то количество строк, которое план выполнения возвращает при поиске по индексу на nd2 и nd3. Потому что приведенная выше логика, по сути, заключается в том, что этот запрос nursdate в WSM просит сервер базы данных сделать — найти все записи для области, а затем для каждой такой записи найти все записи для этого ansos_id. Для нас это нереальные данные, поскольку один единственный «ansos_id» содержит тысячи записей. Спасибо всем людям, которые помогли здесь.

person riceball    schedule 06.09.2017