Pengantar Kinerja

Performa database adalah topik yang luas dan kompleks, mencakup seluruh tumpukan komponen: database, jaringan, driver database, dan lapisan akses data seperti EF Core. Meskipun lapisan tingkat tinggi dan O/RM seperti EF Core sangat menyederhanakan pengembangan aplikasi dan meningkatkan ketahanan, mereka kadang-kadang dapat buram, menyembunyikan detail internal kritis performa seperti SQL yang dijalankan. Bagian ini mencoba memberikan gambaran umum tentang cara mencapai performa yang baik dengan EF Core, dan cara menghindari jebakan umum yang dapat menurunkan performa aplikasi.

Mengidentifikasi hambatan dan mengukur, mengukur, mengukur

Seperti biasa dengan kinerja, penting untuk tidak terburu-buru ke dalam pengoptimalan tanpa data yang menunjukkan masalah; seperti yang pernah dikatakan oleh Donald Knuth yang hebat, "Pengoptimalan awal adalah akar dari segala keburukan". Bagian diagnosis performa membahas berbagai cara untuk memahami di mana aplikasi Anda menghabiskan waktu dalam logika database, dan cara menentukan area bermasalah tertentu. Setelah kueri lambat diidentifikasi, solusi dapat dipertimbangkan: apakah database Anda kehilangan indeks? Haruskah Anda mencoba pola kueri lainnya?

Selalu tolok ukur kode Anda dan kemungkinan alternatif sendiri - bagian diagnosis performa berisi tolok ukur sampel dengan BenchmarkDotNet, yang dapat Anda gunakan sebagai templat untuk tolok ukur Anda sendiri. Jangan berasumsi bahwa tolok ukur umum publik berlaku as-is untuk kasus penggunaan spesifik Anda; berbagai faktor seperti latensi database, kompleksitas kueri, dan jumlah data aktual dalam tabel Anda dapat memiliki efek mendalam tentang solusi mana yang terbaik. Misalnya, banyak tolok ukur publik dilakukan dalam kondisi jaringan yang ideal, di mana latensi ke basis data hampir nol, dan dengan pertanyaan yang sangat ringan yang hampir tidak memerlukan pemrosesan (atau I/O disk) di sisi basis data. Meskipun ini berharga untuk membandingkan overhead runtime dari lapisan akses data yang berbeda, perbedaan yang terungkap biasanya terbukti dapat diabaikan dalam aplikasi dunia nyata, di mana database menjalankan tugas sebenarnya dan latensi yang sebenarnya ke database adalah faktor performa yang signifikan.

Aspek performa akses data

Performa akses data secara keseluruhan dapat dipecah ke dalam kategori luas berikut:

  • Performa database yang optimal. Dengan database relasional, EF menerjemahkan kueri LINQ aplikasi ke dalam pernyataan SQL yang dijalankan oleh database; pernyataan SQL ini sendiri dapat berjalan lebih atau kurang efisien. Indeks yang tepat di tempat yang tepat dapat membuat dunia perbedaan dalam performa SQL, atau menulis ulang kueri LINQ Anda dapat membuat EF menghasilkan kueri SQL yang lebih baik.
  • Transfer data jaringan. Seperti halnya sistem jaringan apa pun, penting untuk membatasi jumlah data yang bolak-balik pada kawat. Ini mencakup memastikan bahwa Anda hanya mengirim dan memuat data yang sebenarnya akan Anda butuhkan, tetapi juga menghindari apa yang disebut efek "ledakan kartesius" saat memuat entitas terkait.
  • Perjalanan bolak-balik jaringan. Di luar jumlah data yang bolak-balik, putaran balik jaringan sangat signifikan, karena waktu yang dibutuhkan agar kueri dijalankan dalam database dapat dikerdilkan oleh waktu perjalanan paket bolak-balik antara aplikasi Anda dan database Anda. Beban perjalanan pulang-pergi sangat tergantung pada lingkungan Anda; semakin jauh server database Anda, semakin tinggi latensi dan semakin mahal setiap perjalanan pulang-pergi. Dengan munculnya cloud, aplikasi semakin menemukan diri mereka lebih jauh dari database, dan aplikasi "cerewet" yang melakukan terlalu banyak perjalanan pulang-pergi mengalami penurunan performa. Oleh karena itu, penting untuk dipahami dengan tepat ketika aplikasi Anda menghubungi database, berapa banyak perjalanan pulang pergi yang dilakukannya, dan apakah angka tersebut dapat diminimalkan.
  • Overhead runtime EF. Terakhir, EF sendiri menambahkan beberapa overhead runtime ke operasi database: EF perlu mengkompilasi kueri Anda dari LINQ ke SQL (meskipun biasanya harus dilakukan hanya sekali), pelacakan perubahan menambahkan beberapa overhead (tetapi dapat dinonaktifkan), dll. Dalam praktiknya, overhead EF untuk aplikasi dunia nyata kemungkinan dapat diabaikan dalam banyak kasus, karena waktu eksekusi kueri dalam database dan latensi jaringan mendominasi total waktu; tetapi penting untuk memahami apa pilihan Anda dan cara menghindari beberapa perangkap.

Ketahui apa yang terjadi di bawah tenda

EF memungkinkan pengembang untuk berkonsentrasi pada logika bisnis dengan menghasilkan SQL, mewujudkan hasil, dan melakukan tugas lain. Seperti lapisan atau abstraksi apa pun, ia juga cenderung menyembunyikan apa yang terjadi di bawah tenda, seperti kueri SQL aktual yang dijalankan. Performa belum tentu merupakan aspek penting dari setiap aplikasi yang ada, tetapi dalam aplikasi di mana performa adalah aspek penting, sangat penting bahwa pengembang memahami apa yang dilakukan EF: memeriksa kueri SQL yang keluar, mengikuti proses bolak-balik untuk memastikan masalah N+1 tidak terjadi, dll.

Cache di luar database

Akhirnya, cara paling efisien untuk berinteraksi dengan database, adalah dengan tidak berinteraksi dengannya sama sekali. Dengan kata lain, jika akses database muncul sebagai hambatan performa di aplikasi Anda, mungkin ada baiknya untuk menyimpan hasil tertentu di luar database, sehingga dapat meminimalkan permintaan. Meskipun penembolokan menambah kompleksitas, ini adalah bagian yang sangat penting dari aplikasi apa pun yang dapat diskalakan: sementara lapisan aplikasi dapat diskalakan dengan mudah dengan menambahkan server tambahan untuk menangani peningkatan beban, penskalaan lapisan basis data biasanya jauh lebih kompleks.