Это хорошо, но иногда бывает плохо.
Параметр sniffing - это оптимизатор запросов, использующий значение предоставленного параметра для определения наилучшего плана запроса. Один из многих вариантов и один, который довольно легко понять, это то, что вся таблица должна быть отсканирована, чтобы получить значения, или если она будет быстрее с использованием запросов индекса. Если значение в вашем параметре очень избирательно, оптимизатор, вероятно, построит план запроса с помощью запросов, и если он не будет выполнять запрос, сканирование вашей таблицы.
План запроса затем кэшируется и повторно используется для последовательных запросов, имеющих разные значения. Плохая часть параметра sniffing - это когда кешированный план не является лучшим выбором для одного из этих значений.
Образец данных:
create table T
(
ID int identity primary key,
Value int not null,
AnotherValue int null
);
create index IX_T_Value on T(Value);
insert into T(Value) values(1);
insert into T(Value)
select 2
from sys.all_objects;
T
таблица с пару тысяч строк с кластерным индексом, не по значению. Существует одна строка, где значение равно 1
, а остальное значение - 2
.
Пример запроса:
select *
from T
where Value = @Value;
Выбор оптимизатор запросов имеет здесь либо сделать индекс кластерного сканирования и проверьте, где положение в отношении каждой строки или использовать индекс Стремитесь найти в строки, которые соответствуют, а затем выполните поиск ключа, чтобы получить значения из столбцов, запрошенных в списке столбцов.
Когда понюхал значение 1
план запроса будет выглядеть следующим образом:
И когда понюхала значение 2
это будет выглядеть следующим образом:
Плохая часть параметра sniffing в этом случае происходит, когда план запроса построен, обнюхивая 1
, но выполняемый позже с значение 2
.
Вы можете видеть, что ключ поиска был выполнен 2352 раз. Лучшим выбором будет сканирование.
Подводя итог, я бы сказал, что параметр sniffing - это хорошая вещь, которую вы должны попытаться сделать как можно больше, используя параметры для своих запросов. Иногда это может пойти не так, и в таких случаях это, скорее всего, связано с искаженными данными, которые воюют с вашей статистикой.
Update:
Вот запрос на пару DMV-х годов, которые вы можете использовать, чтобы найти то, что запросы являются наиболее дорогими в вашей системе. Измените в порядке заказа, чтобы использовать разные критерии для того, что вы ищете. Я думаю, что TotalDuration
- хорошее место для начала.
set transaction isolation level read uncommitted;
select top(10)
PlanCreated = qs.creation_time,
ObjectName = object_name(st.objectid),
QueryPlan = cast(qp.query_plan as xml),
QueryText = substring(st.text, 1 + (qs.statement_start_offset/2), 1 + ((isnull(nullif(qs.statement_end_offset, -1), datalength(st.text)) - qs.statement_start_offset)/2)),
ExecutionCount = qs.execution_count,
TotalRW = qs.total_logical_reads + qs.total_logical_writes,
AvgRW = (qs.total_logical_reads + qs.total_logical_writes)/qs.execution_count,
TotalDurationMS = qs.total_elapsed_time/1000,
AvgDurationMS = qs.total_elapsed_time/qs.execution_count/1000,
TotalCPUMS = qs.total_worker_time/1000,
AvgCPUMS = qs.total_worker_time/qs.execution_count/1000,
TotalCLRMS = qs.total_clr_time/1000,
AvgCLRMS = qs.total_clr_time/qs.execution_count/1000,
TotalRows = qs.total_rows,
AvgRows = qs.total_rows/qs.execution_count
from sys.dm_exec_query_stats as qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) as st
cross apply sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) as qp
--order by ExecutionCount desc
--order by TotalRW desc
order by TotalDurationMS desc
--order by AvgDurationMS desc
;
Проверьте [это] (http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx). – Sergi
@Sergi: Это относится и к специальным заявлениям? – user3104183
, когда фактическое число строк возвращается для каждого параметра почти одинаковое. Не так много вариаций, то можно позволить себе игнорировать его. Также я думаю, что объявление фиктивной переменной лучше. Я не прав? – KumarHarsh