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

Apa dampak dari opsi kursor yang berbeda?

Saya telah menulis beberapa kali tentang menggunakan kursor dan bagaimana, dalam banyak kasus, lebih efisien untuk menulis ulang kursor Anda menggunakan logika berbasis set.

Namun, saya realistis.

Saya tahu bahwa ada kasus di mana kursor "diperlukan" - Anda perlu memanggil prosedur tersimpan lain atau mengirim email untuk setiap baris, Anda melakukan tugas pemeliharaan terhadap setiap database, atau Anda menjalankan tugas satu kali yang hanya tidak layak menginvestasikan waktu untuk mengonversi ke berbasis set.

Bagaimana (mungkin) Anda melakukannya hari ini

Terlepas dari alasan Anda masih menggunakan kursor, setidaknya Anda harus berhati-hati untuk tidak menggunakan opsi default yang cukup mahal. Kebanyakan orang memulai kursor mereka seperti ini:

DECLARE c CURSOR FOR 
  SELECT whatever FROM ...

Sekarang sekali lagi, untuk tugas ad-hoc, satu kali, ini mungkin baik-baik saja. Tapi ada…

Cara lain untuk melakukannya

Saya ingin menjalankan beberapa tes menggunakan default dan membandingkannya dengan opsi kursor yang berbeda seperti LOCAL , STATIC , READ_ONLY dan FAST_FORWARD . (Ada banyak pilihan, tetapi ini adalah yang paling umum digunakan karena dapat diterapkan pada jenis operasi kursor paling umum yang digunakan orang.) Saya tidak hanya ingin menguji kecepatan mentah dari beberapa kombinasi berbeda, tetapi juga berdampak pada tempdb dan memori, baik setelah restart layanan dingin dan dengan cache hangat.

Kueri yang saya putuskan untuk dimasukkan ke kursor adalah kueri yang sangat sederhana terhadap sys.objects , dalam database sampel AdventureWorks2012. Ini mengembalikan 318.500 baris di sistem saya (sistem 2-inti yang sangat sederhana dengan RAM 4GB):

SELECT c1.[object_id] 
  FROM sys.objects AS c1
  CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2;

Kemudian saya membungkus kueri ini dalam kursor dengan berbagai opsi (termasuk default) dan menjalankan beberapa tes, mengukur Total Server Memory, halaman yang dialokasikan ke tempdb (menurut sys.dm_db_task_space_usage dan/atau sys.dm_db_session_space_usage ), dan durasi total. Saya juga mencoba mengamati pertentangan tempdb menggunakan skrip dari Glenn Berry dan Robert Davis, tetapi pada sistem remeh saya, saya tidak dapat mendeteksi pertentangan apa pun. Tentu saja saya juga menggunakan SSD dan sama sekali tidak ada yang berjalan di sistem, jadi ini mungkin hal-hal yang ingin Anda tambahkan ke pengujian Anda sendiri jika tempdb lebih cenderung menjadi hambatan.

Jadi pada akhirnya kueri terlihat seperti ini, dengan kueri diagnostik dibumbui pada titik yang tepat:

DECLARE @i INT = 1;
 
DECLARE c CURSOR
-- LOCAL
-- LOCAL STATIC
-- LOCAL FAST_FORWARD
-- LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
  SELECT c1.[object_id] 
    FROM sys.objects AS c1
    CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2
    ORDER BY c1.[object_id];
 
OPEN c;
FETCH c INTO @i;
 
WHILE (@@FETCH_STATUS = 0)
BEGIN
  SET @i += 1; -- meaningless operation
  FETCH c INTO @i;
END
 
CLOSE c;
DEALLOCATE c;

Hasil

    Durasi

    Bisa dibilang ukuran yang paling penting dan umum adalah, "berapa lama waktu yang dibutuhkan?" Yah, butuh hampir lima kali lebih lama untuk menjalankan kursor dengan opsi default (atau hanya dengan LOCAL ditentukan), dibandingkan dengan menentukan STATIC atau FAST_FORWARD :

    Memori

    Saya juga ingin mengukur memori tambahan yang akan diminta SQL Server saat memenuhi setiap jenis kursor. Jadi saya cukup memulai ulang sebelum setiap tes cache dingin, mengukur penghitung kinerja Total Server Memory (KB) sebelum dan sesudah setiap tes. Kombinasi terbaik di sini adalah LOCAL FAST_FORWARD :

    penggunaan tempdb

    Hasil ini mengejutkan saya. Karena definisi kursor statis berarti ia menyalin seluruh hasil ke tempdb, dan sebenarnya dinyatakan dalam sys.dm_exec_cursors sebagai SNAPSHOT , saya berharap hit pada halaman tempdb lebih tinggi dengan semua varian statis kursor. Ini tidak terjadi; lagi kita melihat sekitar 5X hit pada penggunaan tempdb dengan kursor default dan yang hanya memiliki LOCAL ditentukan:

Kesimpulan

Selama bertahun-tahun saya telah menekankan bahwa opsi berikut harus selalu ditentukan untuk kursor Anda:

LOCAL STATIC READ_ONLY FORWARD_ONLY

Mulai saat ini, hingga saya memiliki kesempatan untuk menguji permutasi lebih lanjut atau menemukan kasus yang bukan merupakan opsi tercepat, saya akan merekomendasikan hal berikut:

LOCAL FAST_FORWARD

(Selain itu, saya juga menjalankan tes dengan menghilangkan LOCAL pilihan, dan perbedaannya dapat diabaikan.)

Meskipun demikian, ini belum tentu benar untuk *semua* kursor. Dalam hal ini, saya hanya berbicara tentang kursor di mana Anda hanya membaca data dari kursor, dalam arah maju saja, dan Anda tidak memperbarui data yang mendasarinya (baik dengan kunci atau menggunakan WHERE CURRENT OF ). Itu adalah ujian untuk hari lain.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Membuat Model Lebih Lanjut Dengan Status Pengguna, Utas, dan Posting

  2. Statistik Penantian Lutut :PAGEIOLATCH_SH

  3. Dasar-dasar ekspresi tabel, Bagian 3 – Tabel turunan, pertimbangan pengoptimalan

  4. Pulihkan Database WordPress Anda dengan WP-CLI

  5. Jatuhkan vs Potong dalam SQL