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

Bagaimana Pembaruan Otomatis pada Statistik Dapat Mempengaruhi Kinerja Kueri

Dalam posting saya sebelumnya, saya menjelajahi berbagai metode untuk melacak pembaruan otomatis ke statistik untuk menentukan apakah mereka memengaruhi kinerja kueri. Di paruh kedua posting saya menyertakan opsi, salah satunya adalah mengaktifkan pengaturan database Auto Update Statistics Asynchronous. Dalam posting ini, saya ingin melihat bagaimana kinerja kueri berubah ketika pembaruan otomatis terjadi sebelum eksekusi kueri, dan apa yang terjadi pada kinerja jika pembaruan tidak sinkron.

Penyiapan

Saya mulai dengan salinan database AdventureWorks2012, dan kemudian membuat salinan tabel SalesOrderHeader dengan lebih dari 200 juta baris menggunakan skrip ini. Tabel memiliki indeks berkerumun di SalesOrderID, dan indeks tidak berkerumun di ID Pelanggan, TanggalPesanan, SubTotal. [Catatan:jika Anda akan melakukan pengujian berulang, ambil cadangan database ini pada saat ini untuk menghemat waktu Anda]. Setelah memuat data dan membuat indeks nonclustered, saya memverifikasi jumlah baris dan menghitung berapa banyak baris (kurang-lebih) yang perlu dimodifikasi untuk menjalankan pembaruan otomatis.

SELECTOBJECT_NAME([p].[object_id]) [TableName],[si].[name] [IndexName],[au].[type_desc] [Type],[p].[rows] [RowCount], ([p].[rows]*.20) + 500 [UpdateThreshold],[au].total_pages [PageCount],(([au].[total_pages]*8)/1024)/1024 [TotalGB]FROM [sys ].[partitions] [p]JOIN [sys].[allocation_units] [au] ON [p].[partition_id] =[au].[container_id]JOIN [sys].[indexes] [si] pada [p] .[object_id] =[si].object_id dan [p].[index_id] =[si].[index_id]WHERE [p].[object_id] =OBJECT_ID(N'Sales.Big_SalesOrderHeader');


Big_SalesOrderHeader Informasi CIX dan NCI

Saya juga memverifikasi tajuk statistik saat ini untuk indeks:

DBCC SHOW_STATISTICS ('Sales.Big_SalesOrderHeader',[IX_Big_SalesOrderHeader_CustomerID_OrderDate_SubTotal]);


Statistik NCI:Saat Memulai

Saya kemudian membuat prosedur tersimpan yang akan saya gunakan untuk pengujian. Ini adalah prosedur langsung yang menanyakan Sales.Big_SalesOrderHeader, dan menggabungkan data penjualan menurut CustomerID dan OrderDate untuk dianalisis:

BUAT PROSEDUR Sales.usp_GetCustomerStats@CustomerID INT,@StartDate DATETIME,@EndDate DATETIMEASBEGIN SET NOCOUNT ON; SELECT CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate), COUNT([SalesOrderID]) sebagai Dihitung FROM [Sales].[Big_SalesOrderHeader] WHERE CustomerID =@CustomerID AND OrderDate BETWEEN @StartDate dan @EndDate GROUP BY CustomerID, DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate) ORDER BY DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate);END

Terakhir, sebelum menjalankan prosedur tersimpan, saya membuat sesi Acara yang Diperpanjang sehingga saya dapat melacak durasi kueri menggunakan sp_statement_starting dan sp_statement_completed. Saya juga menambahkan acara auto_stats, karena meskipun saya tidak mengharapkan pembaruan terjadi, saya ingin menggunakan definisi sesi yang sama ini nanti.

BUAT SESI ACARA [StatsUpdate_QueryPerf]ON SERVERADD EVENT sqlserver.auto_stats,TAMBAHKAN ACARA sqlserver.sp_statement_completed(SET collect_statement=(1)), ADD EVENT sqlserver.sp_statement_startingADD TARGET package0.event_file'(SET filename=\Nfile' StatsUpdate_QueryPerf.xel')DENGAN (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 DETIK,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=TIDAK ADA,preTRACK_CAUSALITYUjian 

Saya memulai sesi Acara yang Diperpanjang, dan kemudian menjalankan prosedur tersimpan beberapa kali, menggunakan ID Pelanggan yang berbeda:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]ON SERVERSTATE =START;GO EXEC Sales.usp_GetCustomerStats 11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11330, '01-01-2013 00:00:00.000', '31-01-2013 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11506, '2011-11-01 00:00:00.000', '2012-11 -30 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 17061, '01-01-2013 00:00:00.000', '31-01-2013 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11711, '2013-03- 01 00:00:00.000', '2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15131, '2013-02-01 00:00:00.000', '28-02-2013 23:59:59.997 'GOEXEC Sales.usp_GetCustomerStats 29837, '2012-10-01 00:00:00.000', '31-10-2012 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15750, '2013-03-01 00:00:00.000' , '2013-03-31 23:59:59,997'GO

Saya memverifikasi jumlah eksekusi, dan rencananya, dengan menanyakan cache prosedur:

SELECTOBJECT_NAME([st].[objectid]),[st].[text],[qs].[execution_count],[qs].[creation_time],[qs].[last_execution_time],[qs]. [min_worker_time],[qs].[max_worker_time],[qs].[min_logical_reads],[qs].[max_logical_reads],[qs].[min_elapsed_time],[qs].[max_elapsed_time],[qp].[query_plan ]DARI [sys].[dm_exec_query_stats] [qs]CROSS APPLY [sys].[dm_exec_sql_text]([qs].plan_handle) [st]CROSS APPLY [sys].[dm_exec_query_plan]([qs].plan_handle) [qp] DI MANA [st].[text] LIKE '%usp_GetCustomerStats%'DAN OBJECT_NAME([st].[objectid]) BUKAN NULL;


Rencanakan Cache:Saat Memulai


Rencana Kueri untuk Prosedur Tersimpan, menggunakan SQL Sentry Plan Explorer

Saya dapat melihat bahwa rencana tersebut dibuat pada 08-04-2014 18:59:39.850. Dengan paket dalam cache, saya menghentikan sesi Acara yang Diperpanjang:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]ON SERVERSTATE =STOP;

Selanjutnya saya menambahkan sekitar 47 juta baris data ke tabel menggunakan skrip ini, jauh di atas ambang batas yang diperlukan untuk membatalkan statistik saat ini. Setelah menambahkan data, saya memverifikasi jumlah baris dalam tabel:


Big_SalesOrderHeader CI:Setelah Data Dimuat

Sebelum saya menjalankan kembali prosedur tersimpan saya, saya memeriksa cache paket untuk memastikan tidak ada yang berubah, dan memverifikasi bahwa statistik belum diperbarui. Ingat, meskipun statistik tidak valid pada saat ini, statistik tidak akan diperbarui hingga kueri yang menggunakan statistik dijalankan (untuk referensi:Memahami Kapan Statistik Akan Diperbarui Secara Otomatis). Untuk langkah terakhir, saya memulai sesi Extended Events lagi, dan kemudian menjalankan prosedur tersimpan beberapa kali. Setelah eksekusi itu, saya memeriksa cache paket lagi:


Rencanakan Cache:Setelah Data Dimuat

Execution_count adalah 8 lagi, dan jika kita melihat pada create_time dari rencana, kita dapat melihatnya berubah menjadi 08-04-2014 19:32:52.913. Jika kita periksa rencananya, kita dapat melihat bahwa itu sama, meskipun rencana itu dikompilasi ulang:


Rencana Kueri untuk Prosedur Tersimpan, menggunakan SQL Sentry Plan Explorer

Analisis Keluaran Peristiwa yang Diperpanjang

Saya mengambil file Extended Events pertama – sebelum data dimuat – dan membukanya di SSMS, lalu menerapkan filter sehingga hanya pernyataan dari prosedur tersimpan yang terdaftar:


Output Acara yang Diperpanjang:Setelah Eksekusi SP Awal

Anda dapat melihat bahwa ada delapan (8) eksekusi prosedur tersimpan, dengan durasi kueri yang sedikit berbeda.

Saya mengambil file Extended Events kedua – setelah data dimuat – membukanya SSMS, dan memfilternya lagi sehingga hanya pernyataan dari stored procedure, serta event auto_stats, yang terdaftar:


Output Peristiwa yang Diperpanjang:Eksekusi SP Setelah Data Dimuat

Output terpotong, karena tidak semua diperlukan untuk menampilkan hasil utama. Entri yang disorot biru mewakili eksekusi pertama dari prosedur tersimpan, dan perhatikan bahwa ada beberapa langkah – pembaruan statistik adalah bagian dari eksekusi. Pernyataan SELECT dimulai (attach_activity_id.seq =3), dan pembaruan statistik kemudian dijalankan. Dalam contoh kami, kami sebenarnya memiliki pembaruan untuk tiga statistik. Setelah pembaruan terakhir selesai (attach_activity_id.seq =11), maka prosedur tersimpan dimulai dan selesai (attach_activity_id.seq =13 dan attach_activity_id.seq =14). Yang cukup menarik, ada kejadian sp_statement_starting kedua untuk prosedur tersimpan (mungkin yang pertama diabaikan), jadi total durasi untuk prosedur tersimpan dihitung tanpa pembaruan statistik.

Dalam skenario ini, statistik segera diperbarui secara otomatis – yaitu, ketika kueri yang menggunakan statistik yang tidak valid dijalankan – menyebabkan kueri berjalan lebih lama, meskipun durasi kueri berdasarkan peristiwa sp_statement_completed masih kurang dari 14000. Hasil akhirnya adalah bahwa ada tidak ada manfaat untuk kinerja kueri, karena rencananya persis sama sebelum dan sesudah pembaruan statistik. Dalam skenario ini, rencana kueri dan durasi eksekusi tidak berubah setelah lebih banyak data ditambahkan ke tabel, sehingga pembaruan statistik hanya menghambat kinerjanya. Sekarang mari kita lihat apa yang terjadi saat kita mengaktifkan opsi Auto Update Statistics Asynchronously.

Ujian, Versi 2

Kami mulai dengan mengembalikan ke cadangan yang saya ambil sebelum kami memulai tes pertama. Saya membuat ulang prosedur tersimpan dan kemudian mengubah opsi basis data untuk memperbarui statistik secara tidak sinkron:

GUNAKAN [master];GOALTER DATABASE [AdventureWorks2012_Big] AKTIFKAN AUTO_UPDATE_STATISTICS_ASYNC DENGAN NO_WAITGO

Saya memulai sesi Acara yang Diperpanjang, dan sekali lagi menjalankan prosedur tersimpan beberapa kali, menggunakan ID Pelanggan yang berbeda:

ALTER EVENT SESSION [StatsUpdate_QueryPerf]ON SERVERSTATE =START;GO EXEC Sales.usp_GetCustomerStats11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59,997'GOEXEC Sales.usp_GetCustomerStats11506, '2011-11-01 00:00:00.000', '30-11-2012 23 :59:59.997'GOEXEC Sales.usp_GetCustomerStats17061, '01-01-2013 00:00:00.000', '31-01-2013 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11711, '2013-03-01 00:00:00.000', '2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15750, '2013-03-01 00:00:00.000', '2013-03-31 23 :59:59,997'GO

Saya memverifikasi jumlah eksekusi, dan rencananya, dengan menanyakan cache prosedur:


Rencanakan Tembolok:Saat Mulai, Uji 2


Rencana Kueri untuk Prosedur Tersimpan, menggunakan SQL Sentry Plan Explorer

Untuk tes ini, rencananya dibuat pada 08-04-2014 21:15:55.490. Saya menghentikan sesi Acara yang Diperpanjang dan menambahkan lagi sekitar 47 juta baris data ke tabel, menggunakan kueri yang sama seperti sebelumnya.

Setelah data ditambahkan, saya memeriksa cache paket untuk memastikan tidak ada yang berubah, dan memverifikasi bahwa statistik belum diperbarui. Akhirnya, saya memulai sesi Acara yang Diperpanjang lagi, dan kemudian menjalankan prosedur tersimpan delapan kali lagi. Intip terakhir ke dalam cache rencana menunjukkan execution_count pada 16 dan create_time pada 08-04-2014 21:15:55.490. Execution_count dan create_time menunjukkan bahwa statistik belum diperbarui, karena rencana belum dihapus dari cache (jika ada, kita akan memiliki create_time dan execution_count 8 di kemudian hari).


Rencanakan Cache:Setelah Data Dimuat, Uji 2

Jika kita membuka output Extended Events dari setelah data dimuat di SSMS, dan sekali lagi memfilter sehingga kita hanya melihat pernyataan dari prosedur tersimpan, serta event auto_stats, kita menemukan ini (perhatikan bahwa output dipecah menjadi dua tangkapan layar):


Extended Events Output:Uji 2, Eksekusi SP Setelah Data Dimuat, bagian I


Extended Events Output:Test 2, Eksekusi SP Setelah Data Dimuat, bagian II

Peristiwa untuk eksekusi panggilan pertama dari prosedur tersimpan disorot dengan warna biru – dimulai pada 08-04-2014 21:54:14.9480607 dan ada tujuh (7) peristiwa. Perhatikan bahwa ada tiga (3) peristiwa auto_stats, tetapi tidak ada yang benar-benar selesai, seperti yang kita lihat saat opsi Auto Update Statistics Asynchronously dinonaktifkan. Anda akan melihat bahwa pembaruan otomatis segera dimulai untuk salah satu statistik (2014-04-08 21:54:14.9481288), dan tiga peristiwa itu memiliki teks merah 'Pembaruan Statistik #1' di sebelahnya. Pembaruan statistik itu selesai pada 08-04-2014 21:54:16.5392219, hanya kurang dari dua detik setelah dimulai, tetapi setelah semua eksekusi prosedur lainnya selesai. Inilah sebabnya mengapa execution_count dari sys.dm_exec_query_stats menunjukkan 16. Dari output XE, kita dapat melihat bahwa statistik lainnya diperbarui kemudian selesai (Stat Update #2 dan Stat Update #3). Semua pembaruan tidak sinkron dengan eksekusi prosedur tersimpan awal.

Ringkasan

Seperti yang Anda lihat, pembaruan otomatis pada statistik berpotensi memengaruhi kinerja kueri secara negatif. Tingkat dampak akan tergantung pada jumlah data yang harus dibaca untuk memperbarui statistik, dan sumber daya sistem. Dalam beberapa kasus, kinerja kueri hanya meningkat beberapa milidetik dan kemungkinan besar tidak terlihat oleh pengguna. Di lain waktu, durasinya dapat meningkat secara dramatis, yang kemudian memengaruhi pengalaman pengguna akhir. Jika rencana kueri tidak berubah setelah pembaruan statistik, sebaiknya pertimbangkan untuk mengaktifkan opsi Pembaruan Otomatis Statistik Secara Asinkron, untuk mengurangi dampak pada kinerja kueri.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tampilan SQL:Bagaimana cara bekerja dengan Tampilan dalam SQL?

  2. Parsing nilai default parameter menggunakan PowerShell – Bagian 2

  3. Mitos Kinerja :Indeks Clustered vs. Non-Clustered

  4. Menggunakan Tabel JavaFX untuk Mengatur Data

  5. SQL PILIH MIN