Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Topik ini menjelaskan karakteristik performa ADO.NET Entity Framework dan memberikan beberapa pertimbangan untuk membantu meningkatkan performa aplikasi Entity Framework.
Tahapan Pelaksanaan Kueri
Untuk lebih memahami performa kueri dalam Kerangka Kerja Entitas, sangat membantu untuk memahami operasi yang terjadi ketika kueri dijalankan terhadap model konseptual dan mengembalikan data sebagai objek. Tabel berikut ini menjelaskan rangkaian operasi ini.
| Operasi | Biaya Relatif | Frekuensi | Komentar |
|---|---|---|---|
| Memuat metadata | Menengah | Sekali di setiap domain aplikasi. | Model dan metadata pemetaan yang digunakan oleh Kerangka Kerja Entitas dimuat ke dalam MetadataWorkspace. Metadata ini di-cache secara global dan tersedia untuk instans ObjectContext lain di domain aplikasi yang sama. |
| Membuka koneksi database | Sedang1 | Sesuai kebutuhan. | Karena koneksi terbuka ke database menggunakan sumber daya yang berharga, Kerangka Kerja Entitas membuka dan menutup koneksi database hanya sesuai kebutuhan. Anda juga dapat secara eksplisit membuka koneksi. Untuk informasi selengkapnya, lihat Mengelola Koneksi dan Transaksi. |
| Menghasilkan tampilan | Tinggi | Sekali di setiap domain aplikasi. (Dapat dibuat sebelumnya.) | Sebelum Kerangka Kerja Entitas dapat menjalankan kueri terhadap model konseptual atau menyimpan perubahan ke sumber data, kerangka kerja tersebut harus menghasilkan sekumpulan tampilan kueri lokal untuk mengakses database. Karena biaya tinggi untuk menghasilkan tampilan ini, Anda dapat membuat tampilan sebelumnya dan menambahkannya ke proyek pada waktu desain. Untuk informasi selengkapnya, lihat Cara: Pra-Buat Tampilan untuk Meningkatkan Kinerja Kueri. |
| Menyiapkan kueri | Sedang2 | Sekali untuk setiap pertanyaan unik. | Termasuk biaya untuk menyusun perintah kueri, menghasilkan pohon perintah berdasarkan model dan metadata pemetaan, dan menentukan bentuk data yang dikembalikan. Karena sekarang perintah kueri SQL Entitas dan kueri LINQ di-cache, eksekusi kueri yang sama membutuhkan waktu lebih sedikit. Anda masih dapat menggunakan kueri LINQ yang dikompilasi untuk mengurangi biaya ini dalam eksekusi nanti dan kueri yang dikompilasi dapat lebih efisien daripada kueri LINQ yang secara otomatis di-cache. Untuk informasi selengkapnya, lihat Kueri yang Dikompilasi (LINQ ke Entitas). Untuk informasi umum tentang eksekusi kueri LINQ, lihat LINQ ke Entitas.
Nota: LINQ ke kueri Entitas yang menerapkan operator Enumerable.Contains pada koleksi dalam memori tidak di-cache secara otomatis. Parameterisasi koleksi yang ada dalam memori pada kueri LINQ yang dikompilasi juga tidak diperbolehkan. |
| Menjalankan kueri | Rendah2 | Sekali untuk setiap permintaan. | Biaya menjalankan perintah terhadap sumber data dengan menggunakan penyedia data ADO.NET. Karena sebagian besar sumber data menyimpan rencana kueri, eksekusi kueri yang sama nanti mungkin memakan waktu lebih sedikit. |
| Memuat dan memvalidasi tipe | Rendah3 | Sekali untuk setiap ObjectContext contoh. | Jenis dimuat dan divalidasi terhadap jenis yang ditentukan model konseptual. |
| Pelacakan | Rendah3 | Sekali untuk setiap objek yang dikembalikan kueri. 4 | Jika kueri menggunakan opsi gabungkan NoTracking , tahap ini tidak memengaruhi performa. Jika kueri menggunakan opsi gabungkan AppendOnly, PreserveChanges, atau OverwriteChanges, hasil kueri dilacak di ObjectStateManager. EntityKey dihasilkan untuk setiap objek yang terlacak yang dikembalikan oleh kueri dan digunakan untuk membuat ObjectStateEntry di ObjectStateManager. Jika yang sudah ada ObjectStateEntry dapat ditemukan untuk EntityKey, objek yang ada dikembalikan. PreserveChangesJika opsi , atau OverwriteChanges digunakan, objek diperbarui sebelum dikembalikan. Untuk informasi selengkapnya, lihat Resolusi Identitas, Manajemen Status, dan Pelacakan Perubahan. |
| Mewujudkan objek | Sedang3 | Sekali untuk setiap objek yang dikembalikan kueri. 4 | Proses membaca objek yang dikembalikan DbDataReader dan membuat objek dan mengatur nilai properti yang didasarkan pada nilai di setiap instans DbDataRecord kelas. Jika objek sudah ada di ObjectContext dan kueri menggunakan opsi AppendOnly atau opsi penggabungan PreserveChanges, tahap ini tidak memengaruhi performa. Untuk informasi selengkapnya, lihat Resolusi Identitas, Manajemen Status, dan Pelacakan Perubahan. |
1 Ketika penyedia sumber data menerapkan pengumpulan koneksi, biaya pembukaan koneksi didistribusikan di seluruh kumpulan. Penyedia .NET untuk SQL Server mendukung pengumpulan koneksi.
2 Biaya meningkat seiring dengan meningkatnya kompleksitas kueri.
3 Total biaya meningkat sebanding dengan jumlah objek yang dikembalikan oleh kueri.
4 Overhead ini tidak diperlukan untuk kueri EntityClient karena kueri EntityClient mengembalikan EntityDataReader dan bukan objek. Untuk informasi selengkapnya, lihat Penyedia EntityClient untuk Entity Framework.
Pertimbangan Tambahan
Berikut ini adalah pertimbangan lain yang dapat memengaruhi performa aplikasi Entity Framework.
Eksekusi Kueri
Karena kueri bisa intensif sumber daya, pertimbangkan pada titik mana dalam kode Anda dan di komputer mana kueri dijalankan.
Ditangguhkan versus eksekusi segera
Saat Anda membuat ObjectQuery<T> kueri atau LINQ, kueri mungkin tidak segera dijalankan. Eksekusi kueri ditangguhkan hingga hasilnya diperlukan, seperti selama enumerasi foreach (C#) atau For Each (Visual Basic), atau saat digunakan untuk mengisi koleksi List<T>. Eksekusi kueri segera dimulai saat Anda memanggil Execute metode pada ObjectQuery<T> atau saat Anda memanggil metode LINQ yang mengembalikan kueri singleton, seperti First atau Any. Untuk informasi selengkapnya, lihat Kueri Objek dan Eksekusi Kueri (LINQ ke Entitas).
Eksekusi kueri LINQ pada sisi klien
Meskipun eksekusi kueri LINQ terjadi di komputer yang menghosting sumber data, beberapa bagian kueri LINQ dapat dievaluasi di komputer klien. Untuk informasi selengkapnya, lihat bagian Eksekusi Penyimpanan Eksekusi Kueri (LINQ ke Entitas).
Kompleksitas Pencarian dan Pemetaan
Kompleksitas kueri individual dan pemetaan dalam model entitas akan memiliki efek signifikan pada performa kueri.
Kompleksitas pemetaan
Model yang lebih kompleks daripada pemetaan satu-ke-satu sederhana antara entitas dalam model konseptual dan tabel dalam model penyimpanan menghasilkan perintah yang lebih kompleks daripada model yang memiliki pemetaan satu-ke-satu.
Kompleksitas kueri
Kueri yang memerlukan sejumlah besar gabungan dalam perintah yang dijalankan terhadap sumber data atau yang mengembalikan sejumlah besar data dapat memengaruhi performa dengan cara berikut:
Kueri terhadap model konseptual yang tampak sederhana dapat mengakibatkan eksekusi kueri yang lebih kompleks terhadap sumber data. Ini dapat terjadi karena Kerangka Kerja Entitas menerjemahkan kueri terhadap model konseptual ke dalam kueri yang setara terhadap sumber data. Saat satu himpunan entitas dalam model konseptual dipetakan ke lebih dari satu tabel di sumber data, atau ketika hubungan antara entitas dipetakan ke tabel penggabungan, perintah kueri yang dieksekusi terhadap sumber data mungkin memerlukan satu atau beberapa penggabungan.
Nota
ToTraceString Gunakan metode ObjectQuery<T> kelas atau EntityCommand untuk menampilkan perintah yang dijalankan terhadap sumber data untuk kueri tertentu. Untuk informasi selengkapnya, lihat Cara: Menampilkan Perintah Store.
Kueri SQL Entitas Berlapis dapat membuat gabungan di server dan dapat mengembalikan sejumlah besar baris.
Berikut ini adalah contoh kueri berlapis dalam klausa proyeksi:
SELECT c, (SELECT c, (SELECT c FROM AdventureWorksModel.Vendor AS c ) As Inner2 FROM AdventureWorksModel.JobCandidate AS c ) As Inner1 FROM AdventureWorksModel.EmployeeDepartmentHistory AS cSelain itu, kueri tersebut menyebabkan alur kueri menghasilkan satu kueri dengan duplikasi objek di seluruh kueri berlapis. Karena itu, satu kolom dapat diduplikasi beberapa kali. Pada beberapa database, termasuk SQL Server, ini dapat menyebabkan tabel TempDB tumbuh sangat besar, yang dapat mengurangi performa server. Perhatian harus diberikan ketika Anda menjalankan kueri bersarang.
Setiap kueri yang mengembalikan sejumlah besar data dapat menyebabkan penurunan performa jika klien melakukan operasi yang menggunakan sumber daya dengan cara yang sebanding dengan ukuran kumpulan hasil. Dalam kasus seperti itu, Anda harus mempertimbangkan untuk membatasi jumlah data yang dikembalikan oleh kueri. Untuk informasi selengkapnya, lihat Cara: Halaman Melalui Hasil Kueri.
Setiap perintah yang dihasilkan secara otomatis oleh Kerangka Kerja Entitas mungkin lebih kompleks daripada perintah serupa yang ditulis secara eksplisit oleh pengembang database. Jika Anda memerlukan kontrol eksplisit atas perintah yang dijalankan terhadap sumber data Anda, pertimbangkan untuk menentukan pemetaan ke fungsi bernilai tabel atau prosedur tersimpan.
Hubungan
Untuk performa kueri yang optimal, Anda harus menentukan hubungan antara entitas baik sebagai asosiasi dalam model entitas maupun sebagai hubungan logis di sumber data.
Jalur Kueri
Secara default, ketika Anda menjalankan ObjectQuery<T>, objek terkait tidak dikembalikan (meskipun objek yang mewakili hubungan itu sendiri). Anda dapat memuat objek terkait dengan salah satu dari tiga cara:
Atur jalur kueri sebelum ObjectQuery<T> dijalankan.
Panggil metode
Loadpada properti navigasi yang diekspos oleh objek.Atur opsi LazyLoadingEnabled pada ObjectContext ke
true. Perhatikan bahwa ini dilakukan secara otomatis saat Anda membuat kode lapisan objek dengan Perancang Model Data Entitas. Untuk informasi selengkapnya lihat Gambaran Umum Kode yang Dihasilkan.
Saat Anda mempertimbangkan opsi mana yang akan digunakan, ketahuilah bahwa ada tradeoff antara jumlah permintaan terhadap database dan jumlah data yang dikembalikan dalam satu kueri. Untuk informasi selengkapnya, lihat Memuat Objek Terkait.
Menggunakan jalur kueri
Jalur kueri menentukan grafik objek yang dikembalikan kueri. Saat Anda menentukan jalur kueri, hanya satu permintaan terhadap database yang diperlukan untuk mengembalikan semua objek yang ditentukan jalur. Menggunakan jalur kueri dapat mengakibatkan perintah kompleks dijalankan terhadap sumber data dari kueri objek yang tampaknya sederhana. Ini terjadi karena satu atau beberapa gabungan diperlukan untuk mengembalikan objek terkait dalam satu kueri. Kompleksitas ini lebih besar dalam kueri terhadap model entitas yang kompleks, seperti entitas dengan pewarisan atau jalur yang mencakup hubungan banyak ke banyak.
Nota
Gunakan metode ToTraceString untuk melihat perintah yang akan dihasilkan oleh ObjectQuery<T>. Untuk informasi selengkapnya, lihat Cara: Menampilkan Perintah Store.
Saat jalur kueri menyertakan terlalu banyak objek terkait atau objek berisi terlalu banyak data baris, sumber data mungkin tidak dapat menyelesaikan kueri. Ini terjadi jika kueri memerlukan penyimpanan sementara perantara yang melebihi kemampuan sumber data. Ketika ini terjadi, Anda dapat mengurangi kompleksitas kueri sumber data dengan secara eksplisit memuat objek terkait.
Memuat objek terkait secara eksplisit
Anda dapat secara eksplisit memuat objek terkait dengan memanggil Load metode pada properti navigasi yang mengembalikan EntityCollection<TEntity> atau EntityReference<TEntity>. Memuat objek secara eksplisit memerlukan perjalanan pulang pergi ke database setiap kali Load dipanggil.
Nota
jika Anda memanggil Load saat mengulangi kumpulan objek yang dikembalikan, seperti saat Anda menggunakan pernyataan foreach (For Each di Visual Basic), penyedia spesifik sumber data harus mendukung beberapa set hasil aktif pada satu koneksi. Untuk database SQL Server, Anda harus menentukan nilai MultipleActiveResultSets = true dalam string koneksi penyedia.
Anda juga dapat menggunakan metode LoadProperty ketika tidak ada properti EntityCollection<TEntity> atau EntityReference<TEntity> pada entitas. Ini berguna saat Anda menggunakan entitas POCO.
Meskipun secara eksplisit memuat objek terkait akan mengurangi jumlah gabungan dan mengurangi jumlah data redundan, Load memerlukan koneksi berulang ke database, yang dapat menjadi mahal ketika secara eksplisit memuat sejumlah besar objek.
Menyimpan Perubahan
Saat Anda memanggil metode SaveChanges pada ObjectContext, perintah terpisah buat, perbarui, atau hapus dihasilkan untuk setiap objek yang ditambahkan, diperbarui, atau dihapus dalam konteks. Perintah ini dijalankan pada sumber data dalam satu transaksi. Seperti halnya kueri, performa operasi buat, perbarui, dan hapus tergantung pada kompleksitas pemetaan dalam model konseptual.
Transaksi Terdistribusi
Operasi dalam transaksi eksplisit yang memerlukan sumber daya yang dikelola oleh koordinator transaksi terdistribusi (DTC) akan jauh lebih mahal daripada operasi serupa yang tidak memerlukan DTC. Promosi ke DTC akan terjadi dalam situasi berikut:
Transaksi eksplisit dengan operasi terhadap database SQL Server 2000 atau sumber data lain yang selalu mempromosikan transaksi eksplisit ke DTC.
Transaksi eksplisit dengan operasi terhadap SQL Server 2005 saat koneksi dikelola oleh Kerangka Kerja Entitas. Ini terjadi karena SQL Server 2005 mempromosikan ke DTC setiap kali koneksi ditutup dan dibuka kembali dalam satu transaksi, yang merupakan perilaku default dari Kerangka Kerja Entitas. Promosi DTC ini tidak terjadi saat menggunakan SQL Server 2008. Untuk menghindari promosi ini saat menggunakan SQL Server 2005, Anda harus secara eksplisit membuka dan menutup koneksi dalam transaksi. Untuk informasi selengkapnya, lihat Mengelola Koneksi dan Transaksi.
Transaksi eksplisit digunakan ketika satu atau beberapa operasi dijalankan di dalam System.Transactions transaksi. Untuk informasi selengkapnya, lihat Mengelola Koneksi dan Transaksi.
Strategi untuk Meningkatkan Performa
Anda dapat meningkatkan performa keseluruhan kueri dalam Kerangka Kerja Entitas dengan menggunakan strategi berikut.
Tampilan pra-buat
Menghasilkan tampilan berdasarkan model entitas adalah biaya signifikan saat pertama kali aplikasi menjalankan kueri. Gunakan utilitas EdmGen.exe untuk menghasilkan tampilan sebelumnya sebagai file kode Visual Basic atau C# yang dapat ditambahkan ke proyek selama desain. Anda juga dapat menggunakan Toolkit Transformasi Templat Teks untuk menghasilkan tampilan yang telah dikompilasi sebelumnya. Tampilan yang dibuat sebelumnya divalidasi pada runtime untuk memastikan bahwa tampilan tersebut konsisten dengan versi model entitas yang ditentukan saat ini. Untuk informasi selengkapnya, lihat Cara: Pra-Buat Tampilan untuk Meningkatkan Kinerja Kueri.
Saat bekerja dengan model yang sangat besar, pertimbangan berikut berlaku:
Format metadata .NET membatasi jumlah karakter string pengguna dalam biner tertentu menjadi 16.777.215 (0xFFFFFF). Jika Anda menghasilkan tampilan untuk model yang sangat besar dan berkas tampilan mencapai batas ukuran ini, Anda akan mendapatkan "Tidak ada ruang logis yang tersisa untuk membuat lebih banyak string pengguna." kesalahan kompilasi. Batasan ukuran ini berlaku untuk semua biner terkelola. Untuk informasi selengkapnya, lihat blog yang menunjukkan cara menghindari kesalahan saat bekerja dengan model besar dan kompleks.
Pertimbangkan untuk menggunakan opsi penggabungan NoTracking untuk kueri
Ada biaya diperlukan untuk melacak objek yang dikirim kembali dalam konteks objek. Mendeteksi perubahan pada objek dan memastikan bahwa beberapa permintaan untuk entitas logis yang sama mengembalikan instans objek yang sama memerlukan objek terhubung dengan instans ObjectContext. Jika Anda tidak berencana untuk membuat pembaruan atau menghapus ke objek dan tidak memerlukan manajemen identitas, pertimbangkan untuk menggunakan NoTracking opsi penggabungan saat Anda menjalankan kueri.
Mengembalikan jumlah data yang benar
Dalam beberapa skenario, menentukan jalur kueri menggunakan Include metode ini jauh lebih cepat karena membutuhkan lebih sedikit perjalanan pulang pergi ke database. Namun, dalam skenario lain, perjalanan pulang pergi tambahan ke database untuk memuat objek terkait mungkin lebih cepat karena kueri yang lebih sederhana dengan lebih sedikit gabungan menghasilkan lebih sedikit redundansi data. Karena itu, kami sarankan Anda menguji performa berbagai cara untuk mengambil objek terkait. Untuk informasi selengkapnya, lihat Memuat Objek Terkait.
Untuk menghindari mengembalikan terlalu banyak data dalam satu kueri, pertimbangkan untuk membagi hasil kueri menjadi grup yang lebih mudah dikelola. Untuk informasi selengkapnya, lihat Cara: Halaman Melalui Hasil Kueri.
Membatasi cakupan ObjectContext
Dalam kebanyakan kasus, Anda harus membuat ObjectContext instance dalam using pernyataan (Using…End Using di Visual Basic). Ini dapat meningkatkan performa dengan memastikan bahwa sumber daya yang terkait dengan konteks objek dibuang secara otomatis ketika kode keluar dari blok pernyataan. Namun, ketika kontrol terikat ke objek yang dikelola oleh konteks objek, instans ObjectContext harus dipertahankan selama pengikatan masih diperlukan dan dibuang secara manual. Untuk informasi selengkapnya, lihat Mengelola Koneksi dan Transaksi.
Pertimbangkan untuk membuka koneksi database secara manual
Saat aplikasi Anda menjalankan serangkaian kueri objek atau sering memanggil SaveChanges untuk mempertahankan operasi buat, perbarui, dan hapus ke sumber data, Kerangka Kerja Entitas harus terus membuka dan menutup koneksi ke sumber data. Dalam situasi ini, pertimbangkan untuk membuka koneksi secara manual di awal operasi ini dan menutup atau membuang koneksi ketika operasi selesai. Untuk informasi selengkapnya, lihat Mengelola Koneksi dan Transaksi.
Data Kinerja
Beberapa data performa untuk Kerangka Kerja Entitas diterbitkan dalam posting berikut di blog tim ADO.NET:
Menjelajahi Performa Kerangka Kerja Entitas ADO.NET - Bagian 1
Menjelajahi Performa Kerangka Kerja Entitas ADO.NET – Bagian 2