Постоянное сканирование занимает 0 секунд или 2-3 минуты.

9

Запрос, подобный приведенному ниже, который гарантированно не возвращает никаких строк, занимает от 0 до 160 секунд на одном из наших серверов:

select col1, col2, col3
from tab1
where 0 = 1

Две недели назад это происходило шесть раз с интервалом в 48 часов. На прошлой неделе тот же запрос занял ~ 0 секунд. У меня есть журналы SQL нашего приложения, но я еще не нашел подозреваемых. Кроме того, я подумал, что запрос типа top 0 /, где 0 = 1, никогда не попадает на страницы данных, поэтому он должен быть устойчивым к блокировкам данных на уровне строк / страниц / таблиц? Схема не затрагивается никакими (известными) SQL.

Так как проблема непоследовательна, а сервер находится под очень большой нагрузкой, я хотел бы понять теорию, лежащую в основе того, что происходит, прежде чем подключать SQL Profiler. Другие запросы выполняются без проблем во время этих задержек. Известной проблемой в приложении является большое количество динамически создаваемых SQL-запросов - около 200 тыс. Уникальных запросов из 850 тыс. Запросов в течение 48 часов. Может ли это вызвать такие проблемы?

На сервере установлена ​​стандартная версия SQL Server 2005, 96 ГБ ОЗУ, диски в сети SAN и 4 процессора / 16 ядер. Файлы базы данных и файловые группы хорошо оптимизированы и не должны быть проблемой (но мы рассматриваем это отдельно).

Любые указатели, где искать, с благодарностью.

Редактировать: Отлично! Повторил запрос, чтобы добавить план выполнения, и потребовалось 1 минута 35 секунд. Вот план выполнения и скриншот, показывающий продолжительность запроса: План запроса

Редактировать 2: статистика времени детали для второго запуска. Кажется, сейчас все идет медленно, поэтому мы добавим профилировщик и perfmon:

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 97402 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
Горизонт событий
источник
Не могли бы вы включить план выполнения? CTRL + M в окне запроса перед выполнением.
Крейг Эфрейн
2
Может ли быть проблема с блокировкой? Операторы DML из других сеансов, блокирующие выбор в таблице (это поведение по умолчанию в SQL Server 2005)
a_horse_with_no_name
Нет никаких известных DML-утверждений, и это единственная причина, о которой я могу думать, но мы все еще исследуем это. План выполнения добавляется к вопросу.
EventHorizon
Из того, что я прочитал, это лишь один из тех тривиальных планов выполнения, которые MSSQL использует, чтобы избежать чтения кучи и индексов, когда оптимизатор знает, что строки не возвращаются
Крейг Эфрейн,
1
Увидел случай, который выглядел очень похоже на это. Оказалось, что он запускает статистику обновлений (статистика автообновления была включена и план обслуживания нарушен).
Джошуа

Ответы:

18

Похоже, что даже с ... WHERE 0 = 1условием, что по-прежнему будет требоваться намеренная ISблокировка shared ( ) для таблицы. Давайте докажем это:

Я начну с создания тестовой таблицы:

use TestDb1;
go

create table dbo.MyTestTable1
(
    Id int identity(1, 1) not null,
    SomeInt int not null
);
go

insert into dbo.MyTestTable1 (SomeInt)
values (10), (20), (30), (40), (50);
go

Теперь, когда у меня есть тестовая таблица, в одном сеансе (окно запроса) я собираюсь выполнить следующее, чтобы установить Xблокировку exclusive ( ) dbo.MyTestTable1:

use TestDb1;
go

begin tran;
    select
        Id, SomeInt
    from dbo.MyTestTable1 with (tablockx);
--commit tran;

Я могу проверить эксклюзивную блокировку, посмотрев на sys.dm_tran_locksDMV. Затем в другом сеансе (новое окно запроса) я делаю именно то, что делает ваш запрос:

use TestDb1;
go

select
    Id, SomeInt
from dbo.MyTestTable1
where 0 = 1;

На первый взгляд я вижу, что это не завершает. Глядя на это sys.dm_exec_requests, я точно понимаю, почему это так:

select
    r.session_id,
    r.status,
    r.wait_type,
    r.wait_time,
    r.wait_resource,
    r.blocking_session_id
from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle) st
where st.text like '%where 0 = 1%'
and r.session_id <> @@spid;

введите описание изображения здесь

Я вижу здесь, что мой ... WHERE 0 = 1запрос ожидает ISблокировки для этого объекта (что object_id переводит в dbo.MyTestTable1).

Я ни в коем случае не говорю, что параллелизм - это ваша проблема, но, судя по звукам, вы проявляете симптомы. Приведенный выше пример должен доказать, что вы не освобождаетесь от блокировки и блокировки даже с помощью WHEREпредложения, которое никогда не вернет данные.

Все, что мы можем сделать, это угадать, поэтому, что вам нужно сделать, когда это «занимает много времени», - это увидеть, что именно делает этот запрос, который занимает так много времени. Если он чего-то ждет, то посмотри, чего он ждет.

Томас Стрингер
источник
1

В зависимости от того, насколько резкими и требовательными являются ваши запросы, ваша система может просто поставить этот запрос в очередь. Число рабочих по умолчанию (т.е. число одновременных потоков SQL-сервера) для вашей установки должно быть около 700.

Проверьте sys.dm_os_schedulers и sys.dm_os_waiting_tasks, чтобы увидеть, может ли это быть проблемой.

Саша Рамбо
источник
Хорошее предложение, но проблема в конце концов оказалась глупой блокировкой.
EventHorizon
Я не был действительно убежден, так как 700 рабочих - это достаточно, но это было легко проверить (и, следовательно, исключить)
Саша Рамбо