Saya telah mengikuti mantra "Don't Optimize Prematurely" dan mengkodekan Layanan WCF saya menggunakan Entity Framework.
Namun, saya memprofilkan kinerja dan Entity Framework terlalu lambat. (Aplikasi saya memproses 2 pesan dalam waktu sekitar 1,2 detik, di mana aplikasi (lama) yang saya tulis ulang melakukan 5-6 pesan dalam waktu yang bersamaan. (Aplikasi lama memanggil sprocs untuk DB Access-nya.)
Profiling saya menunjuk ke Entity Framework yang menghabiskan sebagian besar waktu per pesan.
Jadi, apa saja pilihan saya?
Apakah ada ORM yang lebih baik di luar sana?
(Sesuatu yang hanya mendukung membaca dan menulis objek secara normal dan melakukannya dengan cepat ..)Apakah ada cara untuk membuat Entity Framework lebih cepat?
( Catatan : ketika saya mengatakan lebih cepat, maksud saya dalam jangka panjang, bukan panggilan pertama. (Panggilan pertama lambat (15 detik untuk sebuah pesan), tapi itu bukan masalah. Saya hanya perlu cepat untuk sisanya dari pesan.)Beberapa opsi misterius ke-3 yang akan membantu saya mendapatkan lebih banyak kecepatan dari layanan saya.
CATATAN: Sebagian besar interaksi DB saya adalah Buat dan Perbarui. Saya sangat sedikit memilih dan menghapus.
sumber
Jawaban:
Anda harus mulai dengan membuat profil perintah SQL yang sebenarnya dikeluarkan oleh Entity Framework. Bergantung pada konfigurasi Anda (POCO, entitas Self-Tracking), ada banyak ruang untuk pengoptimalan. Anda dapat men-debug perintah SQL (yang seharusnya tidak berbeda antara mode debug dan rilis) menggunakan
ObjectSet<T>.ToTraceString()
metode ini. Jika Anda menemukan kueri yang memerlukan pengoptimalan lebih lanjut, Anda dapat menggunakan beberapa proyeksi untuk memberi EF lebih banyak informasi tentang apa yang ingin Anda capai.Contoh:
Product product = db.Products.SingleOrDefault(p => p.Id == 10); // executes SELECT * FROM Products WHERE Id = 10 ProductDto dto = new ProductDto(); foreach (Category category in product.Categories) // executes SELECT * FROM Categories WHERE ProductId = 10 { dto.Categories.Add(new CategoryDto { Name = category.Name }); }
Bisa diganti dengan:
var query = from p in db.Products where p.Id == 10 select new { p.Name, Categories = from c in p.Categories select c.Name }; ProductDto dto = new ProductDto(); foreach (var categoryName in query.Single().Categories) // Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId { dto.Categories.Add(new CategoryDto { Name = categoryName }); }
Saya baru saja mengetiknya dari kepala saya, jadi ini bukanlah cara yang tepat untuk mengeksekusinya, tetapi EF sebenarnya melakukan beberapa pengoptimalan yang bagus jika Anda menceritakan semua yang Anda ketahui tentang kueri (dalam hal ini, kita akan membutuhkan kategori- nama). Tetapi ini tidak seperti eager-loading (db.Products.Include ("Categories")) karena proyeksi dapat mengurangi jumlah data yang akan dimuat.
sumber
Faktanya adalah bahwa produk seperti Entity Framework SELALU akan lambat dan tidak efisien, karena mereka mengeksekusi lebih banyak kode.
Saya juga merasa konyol bahwa orang menyarankan bahwa seseorang harus mengoptimalkan kueri LINQ, melihat SQL yang dihasilkan, menggunakan debugger, melakukan pra-kompilasi, mengambil banyak langkah tambahan, dll. Yaitu membuang banyak waktu. Tidak ada yang mengatakan - Sederhanakan! Semua orang ingin membuat masalah lebih rumit dengan mengambil lebih banyak langkah (membuang-buang waktu).
Pendekatan akal sehat adalah tidak menggunakan EF atau LINQ sama sekali. Gunakan SQL biasa. Tidak ada yang salah dengan itu. Hanya karena ada mentalitas berkelompok di antara para programmer dan mereka merasakan dorongan untuk menggunakan setiap produk baru yang ada, tidak berarti itu bagus atau akan berhasil. Kebanyakan programmer berpikir jika mereka menggabungkan setiap potongan kode baru yang dirilis oleh perusahaan besar, itu membuat mereka menjadi programmer yang lebih pintar; tidak benar sama sekali. Pemrograman cerdas sebagian besar adalah tentang bagaimana melakukan lebih banyak dengan lebih sedikit sakit kepala, ketidakpastian, dan dalam waktu yang paling sedikit. Ingat waktu! Itu adalah elemen yang paling penting, jadi cobalah untuk menemukan cara untuk tidak menyia-nyiakannya untuk memecahkan masalah dalam kode buruk / membengkak yang ditulis hanya untuk menyesuaikan dengan beberapa yang disebut 'pola' aneh
Santai, nikmati hidup, istirahat dari pengkodean dan berhenti menggunakan fitur tambahan, kode, produk, 'pola'. Hidup itu singkat dan umur kode Anda bahkan lebih pendek, dan ini tentu saja bukan ilmu roket. Hapus layer seperti LINQ, EF dan lainnya, dan kode Anda akan berjalan secara efisien, akan diskalakan, dan ya, itu akan tetap mudah untuk dipelihara. Terlalu banyak abstraksi adalah 'pola' yang buruk.
Dan itulah solusi untuk masalah Anda.
sumber
Satu saran adalah menggunakan LINQ ke Entity Framework hanya untuk pernyataan CRUD rekaman tunggal.
Untuk kueri, pencarian, pelaporan, dll. Yang lebih terlibat, tulis prosedur tersimpan dan tambahkan ke model Entity Framework seperti yang dijelaskan di MSDN .
Ini adalah pendekatan yang saya ambil dengan beberapa situs saya dan tampaknya ini merupakan kompromi yang baik antara produktivitas dan kinerja. Entity Framework tidak selalu menghasilkan SQL paling efisien untuk tugas yang ada. Dan daripada menghabiskan waktu untuk mencari tahu mengapa, menulis prosedur tersimpan untuk query yang lebih kompleks sebenarnya menghemat waktu bagi saya. Setelah Anda terbiasa dengan prosesnya, tidak terlalu merepotkan untuk menambahkan procs tersimpan ke model EF Anda. Dan tentu saja manfaat menambahkannya ke model Anda adalah Anda mendapatkan semua kebaikan yang diketik dengan kuat yang berasal dari penggunaan ORM.
sumber
Jika Anda murni mengambil data, akan sangat membantu kinerja saat Anda memberi tahu EF untuk tidak melacak entitas yang diambilnya. Lakukan ini dengan menggunakan MergeOption.NoTracking. EF hanya akan menghasilkan kueri, mengeksekusinya, dan deserialisasi hasilnya ke objek, tetapi tidak akan mencoba melacak perubahan entitas atau apa pun yang bersifat seperti itu. Jika kueri sederhana (tidak menghabiskan banyak waktu menunggu database kembali), saya telah menemukan bahwa pengaturan ke NoTracking dapat menggandakan kinerja kueri.
Lihat artikel MSDN ini di MergeOption enum:
Resolusi Identitas, Manajemen Status, dan Pelacakan Perubahan
Ini sepertinya artikel yang bagus tentang kinerja EF:
Kinerja dan Kerangka Entitas
sumber
Anda mengatakan bahwa Anda telah membuat profil aplikasi. Sudahkah Anda membuat profil ORM juga? Ada profiler EF dari Ayende yang akan menyoroti di mana Anda dapat mengoptimalkan kode EF Anda. Anda dapat menemukannya di sini:
http://efprof.com/
Ingatlah bahwa Anda dapat menggunakan pendekatan SQL tradisional bersama ORM Anda jika Anda perlu untuk mendapatkan kinerja.
Jika ada ORM yang lebih cepat / lebih baik? Bergantung pada objek / model data Anda, Anda dapat mempertimbangkan untuk menggunakan salah satu ORM mikro, seperti Dapper , Massive , atau PetaPoco .
Situs Dapper menerbitkan beberapa tolok ukur komparatif yang akan memberi Anda gambaran bagaimana perbandingannya dengan ORM lainnya. Namun perlu dicatat bahwa ORM mikro tidak mendukung kumpulan fitur kaya dari ORM lengkap seperti EF dan NH.
Anda mungkin ingin melihat RavenDB . Ini adalah database non-relasional (dari Ayende lagi) yang memungkinkan Anda menyimpan POCO secara langsung tanpa memerlukan pemetaan . RavenDB dioptimalkan untuk pembacaan dan membuat hidup developer jauh lebih mudah dengan menghilangkan kebutuhan untuk memanipulasi skema dan memetakan objek Anda ke skema itu. Namun, ketahuilah bahwa ini adalah pendekatan yang sangat berbeda untuk menggunakan pendekatan ORM dan ini diuraikan di situs produk .
sumber
Saya telah menemukan jawaban dari @Slauma di sini sangat berguna untuk mempercepat segalanya. Saya menggunakan jenis pola yang sama untuk penyisipan dan pembaruan - dan kinerja meroket.
sumber
Dari pengalaman saya, masalahnya bukan dengan EF, tapi dengan pendekatan ORM itu sendiri.
Secara umum semua ORM menderita masalah N + 1 tidak dioptimalkan kueri dan lain-lain. Tebakan terbaik saya adalah melacak kueri yang menyebabkan penurunan kinerja dan mencoba menyetel alat ORM, atau menulis ulang bagian itu dengan SPROC.
sumber
Ini adalah opsi non-framework, non-ORM sederhana yang dimuat pada 10.000 / detik dengan 30 kolom atau lebih. Berjalan di laptop lama, jadi mungkin lebih cepat dari itu di lingkungan nyata.
https://sourceforge.net/projects/dopersistence/?source=directory
sumber
Saya mengalami masalah ini juga. Saya benci membuang ke EF karena bekerja dengan sangat baik, tapi lambat. Dalam kebanyakan kasus, saya hanya ingin mencari catatan atau pembaruan / penyisipan. Bahkan operasi sederhana seperti ini lambat. Saya menarik kembali 1100 catatan dari tabel ke dalam Daftar dan operasi itu memakan waktu 6 detik dengan EF. Bagi saya ini terlalu lama, bahkan menabung pun butuh waktu lama.
Saya akhirnya membuat ORM saya sendiri. Saya menarik 1100 record yang sama dari database dan ORM saya membutuhkan waktu 2 detik, jauh lebih cepat daripada EF. Segala sesuatu dengan ORM saya hampir instan. Satu-satunya batasan saat ini adalah bahwa ini hanya bekerja dengan MS SQL Server, tetapi dapat diubah untuk bekerja dengan yang lain seperti Oracle. Saya menggunakan MS SQL Server untuk semuanya sekarang.
Jika Anda ingin mencoba ORM saya, berikut adalah tautan dan situs webnya:
https://github.com/jdemeuse1204/OR-M-Data-Entities
Atau jika Anda ingin menggunakan nugget:
PM> Instal-Paket ATAU-M_DataEntities
Dokumentasi juga ada di sana
sumber
Masuk akal untuk mengoptimalkan setelah Anda membuat profil. Jika Anda mengetahui bahwa akses DB lambat, Anda dapat mengonversi menggunakan prosedur tersimpan dan tetap menggunakan EF. Jika Anda mengetahui bahwa EF itu sendiri yang lambat, Anda mungkin harus beralih ke ORM yang berbeda atau tidak menggunakan ORM sama sekali.
sumber
Kami memiliki aplikasi serupa (Wcf -> EF -> database) yang melakukan 120 Permintaan per detik dengan mudah, jadi saya lebih dari yakin bahwa EF bukan masalah Anda di sini, karena itu, saya telah melihat peningkatan kinerja yang besar dengan kueri yang dikompilasi.
sumber
Saya menggunakan EF, LINQ ke SQL dan rapi. Dapper adalah yang tercepat. Contoh: Saya membutuhkan 1000 catatan utama dengan masing-masing 4 sub catatan. Saya menggunakan LINQ ke sql, butuh waktu sekitar 6 detik. Saya kemudian beralih ke necis, mengambil 2 kumpulan record dari satu prosedur tersimpan dan untuk setiap record menambahkan sub record. Total waktu 1 detik.
Juga prosedur tersimpan menggunakan fungsi nilai tabel dengan penerapan silang, saya menemukan fungsi nilai skalar menjadi sangat lambat.
Saran saya adalah menggunakan EF atau LINQ ke SQL dan untuk situasi tertentu beralih ke rapi.
sumber
Kerangka Entitas seharusnya tidak menyebabkan kemacetan besar itu sendiri. Kemungkinannya ada penyebab lain. Anda dapat mencoba mengalihkan EF ke Linq2SQL, keduanya memiliki fitur pembanding dan kodenya harus mudah dikonversi tetapi dalam banyak kasus Linq2SQL lebih cepat daripada EF.
sumber