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

Parameterisasi Sederhana dan Rencana Trivial — Bagian 1

Ini adalah bagian pertama dari seri tentang parameterisasi sederhana dan rencana sepele . Kedua fitur kompilasi ini terkait erat dan memiliki tujuan yang sama. Target kinerja dan efisiensi untuk beban kerja sering kali mengirimkan pernyataan sederhana.

Terlepas dari nama "sederhana" dan "sepele", keduanya memiliki perilaku halus dan detail implementasi yang dapat membuat cara kerjanya sulit untuk dipahami. Seri ini tidak membahas dasar-dasarnya terlalu lama, tetapi berkonsentrasi pada aspek-aspek yang kurang terkenal yang kemungkinan akan menjebak para profesional basis data yang paling berpengalaman sekalipun.

Di bagian pertama ini, setelah pengenalan singkat, saya melihat efek dari parameterisasi sederhana pada cache paket.

Parameterisasi Sederhana

Hampir selalu lebih baik untuk mengukur parameter secara eksplisit pernyataan, daripada mengandalkan server untuk melakukannya. Menjadi eksplisit memberi Anda kendali penuh atas semua aspek proses parameterisasi, termasuk di mana parameter digunakan, jenis data yang tepat digunakan, dan kapan rencana digunakan kembali.

Sebagian besar klien dan driver menyediakan cara khusus untuk menggunakan parameterisasi eksplisit. Ada juga opsi seperti sp_executesql , prosedur tersimpan, dan fungsi.

Saya tidak akan membahas masalah terkait parameter sniffing atau injeksi SQL karena, meskipun penting, mereka bukan fokus dari seri ini. Namun, Anda harus menulis kode dengan keduanya berada di depan pikiran Anda.

Untuk aplikasi lawas atau kode pihak ketiga lainnya yang tidak dapat dengan mudah diubah, parameterisasi eksplisit mungkin tidak selalu dapat dilakukan. Anda mungkin dapat mengatasi beberapa kendala dengan menggunakan panduan rencana template. Bagaimanapun, itu akan menjadi beban kerja yang tidak biasa yang tidak mengandung setidaknya beberapa pernyataan berparameter di sisi server.

Rencana Shell

Ketika SQL Server 2005 memperkenalkan Parameterisasi Paksa , parameterisasi otomatis . yang ada fitur diubah namanya menjadi Parameterisasi Sederhana . Meskipun ada perubahan dalam terminologi, parameterisasi sederhana bekerja sama dengan parameterisasi otomatis selalu melakukannya:SQL Server mencoba mengganti nilai literal konstan dalam pernyataan ad hoc dengan penanda parameter. Tujuannya adalah untuk mengurangi kompilasi dengan meningkatkan penggunaan kembali paket yang di-cache.

Mari kita lihat contoh, menggunakan database Stack Overflow 2010 pada SQL Server 2019 CU 14. Kompatibilitas database diatur ke 150, dan ambang biaya untuk paralelisme diatur ke 50 untuk menghindari paralelisme untuk saat ini:

EXECUTE sys.sp_configure
    @configname = 'show advanced options',
    @configvalue = 1;
RECONFIGURE;
GO
EXECUTE sys.sp_configure
    @configname = 'cost threshold for parallelism',
    @configvalue = 50;
RECONFIGURE;

Contoh kode:

-- Clear the cache of plans for this database
ALTER DATABASE SCOPED CONFIGURATION 
    CLEAR PROCEDURE_CACHE;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 2521;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 2827;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3144;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3151;
GO

Pernyataan-pernyataan tersebut menampilkan predikat yang hanya berbeda dalam nilai literal konstannya. SQL Server berhasil menerapkan parameterisasi sederhana , menghasilkan rencana parameter. Paket berparameter tunggal digunakan empat kali seperti yang dapat kita lihat dengan menanyakan cache paket:

SELECT
    CP.usecounts,
    CP.cacheobjtype,
    CP.objtype,
    CP.size_in_bytes,
    ST.[text],
    QP.query_plan
FROM sys.dm_exec_cached_plans AS CP
OUTER APPLY sys.dm_exec_sql_text (CP.plan_handle) AS ST
OUTER APPLY sys.dm_exec_query_plan (CP.plan_handle) AS QP
WHERE 
    ST.[text] NOT LIKE '%dm_exec_cached_plans%'
    AND ST.[text] LIKE '%DisplayName%Users%'
ORDER BY 
    CP.usecounts ASC;

Hasilnya menunjukkan Adhoc rencanakan entri cache untuk setiap pernyataan asli dan satu Disiapkan rencana:

Empat paket adhoc dan satu paket siap

Disiapkan pernyataan mirip dengan prosedur tersimpan, dengan parameter disimpulkan dari nilai literal yang ditemukan di Adhoc penyataan. Saya menyebutkan ini sebagai model mental yang berguna ketika memikirkan proses parameterisasi sisi server.

Perhatikan bahwa SQL Server menyimpan keduanya teks asli dan bentuk parameter. Ketika parameterisasi sederhana berhasil, rencana yang terkait dengan teks asli adalah Adhoc dan tidak berisi rencana eksekusi penuh. Sebaliknya, paket yang di-cache adalah shell dengan sangat sedikit selain pointer ke Disiapkan rencana parameter.

Representasi XML dari rencana shell berisi teks seperti:

<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.539" Build="15.0.4188.2">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple 
  StatementText="SELECT U.DisplayName&#xD;&#xA;FROM dbo.Users AS U &#xD;&#xA;WHERE U.Reputation = 3151"
  StatementId="1" 
  StatementCompId="1" 
  StatementType="SELECT" 
  RetrievedFromCache="true" 
  ParameterizedPlanHandle="0x0600050090C8321CE04B4B079E01000001000000000000000000000000000000000000000000000000000000" 
  ParameterizedText="(@1 smallint)SELECT [U].[DisplayName] FROM [dbo].[Users] [U] WHERE [U].[Reputation]=@1" />
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>

Itu seluruh rencana. ParameterizedPlanHandle poin dari Adhoc shell ke rencana parameter penuh. Nilai pegangannya sama untuk keempat paket shell.

Rencana Rintisan

Paket Shell lebih kecil dari paket lengkap yang dikompilasi—16KB, bukan 40KB dalam contoh. Ini masih dapat menambah jumlah memori yang signifikan jika Anda memiliki banyak pernyataan menggunakan parameterisasi sederhana atau banyak nilai parameter yang berbeda. Sebagian besar instance SQL Server tidak begitu dibanjiri memori sehingga mereka dapat menyia-nyiakannya seperti ini. Paket shell dianggap sangat sekali pakai oleh SQL Server, tetapi menemukan dan menghapusnya menghabiskan sumber daya dan dapat menjadi bahan perdebatan.

Kami dapat mengurangi konsumsi memori total untuk paket shell dengan mengaktifkan opsi optimalkan untuk beban kerja ad hoc.

EXECUTE sys.sp_configure
    @configname = 'show advanced options',
    @configvalue = 1;
RECONFIGURE;
GO
EXECUTE sys.sp_configure
    @configname = 'optimize for ad hoc workloads',
    @configvalue = 1;
RECONFIGURE;

Ini men-cache sebuah rintisan kecil saat pertama kali pernyataan ad hoc ditemukan alih-alih shell. Rintisan berfungsi sebagai penanda sehingga server dapat mengingat teks pernyataan yang telah dilihat sebelumnya. Setelah menemukan teks yang sama untuk kedua kalinya, kompilasi dan caching dilanjutkan seolah-olah mengoptimalkan beban kerja ad hoc tidak diaktifkan.

Menjalankan kembali contoh dengan mengoptimalkan beban kerja ad hoc diaktifkan menunjukkan efek pada cache paket.

Ringanan Rencana Terkompilasi

Tidak ada rencana yang di-cache untuk pernyataan ad-hoc, hanya sebuah rintisan. Tidak ada ParameterizedPlanHandle penunjuk ke Disiapkan rencana, meskipun rencana parameter lengkap adalah di-cache.

Menjalankan batch pengujian untuk kedua kalinya (tanpa mengosongkan cache paket) memberikan hasil yang sama seperti saat mengoptimalkan beban kerja ad hoc tidak diaktifkan—empat Adhoc rencana shell menunjuk ke Disiapkan rencana.

Sebelum melanjutkan, setel ulang optimalkan untuk beban kerja ad hoc pengaturan ke nol:

EXECUTE sys.sp_configure
    @configname = 'optimize for ad hoc workloads',
    @configvalue = 0;
RECONFIGURE;

Batas Ukuran Cache Rencana

Apakah shell rencana atau stub rencana digunakan, masih ada kerugian untuk semua Adhoc ini entri cache. Saya telah menyebutkan penggunaan memori total, tetapi setiap cache paket juga memiliki jumlah maksimum dari entri. Bahkan jika penggunaan memori total tidak menjadi perhatian, jumlahnya mungkin saja.

Batas dapat dinaikkan dengan bendera jejak terdokumentasi 174 (jumlah entri) dan bendera jejak 8032 (ukuran total). Tergantung pada beban kerja dan permintaan memori lainnya, ini mungkin bukan solusi terbaik. Lagi pula, itu hanya berarti menyimpan lebih banyak Adhoc bernilai rendah dalam cache rencana, menghilangkan memori dari kebutuhan lain.

Hanya Caching Paket yang Disiapkan

Jika beban kerja jarang mengeluarkan kumpulan ad-hoc dengan tepatnya teks pernyataan yang sama, shell rencana caching atau stub rencana adalah pemborosan sumber daya. Itu menghabiskan memori dan dapat menyebabkan pertengkaran saat SQL Plans penyimpanan cache (CACHESTORE_SQLCP ) perlu dikecilkan agar sesuai dengan batas yang dikonfigurasi.

Idealnya adalah membuat parameter batch ad-hoc yang masuk, tetapi hanya cache versi yang diparameterisasi. Ada biaya untuk melakukan ini, karena pernyataan ad-hoc di masa mendatang perlu diparameterisasi sebelum dapat dicocokkan dengan rencana cache yang diparameterisasi. Di sisi lain, ini akan tetap terjadi karena kami telah menyatakan tepat kecocokan tekstual jarang terjadi untuk beban kerja target.

Untuk beban kerja yang diuntungkan dari parameterisasi sederhana, tetapi bukan caching Adhoc entri, ada beberapa opsi.

Tanda Jejak Tidak Berdokumen

Opsi pertama adalah mengaktifkan tanda jejak tidak berdokumen 253. Ini mencegah cache Adhoc rencana sepenuhnya. Itu tidak hanya membatasi jumlah rencana tersebut, atau mencegah mereka dari "tinggal" di cache, seperti yang kadang-kadang disarankan.

Trace flag 253 dapat diaktifkan di tingkat sesi—membatasi efeknya hanya pada koneksi itu—atau lebih luas lagi sebagai flag global atau start-up. Ini juga berfungsi sebagai petunjuk kueri, tetapi menggunakan itu mencegah parameterisasi sederhana, yang akan menjadi kontraproduktif di sini. Ada sebagian daftar hal-hal yang mencegah parameterisasi sederhana di Makalah Teknis Microsoft, Caching Rencana, dan Kompilasi Ulang di SQL Server 2012.

Dengan bendera jejak 253 aktif sebelum kumpulan dikompilasi , hanya Disiapkan pernyataan di-cache:

ALTER DATABASE SCOPED CONFIGURATION 
    CLEAR PROCEDURE_CACHE;
GO
-- Do not cache ad-hoc plans
DBCC TRACEON (253);
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 2521;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 2827;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3144;
GO
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3151;
GO
-- Cache ad-hoc plans again
DBCC TRACEOFF (253);
GO

Kueri cache paket hanya mengonfirmasi Disiapkan pernyataan di-cache dan digunakan kembali.

Hanya pernyataan yang disiapkan yang di-cache

Batch yang Tidak Dapat Di-cache

Opsi kedua adalah menyertakan pernyataan yang menandai seluruh kumpulan sebagai tidak dapat disimpan dalam cache . Pernyataan yang sesuai seringkali terkait dengan keamanan atau sensitif dalam beberapa hal.

Ini mungkin terdengar tidak praktis, tetapi ada beberapa mitigasi. Pertama, pernyataan sensitif tidak perlu dieksekusi—itu hanya perlu hadir . Ketika kondisi itu terpenuhi, pengguna yang menjalankan batch bahkan tidak memerlukan izin untuk mengeksekusi pernyataan sensitif. Perhatikan baik-baik, efeknya terbatas pada kumpulan yang berisi pernyataan sensitif.

Dua pernyataan sensitif yang sesuai dan contoh penggunaan ditunjukkan di bawah ini (dengan pernyataan pengujian sekarang dalam satu kumpulan):

ALTER DATABASE SCOPED CONFIGURATION 
    CLEAR PROCEDURE_CACHE;
GO
-- Prevent caching of all statements in this batch.
-- Neither KEY nor CERTIFICATE need to exist.
-- No special permissions are needed.
-- GOTO is used to ensure the statements are not executed.
GOTO Start
    OPEN SYMMETRIC KEY Banana 
        DECRYPTION BY CERTIFICATE Banana;
Start:
 
/* Another way to achieve the same effect without GOTO
IF 1 = 0
BEGIN
    CREATE APPLICATION ROLE Banana 
    WITH PASSWORD = '';
END;
*/
 
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 2521;
 
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 2827;
 
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3144;
 
SELECT U.DisplayName
FROM dbo.Users AS U 
WHERE U.Reputation = 3151;
GO

Disiapkan rencana yang dibuat dengan parameterisasi sederhana masih di-cache dan digunakan kembali meskipun kumpulan induk ditandai sebagai tidak dapat di-cache.

Hanya pernyataan yang disiapkan yang di-cache

Tidak ada solusi yang ideal, tetapi hingga Microsoft menyediakan solusi yang terdokumentasi dan didukung untuk masalah ini, itu adalah opsi terbaik yang saya ketahui.

Akhir Bagian 1

Ada lebih banyak alasan untuk membahas topik ini. Bagian dua akan mencakup tipe data yang ditetapkan saat parameterisasi sederhana dipekerjakan.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bekerja dengan JavaFX Chart API

  2. Aljabar Relasional

  3. Efek Samping yang Tidak Diinginkan – Sesi Tidur Memegang Kunci

  4. ScaleGrid Terpilih untuk Program Penghargaan Cloud 2017-2018

  5. Parameter Mengendus Primer