Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Beberapa Paket untuk Kueri Identik

Saya sering melihat orang berjuang dengan SQL Server ketika mereka melihat dua rencana eksekusi yang berbeda untuk apa yang mereka yakini sebagai kueri yang sama. Biasanya ini ditemukan setelah pengamatan lain, seperti waktu eksekusi yang sangat berbeda. Saya katakan mereka percaya itu adalah pertanyaan yang sama karena, kadang-kadang, dan kadang-kadang tidak.

Salah satu kasus yang paling umum adalah ketika mereka menguji kueri di SSMS dan mendapatkan paket yang berbeda dari yang mereka dapatkan dari aplikasi mereka. Ada dua faktor yang berpotensi berperan di sini (yang juga bisa relevan jika perbandingannya BUKAN antara aplikasi dan SSMS):

  1. Aplikasi hampir selalu memiliki SET yang berbeda pengaturan dari SSMS (ini adalah hal-hal seperti ARITHABORT , ANSI_NULLS dan QUOTED_IDENTIFIER ). Ini memaksa SQL Server untuk menyimpan dua paket secara terpisah; Erland Sommarskog telah membahas ini dengan sangat rinci dalam artikelnya, Lambat dalam Aplikasi, Cepat di SSMS?
  2. Parameter yang digunakan oleh aplikasi ketika salinan rencana pertama kali dikompilasi bisa sangat berbeda, dan mengarah ke rencana yang berbeda, daripada yang digunakan pertama kali kueri dijalankan dari SSMS – ini dikenal sebagai parameter sniffing . Erland berbicara tentang itu secara mendalam juga, dan saya tidak akan memuntahkan rekomendasinya, tetapi rangkum dengan mengingatkan Anda bahwa menguji kueri aplikasi di SSMS tidak selalu berguna, karena sangat tidak mungkin untuk menjadi tes apel-ke-apel.

Ada beberapa skenario lain yang sedikit lebih tidak jelas yang saya kemukakan dalam pembicaraan tentang Kebiasaan Buruk &Praktik Terbaik. Ini adalah kasus di mana paket tidak berbeda, tetapi ada banyak salinan paket yang sama yang membuat cache paket membengkak. Saya pikir saya harus menyebutkannya di sini karena mereka selalu mengejutkan banyak orang.

cAsE dan spasi itu penting

SQL Server meng-hash teks kueri ke dalam format biner, yang berarti bahwa setiap karakter dalam teks kueri sangat penting. Mari kita ambil pertanyaan sederhana berikut:

USE AdventureWorks2014;
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
GO
SELECT StoreID FROM Sales.Customer;
GO -- original query
GO
SELECT  StoreID FROM Sales.Customer;
GO ----^---- extra space
GO
SELECT storeid FROM sales.customer;
GO ---- lower case names
GO
select StoreID from Sales.Customer;
GO ---- lower case keywords
GO

Ini menghasilkan hasil yang sama persis, jelas, dan menghasilkan rencana yang sama persis. Namun, jika kita melihat apa yang kita miliki di cache paket:

SELECT t.[text], p.size_in_bytes, p.usecounts
 FROM sys.dm_exec_cached_plans AS p
 CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
 WHERE LOWER(t.[text]) LIKE N'%sales'+'.'+'customer%';

Hasilnya sangat disayangkan:

Jadi, dalam hal ini, jelas bahwa case dan whitespace sangat penting. Saya membicarakan hal ini secara lebih rinci Mei lalu.

Referensi skema penting

Saya telah membuat blog sebelumnya tentang pentingnya menentukan awalan skema saat mereferensikan objek apa pun, tetapi pada saat itu saya tidak sepenuhnya menyadari bahwa itu juga memiliki implikasi cache rencana.

Mari kita lihat kasus yang sangat sederhana di mana kita memiliki dua pengguna dengan skema default yang berbeda, dan mereka menjalankan teks kueri yang sama persis, gagal mereferensikan objek dengan skemanya:

USE AdventureWorks2014;
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
GO
 
CREATE USER SQLPerf1 WITHOUT LOGIN WITH DEFAULT_SCHEMA = Sales;
CREATE USER SQLPerf2 WITHOUT LOGIN WITH DEFAULT_SCHEMA = Person;
GO
 
CREATE TABLE dbo.AnErrorLog(id INT);
GRANT SELECT ON dbo.AnErrorLog TO SQLPerf1, SQLPerf2;
GO
 
EXECUTE AS USER = N'SQLPerf1';
GO
SELECT id FROM AnErrorLog;
GO
REVERT;
GO
EXECUTE AS USER = N'SQLPerf2';
GO
SELECT id FROM AnErrorLog;
GO
REVERT;
GO

Sekarang, jika kita melihat cache rencana, kita dapat menarik sys.dm_exec_plan_attributes untuk melihat dengan tepat mengapa kami mendapatkan dua paket berbeda untuk kueri yang identik:

SELECT t.[text], p.size_in_bytes, p.usecounts, 
  [schema_id] = pa.value, 
  [schema] = s.name
FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
CROSS APPLY sys.dm_exec_plan_attributes(p.plan_handle) AS pa
INNER JOIN sys.schemas AS s ON s.[schema_id] = pa.value
WHERE t.[text] LIKE N'%AnError'+'Log%' 
AND pa.attribute = N'user_id';

Hasil:

Dan jika Anda menjalankan semuanya lagi tetapi tambahkan dbo. awalan untuk kedua kueri, Anda akan melihat hanya ada satu paket yang digunakan dua kali. Ini menjadi argumen yang sangat menarik untuk selalu merujuk objek sepenuhnya.

ATUR redux pengaturan

Sebagai catatan tambahan, Anda dapat menggunakan pendekatan serupa untuk menentukan apakah SET pengaturan berbeda untuk dua atau lebih versi kueri yang sama. Dalam hal ini kami sedang menyelidiki kueri yang terlibat dengan beberapa paket yang dihasilkan oleh panggilan berbeda ke prosedur tersimpan yang sama, tetapi Anda juga dapat mengidentifikasinya dengan teks kueri atau hash kueri.

SELECT p.plan_handle, p.usecounts, p.size_in_bytes, 
  set_options = MAX(a.value)
FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
CROSS APPLY sys.dm_exec_plan_attributes(p.plan_handle) AS a
WHERE t.objectid = OBJECT_ID(N'dbo.procedure_name')
AND a.attribute = N'set_options'
GROUP BY p.plan_handle, p.usecounts, p.size_in_bytes;

Jika Anda memiliki beberapa hasil di sini maka Anda akan melihat nilai yang berbeda untuk set_options (yang merupakan bitmask). Itu baru permulaan; Saya akan membahasnya di sini dan memberi tahu Anda bahwa Anda dapat menentukan rangkaian opsi apa yang diaktifkan untuk setiap paket dengan membongkar nilai sesuai dengan bagian "Mengevaluasi Opsi Set" di sini. Ya, saya sangat malas.

Kesimpulan

Ada beberapa alasan mengapa Anda mungkin melihat paket yang berbeda untuk kueri yang sama (atau menurut Anda kueri yang sama). Dalam kebanyakan kasus, Anda dapat mengisolasi penyebabnya dengan cukup mudah; tantangannya sering kali mengetahui untuk mencarinya terlebih dahulu. Dalam posting saya berikutnya, saya akan berbicara tentang subjek yang sedikit berbeda:mengapa database yang dipulihkan ke server "identik" dapat menghasilkan paket yang berbeda untuk kueri yang sama.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara menganalisis kesehatan indeks basis data

  2. Memperbaiki Kehilangan Data Menggunakan Pengiriman Log dengan Pemulihan Tertunda

  3. Apa Perbedaan Antara RANK dan DENSE_RANK dalam SQL?

  4. Apakah Basis Data Anda Terjamin? Pikirkan lagi

  5. Notasi Barker