Itu bagus tapi terkadang bisa buruk.
Mengendus parameter adalah tentang pengoptimal kueri yang menggunakan nilai parameter yang disediakan untuk mengetahui rencana kueri terbaik. Salah satu dari banyak pilihan dan yang cukup mudah dipahami adalah apakah seluruh tabel harus dipindai untuk mendapatkan nilainya atau akan lebih cepat menggunakan pencarian indeks. Jika nilai dalam parameter Anda sangat selektif, pengoptimal mungkin akan membuat rencana kueri dengan pencarian dan jika tidak, kueri akan memindai tabel Anda.
Rencana kueri kemudian di-cache dan digunakan kembali untuk kueri berurutan yang memiliki nilai berbeda. Bagian buruk dari parameter sniffing adalah ketika paket yang di-cache bukanlah pilihan terbaik untuk salah satu nilai tersebut.
Contoh data:
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
adalah tabel dengan beberapa ribu baris dengan indeks yang tidak berkerumun pada Nilai. Ada satu baris dengan nilai 1
dan sisanya memiliki nilai 2
.
Contoh kueri:
select *
from T
where Value = @Value;
Pilihan yang dimiliki pengoptimal kueri di sini adalah melakukan Pemindaian Indeks Berkelompok dan memeriksa klausa where terhadap setiap baris atau menggunakan Pencarian Indeks untuk menemukan baris yang cocok dan kemudian melakukan Pencarian Kunci untuk mendapatkan nilai dari kolom yang diminta di daftar kolom.
Ketika nilai yang diendus adalah 1
rencana kueri akan terlihat seperti ini:
Dan ketika nilai yang diendus adalah 2
akan terlihat seperti ini:
Bagian buruk dari sniffing parameter dalam kasus ini terjadi ketika rencana kueri dibuat dengan mengendus 1
tetapi dieksekusi nanti dengan nilai 2
.
Anda dapat melihat bahwa Pencarian Kunci dijalankan 2352 kali. Pemindaian jelas akan menjadi pilihan yang lebih baik.
Untuk meringkas, saya akan mengatakan bahwa mengendus parameter adalah hal yang baik yang harus Anda coba wujudkan sebanyak mungkin dengan menggunakan parameter untuk kueri Anda. Kadang-kadang bisa salah dan dalam kasus itu kemungkinan besar karena data miring yang mengacaukan statistik Anda.
Pembaruan:
Berikut adalah kueri terhadap beberapa dmv yang dapat Anda gunakan untuk menemukan kueri apa yang paling mahal di sistem Anda. Ubah untuk memesan berdasarkan klausa untuk menggunakan kriteria yang berbeda pada apa yang Anda cari. Menurut saya TotalDuration
adalah tempat yang baik untuk memulai.
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
;