it-swarm.asia

SQL: Apa yang memperlambat INSERT jika bukan CPU atau IO?

Kami memiliki database untuk produk yang berat-menulis. Kami baru saja membeli mesin server baru dengan SSD untuk membantu. Yang mengejutkan kami, pemasangannya tidak lebih cepat dari pada mesin lama kami dengan penyimpanan yang jauh lebih lambat. Selama benchmarking kami perhatikan bahwa tingkat IO yang ditunjukkan oleh proses SQL Server sangat rendah.

Misalnya, saya menjalankan skrip yang ditemukan pada halaman ini , kecuali bahwa saya menambahkan BEGIN TRAN dan COMMIT di sekitar loop. Paling-paling saya bisa melihat penggunaan disk mencapai 7Mb/s, sementara CPU hampir tidak menyentuh 5%. Server telah menginstal 64Gb dan menggunakan 10. Waktu total berjalan adalah 2 menit 15 detik untuk panggilan pertama turun menjadi sekitar 1 menit untuk panggilan berikutnya. Basis data sedang dalam pemulihan sederhana dan tidak digunakan selama pengujian. Saya menjatuhkan meja di antara setiap panggilan.

Mengapa skrip sederhana ini begitu lambat? Perangkat kerasnya hampir tidak digunakan sama sekali. Kedua alat pembandingan disk khusus dan SQLIO menunjukkan bahwa SSD berkinerja benar dengan kecepatan hingga 500Mb/dtk untuk membaca dan menulis. Saya mengerti bahwa menulis acak lebih lambat dari menulis berurutan, tapi saya berharap insert sederhana seperti ini, ke tabel tanpa pengindeksan berkelompok, menjadi jauh lebih cepat.

Pada akhirnya skenario kami jauh lebih kompleks, tetapi saya merasa perlu memahami kasus sederhana terlebih dahulu. Singkatnya aplikasi kita menghapus data lama, kemudian menggunakan SqlBulkCopy untuk menyalin data baru ke staging tables, melakukan beberapa penyaringan, dan akhirnya menggunakan MERGE dan/atau INSERT INTO tergantung pada kasus untuk menyalin data ke tabel akhir.

-> EDIT 1: Saya mengikuti prosedur yang ditautkan oleh Martin Smith, dan saya mendapat hasil sebagai berikut:

[Wait Type]  [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)]
NETWORK_IO          5008              46735                 46587        148
LOGBUFFER           901               5994                  5977         17
PAGELATCH_UP        40                866                   865          1
SOS_SCHEDULER_YIELD 53279             219                   121          98
WRITELOG            5                 145                   145          0
PAGEIOLATCH_UP      4                 58                    58           0
LATCH_SH            5                 0                     0            0

Saya merasa aneh NETWORK_IO mengambil sebagian besar waktu, mengingat tidak ada hasil untuk ditampilkan dan tidak ada data untuk ditransfer di mana pun selain ke file SQL. Apakah tipe NETWORK_IO mencakup semua IO?

-> EDIT 2: Saya membuat disk 20Gb RAM dan memasang basis data dari sana. Waktu terbaik yang saya miliki di SSD adalah 48 detik, dengan RAM = disk itu turun ke 37 detik. NETWORK_IO masih menunggu terbesar. Kecepatan tulis maksimum ke disk RAM sekitar 250Mb/s sementara masih bisa melakukan multi gigabytes per detik. Masih tidak menggunakan banyak CPU, jadi apa yang menahan SQL?

20
Djof

Saya tahu ini adalah pertanyaan lama tetapi ini mungkin masih membantu para pencari dan ini adalah masalah yang muncul sesekali.

Alasan utama mengapa Anda menekan langit-langit kinerja tanpa Anda melihat hambatan sumber daya adalah karena Anda telah mencapai batas apa yang mungkin untuk diproses dalam satu thread tunggal sesi. Loop tidak diproses secara paralel, tetapi semua sisipan dilakukan secara seri.

Dalam kasus saya, dibutuhkan 36 detik untuk memasukkan 3 juta baris. Itu berarti 36/30000000 = 0,000012 detik per baris. Itu cukup cepat. Di sistem saya, hanya dibutuhkan 0,000012 untuk melalui semua langkah yang diperlukan.

Satu-satunya cara untuk menyelesaikannya lebih cepat adalah memulai sesi kedua secara paralel.

Jika saya memulai 2 sesi secara paralel, keduanya melakukan 15 juta sisipan. Keduanya selesai dalam 18 detik. Saya dapat meningkatkan skala, tetapi pengaturan pengujian saya saat ini mencapai 95% cpu dengan dua sesi paralel, jadi melakukan 3 akan memusingkan hasilnya karena saya akan mengalami hambatan CPU.

Jika saya memulai 2 sesi paralel, keduanya memasukkan 3 juta baris, keduanya selesai dalam 39 detik. jadi sekarang 6 juta baris dalam 39 detik.

Oke, itu masih meninggalkan kita dengan menunggu NETWORK_IO muncul.

Tunggu NETWORK_IO ditambahkan oleh fakta bahwa Anda menggunakan peristiwa yang diperluas untuk melacaknya. Dalam kasus saya, insert membutuhkan waktu 36 detik (rata-rata). Saat menggunakan cara acara yang diperluas (dari tautan di atas di komentar pertama) inilah yang terdaftar:

Wait Type             Wait Count  Total Wait Time (ms) Total Resource Wait Time (ms) Total Signal Wait Time (ms)
NETWORK_IO            3455        68808                68802                         6
PAGEIOLATCH_SH        3           64                   64                            0
PAGEIOLATCH_UP        12          58                   58                            0
WRITE_COMPLETION      8           15                   15                            0
WRITELOG              3           9                    9                             0
PAGELATCH_UP          2           4                    4                             0
SOS_SCHEDULER_YIELD   32277       1                    0                             1
IO_COMPLETION         8           0                    0                             0
LATCH_SH              3           0                    0                             0
LOGBUFFER             1           0                    0                             0

Anda dapat melihat bahwa NETWORK_IO 68 detik terdaftar. Tetapi karena loop penyisipan adalah tindakan berulir tunggal yang membutuhkan waktu 36 detik, ini tidak mungkin. (Ya, banyak utas digunakan, tetapi operasinya serial, tidak pernah paralel, sehingga Anda tidak dapat mengakumulasi lebih banyak waktu tunggu daripada total durasi kueri)

Jika saya tidak menggunakan acara yang diperluas tetapi hanya menunggu DMVs statistik pada contoh yang tenang (hanya dengan saya menjalankan sisipan) Saya mendapatkan ini:

Wait Type                   Wait Count  Total Wait Time (ms)  Total Resource Wait Time (ms) Signal Resource Wait Time (ms)
SOS_SCHEDULER_YIELD             8873                 0.21                                    0.01                                    0.20
PAGEIOLATCH_UP                  3                    0.02                                    0.02                                    0.00
PREEMPTIVE_OS_AUTHENTICATIONOPS 17                   0.02                                    0.02                                    0.00
PAGEIOLATCH_SH                  1                    0.00                                    0.00                                    0.00

Jadi NETWORK_IO yang Anda lihat di log peristiwa yang diperluas, tidak terkait dengan loop sisipan Anda. (Jika Anda tidak mengaktifkan nocount, Anda akan memiliki jaringan async besar IO menunggu, +1 Martin)

Namun saya tidak tahu mengapa NETWORK_IO muncul di jejak acara yang diperluas. Tentu saja penulisan target file async dari peristiwa tersebut mengakumulasi ASYNC_NETWORK_IO, tetapi tentu saja ini semua dilakukan pada SPID yang berbeda dari yang kami filter. Saya mungkin mengajukan ini sebagai pertanyaan baru sendiri)

10
Edward Dortland

Biasanya Anda mulai dengan melihat sys.dm_exec_requests , khususnya di wait_time, wait_type dan wait_resource untuk permintaan INSERT Anda. Ini akan memberikan indikasi yang jelas apa yang menghalangi INSERT Anda. Hasil akan menunjukkan apakah pertikaian kunci, peristiwa pertumbuhan file, menunggu log flush, pertikaian alokasi (dimanifestasikan sebagai pertengkaran kait halaman PFS) dll. Dll. Setelah Anda mengukur, perbarui pertanyaan Anda sesuai. Saya sangat menyarankan Anda untuk berhenti sekarang dan membaca Tunggu dan Antrian metodologi pemecahan masalah sebelum Anda melanjutkan.

9
Remus Rusanu

Saya menjalankan skrip pengujian pada halaman yang terhubung dalam OP dengan BEGIN TRAN/COMMIT di sekitar loop. Di komputer saya, dibutuhkan 1:28 untuk menyelesaikan pertama kalinya.

Lalu saya memindahkan dua perintah ini di luar loop:

SELECT @Random = ROUND(((@Upper - @Lower -1) * Rand() + @Lower), 0)
SET @InsertDate = DATEADD(dd, @Random, GETDATE())

Itu selesai dalam 28 detik setelah itu.

Saya tidak tahu pasti apa yang terjadi, tapi saya kira mungkin ada semacam tidur di kode Rand(), mungkin sebagai bagian dari algoritma yang mereka gunakan untuk menghasilkan entropi (acak yang lebih baik angka).

FWIW, SSD tidak selalu merupakan teknologi terbaik untuk aplikasi yang berat. Untuk kinerja terbaik, pastikan log DB Anda menggunakan huruf drive yang berbeda dari data DB, file log sudah dipra-tumbuh hingga ukuran maksimumnya, dan jangan pernah memotong log.

3
RickNZ

DMV lain yang saya gunakan untuk mengidentifikasi kelambatan adalah sys.dm_os_waiting_tasks . Jika permintaan Anda bukan CPU intensif, maka Anda dapat menemukan informasi lebih lanjut tentang menunggu dari DMV ini.

1
StanleyJohns

Saya memeriksa daftar acara tunggu untuk sql 2008 dan saya tidak melihat NETWORK_IO terdaftar: http://technet.Microsoft.com/en-us/library/ms179984 (v = sql.100). aspx

Saya pikir NETWORK_IO sekarang baru saja terdaftar sebagai ASYNC_NETWORK_IO, jadi saya ingin bertanya apakah Anda dapat memeriksa versi SQL Anda lagi, karena saya hanya ingin tahu bagaimana/mengapa acara tunggu itu muncul untuk versi itu.

Adapun menunggu jaringan muncul sama sekali, ya itu bisa terjadi bahkan jika Anda bekerja pada server mandiri. Sudahkah Anda memeriksa pengaturan untuk kartu jaringan Anda? Saya bertanya-tanya apakah itu masalah.

Pada akhirnya, hanya ada beberapa hambatan sumber daya yang mungkin: memori, CPU, disk I/O, jaringan, dan penguncian. Anda telah mengindikasikan bahwa CPU dan I/O bukan masalahnya, dan Anda memiliki acara tunggu NETWORK_IO, jadi saya sarankan Anda melihat kartu NIC terlebih dahulu.

0
SQLRockstar