Membuat koneksi basis data - Lakukan sekali atau untuk setiap permintaan?

101

Saat ini saya membuat koneksi database ketika halaman web saya pertama kali dimuat. Saya kemudian memproses halaman dan menjalankan kueri terhadap koneksinya. Apakah ini cara terbaik untuk melakukannya atau haruskah saya membuat koneksi database setiap kali saya menjalankan kueri?

ps Lebih masuk akal bagi saya untuk membuat 1 koneksi dan menggunakannya tetapi saya tidak tahu apakah ini dapat menyebabkan masalah lain.

Saya menggunakan C # (ASP.NET) dengan MSSQL.

webnoob
sumber

Jawaban:

124

Jika Anda membuat satu per permintaan / transaksi, akan lebih mudah untuk mengelola "menutup" koneksi.

Saya dapat melihat mengapa akal sehat menentukan bahwa Anda harus membukanya dan menggunakannya secara keseluruhan, tetapi Anda akan mengalami masalah dengan koneksi yang terputus dan multithreading. Jadi langkah Anda selanjutnya adalah membuka kolam, katakanlah 50, koneksi dan biarkan semuanya terbuka, bagikan ke proses yang berbeda. Dan kemudian Anda akan menemukan bahwa inilah yang sudah dilakukan oleh .NET framework untuk Anda .

Jika Anda membuka koneksi saat Anda membutuhkannya dan membuangnya setelah selesai, itu tidak akan benar-benar menutup koneksi, itu hanya akan mengembalikannya ke kumpulan koneksi untuk digunakan lagi.

pdr
sumber
Baru saja membaca artikel itu ketika Anda mempostingnya :) Terima kasih.
webnoob
2
Halaman web yang Anda tautkan khusus untuk SQL Server. Apakah .NET juga menyediakan penyatuan otomatis saat menyambung ke basis data lain misalnya - Oracle, Sqlite, MySql?
briddums
@briddums - Saya pikir itu tergantung pada konektornya. .Net, misalnya, tidak menyediakan konektor MySql. Ini ditulis dan dikelola oleh MySql. Dan sementara itu berfungsi, menurut pengalaman saya implementasi sebelumnya jauh dari bebas bug.
ZweiBlumen
1
@briddums: Tergantung pada perakitan penyedia. Saya yakin bahwa Microsoft mengimplementasikan Oracle dan Oracle sendiri mendukung pooling koneksi, karena saya telah menggunakannya. Saya pernah mendengar bahwa ada MySql yang berfungsi, dan saya berharap penyedia di Spring.NET mendukung pooling, tetapi Anda lebih baik mencari atau bertanya langsung kepada penyedia daripada bertanya kepada saya.
pdr
1
Seharusnya diketahui bahwa membuka, menjalankan kueri, dan membuang koneksi, bahkan dalam satu lingkaran, sama cepatnya, dan terkadang LEBIH CEPAT daripada membukanya sekali dan mengulangi kueri. Selalu buang saja. Ini lebih aman, dan CEPAT. Jangan khawatir tentang overhead mendapatkan koneksi dari kolam - itu sangat sepele.
smdrager
38

Praktik terbaik untuk membuat satu koneksi per kueri - dan dalam hal menampilkan data, praktik terbaik adalah meminta kueri membawa semua data yang diperlukan dalam sekali jalan.

Informasi latar belakang:

Di .NET, panggilan SqlConnection.Open()secara default akan selalu menggunakan pooling koneksi secara transparan (lihat "Menggunakan Connection Pooling dengan SQL Server" di MSDN). Jadi, Anda bisa menggunakan koneksi baru Open(), dan menelepon Close()saat Anda selesai, dan .NET akan melakukan hal yang benar.

Perhatikan bahwa tanpa kumpulan koneksi, satu koneksi per kueri akan menjadi ide yang sangat buruk karena membuat koneksi database nyata bisa sangat mahal (otentikasi, overhead jaringan dll.), Dan jumlah koneksi terbuka simultan biasanya sangat terbatas.

Oded
sumber
7
@ Webbob - Karena .NET menggunakan pooling koneksi, tidak, tidak. Alasannya adalah bahwa koneksi dapat ditutup, dialokasikan kembali dll - jadi menggunakan kembali koneksi bukanlah praktik yang baik.
Oded
11
-1 Jawabannya agak menyesatkan. Membuat koneksi per permintaan adalah ide yang sangat buruk. Apa yang Anda maksud adalah "mengambil koneksi baru untuk setiap permintaan dari kumpulan koneksi" - tetapi itu tidak sama dengan membuat koneksi.
sleske
1
@sleske - Apa bedanya dengan jawaban pdr?
Oded
3
@Oded: Ah, begitu. Di .NET, panggilan SqlConnection.Open()akan selalu menggunakan pooling koneksi secara transparan. Jadi perbedaan antara "buka koneksi" dan "ambil koneksi dari kolam" tidak ada. Kesalahpahaman saya. Saya mengambil kebebasan mengedit sedikit penjelasan ke dalam pertanyaan, dan mengambil kembali pemungutan suara.
sleske
2
@ eaglei22 - sudah seharusnya demikian (lihat docs.microsoft.com/en-us/dotnet/framework/data/adonet/… ). Secara umum, Anda ingin mengembalikan koneksi ke pool sesegera mungkin, meskipun, jika Anda mengeluarkan sejumlah pertanyaan secara berurutan, mungkin lebih baik untuk menggunakan kembali koneksi seperti yang Anda sarankan. Anda perlu menguji dan melihat pendekatan mana yang lebih baik untuk Anda (saya tidak tahu kriteria apa yang Anda gunakan - periksa kedua cara dan lihat efeknya pada metrik yang Anda pilih).
Oded
0

Ingat semua ini dalam konteks ekosistem .Net.

Pengembang terkadang ingin "mengoptimalkan" kode mereka untuk menggunakan kembali objek koneksi mereka. Mengingat konteks pertanyaan ini, ini hampir selalu merupakan kesalahan.

ADO.Net memiliki fitur yang disebut Connection Pooling . Saat Anda membuat dan membuka objek koneksi baru, yang sebenarnya Anda lakukan adalah meminta koneksi dari kumpulan. Ketika Anda menutup koneksi, Anda mengembalikannya ke kolam.

Sangat penting untuk memahami objek yang kita gunakan langsung dalam kode: SqlConnection, MySqlConnection, OleDbConnectio, dll, semua hanya pembungkus di sekitar koneksi yang sebenarnya yang dikelola oleh ADO.Net, dan koneksi nyata ADO.Net jauh "lebih berat" dan lebih mahal dari sudut pandang kinerja. Ini objek yang mendasari yang memiliki kekhawatiran seperti otentikasi, transit jaringan, enkripsi, dan hal-hal itu jauh melebihi jumlah kecil memori dalam objek yang sebenarnya Anda lihat dalam kode Anda sendiri.

Ketika Anda mencoba menggunakan kembali objek koneksi Anda, Anda merusak kemampuan ADO.Net untuk secara efektif mengelola koneksi penting yang mendasarinya. Anda mendapatkan efisiensi dalam hal kecil dengan mengorbankan hal yang jauh lebih besar.

Menggunakan kembali koneksi di suatu aplikasi atau permintaan http juga dapat memaksa Anda untuk membuat serialisasi sesuatu yang mungkin dapat berjalan secara paralel, dan menjadi hambatan kinerja. Saya telah melihat ini terjadi dalam aplikasi nyata.

Dalam kasus contoh halaman web di sini, di mana Anda setidaknya hanya menyimpan koneksi kecil selama satu permintaan / respons http, Anda bisa mendapatkan efisiensi lebih dengan mengevaluasi pertanyaan apa yang Anda jalankan dalam pipa permintaan Anda, dan mencoba mendapatkan turun menjadi beberapa permintaan terpisah ke basis data sebanyak mungkin (petunjuk: Anda dapat mengirimkan lebih dari satu permintaan dalam satu string SQL, dan menggunakan DataReader.NextResult()atau memeriksa tabel yang berbeda DataSetuntuk berpindah di antara mereka).

Dengan kata lain, alih-alih berpikir untuk menggunakan kembali satu koneksi untuk aplikasi atau permintaan http vs satu koneksi per permintaan, pikirkan dalam hal satu koneksi untuk setiap kali Anda memanggil ke database ... setiap perjalanan pulang pergi. Kemudian cobalah untuk meminimalkan jumlah koneksi dengan meminimalkan jumlah perjalanan tersebut. Dengan cara ini Anda dapat memenuhi kedua tujuan.


Tapi itu hanya satu jenis optimasi. Ada juga mengoptimalkan waktu programmer, dan mendapatkan penggunaan kembali kode yang efektif. Pengembang tidak ingin menulis kode boilerplate yang sama berulang-ulang hanya untuk mendapatkan objek koneksi yang terbuka dan siap digunakan. Ini tidak hanya membosankan, ini adalah cara untuk memperkenalkan bug ke dalam program.

Namun, bahkan di sini, umumnya lebih baik memiliki satu koneksi per kueri (atau pulang pergi). Ada pola lain yang dapat Anda gunakan untuk membantu menghindari penulisan ulang kode boilerplate yang sama. Ini adalah salah satu contoh yang saya sukai, tetapi ada banyak contoh lainnya.

Joel Coehoorn
sumber
Saya terlambat ke pesta ini, tetapi saya pikir jawaban ini mencakup beberapa poin penting :)
Joel Coehoorn