Kinerja insert meningkat di bawah beban: Mengapa?


19

Saya memiliki sepotong kode yang melakukan sisipan ke dalam tabel yang sangat dinormalisasi. Tabel memiliki jumlah kolom mulai dari ~ 100 hingga 300+. Ini adalah SQL Server 2008 R2, berjalan pada Windows Server 2008.

Setiap memasukkan terdiri dari memasukkan ke sejumlah tabel di bawah transaksi yang sama. Beberapa sisipan dikelompokkan oleh NHibernate, tetapi beberapa tidak bisa, tetapi semuanya masih dalam transaksi yang sama.

Ketika saya melakukan insert untuk mengatakan 500 kali dengan berulang kali memanggil sepotong kode yang melakukan insert, saya mendapatkan rata-rata ~ 360 ms.

Yang aneh adalah, ketika saya menjalankan kode uji secara bersamaan menggunakan 4 proses (jalankan exe yang sama dari 4 perintah yang berbeda meminta di bawah windows server 2008), kinerja penyisipan per panggilan menjadi jauh lebih baik. Saya melihat semburan yang bergerak secepat 90 ms (hampir X4 lebih cepat). Saya mengukur waktu penyisipan dari kode.

Karena 4 proses tidak tahu apa-apa tentang satu sama lain, saya berasumsi bahwa ini ada hubungannya dengan SQL Server, tapi saya sama sekali tidak tahu mengapa. Saya ingin tahu mengapa hal ini terjadi dan jika ada konfigurasi yang memungkinkan saya untuk mendapatkan kinerja yang sama ketika memasukkan tidak terlalu sering.

Saran mengenai metode pemantauan SQL Server untuk memahami apa yang terjadi di tingkat db sama-sama disambut.

Jawaban:


15

Salah satu alasan yang mungkin adalah bahwa empat proses bersamaan menghasilkan pola flush log yang lebih menguntungkan - biasanya berarti bahwa setiap flush log menulis lebih banyak data daripada kasus dengan proses eksekusi tunggal.

Untuk menentukan apakah transaksi throughput / ukuran flush merupakan faktor, monitor:

Cari batasan internal yang tercapai. Dalam SQL Server 2008 R2, ada maksimum 32 log (asynchronous) log flush I / Os per database pada versi 64-bit (hanya 8 pada 32-bit). Ada juga batas ukuran total pada IO yang luar biasa dari 3840KB.

Informasi lebih lanjut dan bacaan lebih lanjut:


12

Semuanya @PaulWhite mengatakan, plus ...

Jika Anda memiliki kunci asing di tempatnya, setiap sisipan akan membutuhkan pemeriksaan yang harus dilakukan pada setiap tabel yang direferensikan. Kedengarannya bagi saya seperti Anda, karena Anda hanya mendapatkan 360ms, yang terasa lambat bagi saya.

Bagaimanapun, memeriksa tabel-tabel itu sangat terbantu dengan memiliki data dalam RAM, daripada harus memuatnya ke disk.

Bagi saya sepertinya memuat data ke dalam RAM adalah bagian penting dari eksekusi Anda, dan itu hanya perlu terjadi sekali.

Itu juga bisa menjadi caching rencana yang efektif, dan bahwa permintaan Anda harus dikompilasi pertama kali, dengan panggilan berikutnya dapat menghindari fase itu.


Rob terima kasih. Masalah kinerja saya dikaitkan dengan banyaknya tabel yang digunakan selama penyisipan. Tidak ada kunci asing, saya menghapusnya untuk alasan kinerja dan model dan persyaratan domain saya memungkinkan saya untuk melakukan itu. Saya tidak memuat data ke RAM, dan sisipan saya dibentuk secara dinamis oleh permintaan masuk, yang berubah setiap saat. Saya pada dasarnya menyalahgunakan skema star / snowflake (ish) untuk OLTP dan mencoba untuk pergi dengan kinerja terbaik yang saya bisa.
mahonya

2
@mahonya, meskipun Anda tidak secara eksplisit memuat data ke dalam RAM, SQL Server harus terlebih dahulu membaca halaman indeks dan data yang diperlukan ke dalam buffer cache sebelum melakukan operasi penyisipan. Utas penyisipan bersamaan dapat memiliki efek menghangatkan cache sedemikian sehingga satu utas menimbulkan overhead baca dan lainnya mengakses data dalam cache.
Dan Guzman

Terima kasih @DanGuzman - dan ya, mahonya, ada peluang kuat cache Anda dihangatkan dengan baik. Saya akan memeriksa menunggu Anda untuk melihat apakah itu fisik I / O menyebabkan kemacetan Anda.
Rob Farley

Terima kasih @DanGuzman Setuju, speedup cache indeks db adalah sesuatu yang biasa saya lihat di postgres, saya mungkin salah paham input Rob.
mahonya

-3

beberapa server / cpus / os mengingat polanya. seperti cache.

Karena Anda melakukan hal yang sama 4 kali, saya yakin ada cara yang dapat memotong sudut, Apa yang saya duga adalah bahwa cara pertama Anda melakukannya, itu menganggapnya sebagai satu proses panjang (contoh 1) tetapi dengan cara kedua adalah melihat kode yang digunakan kembali dan menjalankannya seperti cache (example2) atau bisa jadi proses pertama adalah besar agar sesuai dengan semuanya dalam (ram example3).

example1: 0111110000110111110000111011111000011110111110000

contoh2: 0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

example3: 0111110000011111000001111100000111110000 example3: loop: 0111110000

Saya tahu server ubuntu melakukan ini dengan permintaan mysql berulang. Saya dapat menyimpannya dalam cache, meskipun satu-satunya perbedaan waktu adalah 10-40mm tetapi bertambah. Ketika saya masih di sekolah ada kelas yang menunjukkan Anda harus membuat program (perl / php) menggunakan cache itu menjadi lebih cepat.

Tapi, itu mungkin tergantung pada program, bahasa apa itu, apa itu dikompilasi atau bagaimana itu diprogram.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.