Apakah Kerangka Entitas Cocok Untuk Situs Web Lalu Lintas Tinggi?

176

Apakah Entity Framework 4 solusi yang baik untuk situs web publik dengan potensi 1000 hit / detik?

Dalam pemahaman saya, EF adalah solusi yang layak untuk sebagian besar situs web yang lebih kecil atau intranet, tetapi tidak akan skala dengan mudah untuk sesuatu seperti situs web komunitas populer (saya tahu SO menggunakan LINQ to SQL, tapi .. Saya ingin lebih banyak contoh / bukti. ..)

Sekarang saya berdiri di persimpangan jalan baik memilih pendekatan ADO.NET murni atau EF4. Apakah Anda pikir peningkatan produktivitas pengembang dengan EF sepadan dengan kinerja yang hilang dan akses granular ADO.NET (dengan prosedur tersimpan)? Adakah masalah serius yang mungkin dihadapi situs web dengan traffic tinggi, apakah menggunakan EF?

Terima kasih sebelumnya.

niaher
sumber
1
Anda tidak mengerti penskalaan. Penskalaan berarti mendapatkan throughput 10x saat Anda menambahkan kapasitas 10x. Mengapa EF mencegah hal ini terjadi? Ini menambah overhead faktor konstan ke beban kerja basis data apa pun.
usr

Jawaban:

152

Tergantung sedikit pada seberapa banyak abstraksi yang Anda butuhkan . Semuanya kompromi; misalnya, EF dan NHibernate memperkenalkan fleksibilitas yang besar untuk mewakili data dalam model yang menarik dan eksotis - tetapi sebagai akibatnya mereka lakukan menambah overhead. Overhead yang terlihat.

Jika Anda tidak perlu dapat beralih di antara penyedia basis data, dan tata letak tabel per-klien yang berbeda, dan jika data Anda utamanya dibaca , dan jika Anda tidak perlu dapat menggunakan model yang sama di EF, SSRS , Layanan Data ADO.NET, dll - maka jika Anda ingin kinerja absolut sebagai ukuran utama Anda, Anda bisa melakukan jauh lebih buruk daripada melihat necis . Dalam pengujian kami berdasarkan pada LINQ-to-SQL dan EF, kami menemukan bahwa EF secara signifikan lebih lambat dalam hal kinerja membaca mentah, mungkin karena lapisan abstraksi (antara model penyimpanan dll) dan materialisasi.

Di sini, di SO, kami sangat obsesif-kompulsif tentang kinerja mentah, dan kami senang untuk mengambil pukulan pengembangan kehilangan beberapa abstraksi untuk mendapatkan kecepatan. Dengan demikian, alat utama kami untuk menanyakan database adalah necis . Ini bahkan memungkinkan kita untuk menggunakan model LINQ-to-SQL yang sudah ada sebelumnya, tetapi cukup: ini lebih cepat. Dalam tes kinerja, ini pada dasarnya adalah kinerja yang persis sama dengan menulis semua kode ADO.NET (parameter, data-pembaca dll) secara manual, tetapi tanpa risiko salah nama kolom. Namun, ini berbasis SQL (meskipun senang menggunakan SPROC jika itu adalah racun pilihan Anda). Keuntungan dari ini adalah tidak ada pemrosesan tambahan yang terlibat, tetapi ini adalah sistem untuk orang yang menyukai SQL. Yang saya anggap: bukan hal yang buruk!

Contoh kueri, misalnya, mungkin:

int customerId = ...
var orders = connection.Query<Order>(
    "select * from Orders where CustomerId = @customerId ",
    new { customerId }).ToList();

yang nyaman, injeksi-aman, dll - tetapi tanpa banyak data-reader goo. Perhatikan bahwa meskipun dapat menangani partisi horizontal dan vertikal untuk memuat struktur yang kompleks, ia tidak akan mendukung pemuatan malas (tapi: kami penggemar berat pemuatan yang sangat eksplisit - lebih sedikit kejutan).

Perhatikan dalam jawaban ini saya tidak mengatakan bahwa EF tidak cocok untuk pekerjaan bervolume tinggi; hanya: Saya tahu bahwa necis itu terserah.

Marc Gravell
sumber
25
+1 untuk necis. Menggunakan ORM yang kompleks untuk model baca sama sekali tidak perlu. Pendekatan yang kami ambil sekarang adalah menggunakan ORM untuk model domain kami (di mana hal-hal ORM yang mewah benar-benar berguna) dan necis untuk model baca kami. Ini membuat aplikasi super cepat.
2
@ Mark, terima kasih atas jawaban yang bagus - Saya akhirnya bisa membuat keputusan dengan percaya diri! Pasti akan melihat ke necis lebih detail nanti. Sangat suka bagaimana itu hanya satu file :)
3
Saya menulis ORM saya sendiri. Ini lambat. Saya melihat necis dan menyukainya. Sekarang saya menggunakan necis untuk semua bacaan saya dan ORM saya sendiri untuk memasukkan (yang mendukung FK, transaksi dan semua hal bagus). Ini adalah kode yang paling mudah dibaca yang pernah saya tulis.
2
@ acidzombie24 dapper mendukung transaksi, dan bagian contrib dari dapper (bukan bagian dari penyebaran nuget) mendapatkan opsi insert dll. Hanya menyebutkan untuk kelengkapan. Aku senang necis itu berguna.
Marc Gravell
1
@anyname Saya belum pernah membuat kursus video tentang topik apa pun; ada beberapa video di luar sana, tetapi tidak oleh saya. Saya cenderung menjadi orang yang menulis kata
Marc Gravell
217

Pertanyaan "ORM mana yang harus saya gunakan" benar-benar menargetkan ujung gunung es besar ketika datang ke strategi akses data keseluruhan dan optimasi kinerja dalam aplikasi skala besar.

Semua hal berikut ( kira-kira dalam urutan kepentingan) akan mempengaruhi throughput, dan semuanya ditangani (kadang-kadang dengan cara yang berbeda) oleh sebagian besar kerangka kerja ORM utama di luar sana:

  1. Desain dan Pemeliharaan Basis Data

    Ini, dengan selisih yang lebar, satu-satunya penentu terpenting dari throughput aplikasi berbasis data atau situs web, dan sering kali sama sekali diabaikan oleh para programmer.

    Jika Anda tidak menggunakan teknik normalisasi yang tepat, situs Anda akan hancur. Jika Anda tidak memiliki kunci utama, hampir setiap permintaan akan berjalan lambat. Jika Anda menggunakan anti-pola terkenal seperti menggunakan tabel untuk Pasangan Nilai Kunci (AKA Entity-Attribute-Value) tanpa alasan yang baik, Anda akan meledak jumlah bacaan dan tulisan fisik.

    Jika Anda tidak memanfaatkan fitur yang diberikan oleh database, seperti kompresi halaman, FILESTREAMpenyimpanan (untuk data biner), SPARSEkolom, hierarchyiduntuk hierarki, dan sebagainya (semua contoh SQL Server), maka Anda tidak akan melihat di dekat kinerja yang bisa Anda lihat.

    Anda harus mulai mengkhawatirkan strategi akses data Anda setelah merancang basis data dan meyakinkan diri sendiri bahwa itu sebaik mungkin, setidaknya untuk saat ini.

  2. Pemuatan bersemangat vs malas

    Sebagian besar ORM menggunakan teknik yang disebut lazy loading untuk hubungan, yang berarti bahwa secara default akan memuat satu entitas (baris tabel) sekaligus, dan melakukan perjalanan bolak-balik ke database setiap kali perlu memuat satu atau banyak yang terkait (asing). kunci) baris.

    Ini bukan hal yang baik atau buruk, itu lebih tergantung pada apa yang sebenarnya akan dilakukan dengan data, dan seberapa banyak Anda tahu di muka. Terkadang lazy-loading adalah hal yang benar untuk dilakukan. NHibernate, misalnya, dapat memutuskan untuk tidak meminta apa pun dan hanya menghasilkan proxy untuk ID tertentu. Jika yang Anda butuhkan hanyalah ID itu sendiri, mengapa harus meminta lebih banyak? Di sisi lain, jika Anda mencoba untuk mencetak pohon dari setiap elemen tunggal dalam hirarki 3-level, pemuatan malas menjadi operasi O (N²), yang sangat buruk untuk kinerja.

    Satu manfaat menarik untuk menggunakan "SQL murni" (yaitu, permintaan / prosedur tersimpan ADO.NET mentah) adalah pada dasarnya memaksa Anda untuk berpikir secara tepat data apa yang diperlukan untuk menampilkan layar atau halaman tertentu. ORMs dan fitur malas-loading tidak mencegah Anda dari melakukan hal ini, tetapi mereka tidak memberi Anda kesempatan untuk menjadi ... baik, malas , dan tidak sengaja meledak jumlah pertanyaan yang Anda jalankan. Jadi, Anda perlu memahami fitur pemuatan cepat ORM Anda dan selalu waspada tentang jumlah kueri yang Anda kirim ke server untuk setiap permintaan halaman yang diberikan.

  3. Caching

    Semua ORM utama mempertahankan cache tingkat pertama, "cache identitas" AKA, yang berarti bahwa jika Anda meminta entitas yang sama dua kali dengan ID-nya, itu tidak memerlukan perjalanan pulang-pergi kedua, dan juga (jika Anda mendesain database Anda dengan benar ) memberi Anda kemampuan untuk menggunakan konkurensi optimis.

    Cache L1 cukup buram di L2S dan EF, Anda harus percaya bahwa itu berfungsi. NHibernate lebih eksplisit tentang hal itu ( Get/ Loadvs. Query/ QueryOver). Namun, selama Anda mencoba untuk query dengan ID sebanyak mungkin, Anda harus baik-baik saja di sini. Banyak orang lupa tentang cache L1 dan berulang kali mencari entitas yang sama berulang-ulang dengan sesuatu selain ID-nya (yaitu bidang pencarian). Jika Anda perlu melakukan ini maka Anda harus menyimpan ID atau bahkan seluruh entitas untuk pencarian di masa mendatang.

    Ada juga cache level 2 ("cache permintaan"). NHibernate memiliki fitur bawaan ini. Linq to SQL dan Entity Framework telah mengkompilasi kueri , yang dapat membantu mengurangi banyak server aplikasi dengan mengkompilasi ekspresi kueri itu sendiri, tetapi itu tidak menyimpan data. Microsoft tampaknya menganggap ini masalah aplikasi daripada masalah akses data, dan ini adalah titik kelemahan utama dari L2S dan EF. Tak perlu dikatakan itu juga merupakan titik lemah dari SQL "mentah". Untuk mendapatkan kinerja yang benar-benar bagus dengan ORM apa pun selain NHibernate, Anda perlu mengimplementasikan façade caching Anda sendiri.

    Ada juga "ekstensi" cache L2 untuk EF4 yang baik - baik saja , tetapi tidak benar-benar pengganti grosir untuk cache tingkat aplikasi.

  4. Jumlah Pertanyaan

    Database relasional didasarkan pada set data. Mereka benar-benar hebat dalam menghasilkan data dalam jumlah besar dalam waktu singkat, tetapi mereka sama sekali tidak sebagus dalam hal latensi kueri karena ada sejumlah overhead tertentu yang terlibat dalam setiap perintah. Aplikasi yang dirancang dengan baik harus memainkan kekuatan dari DBMS ini dan mencoba untuk meminimalkan jumlah pertanyaan dan memaksimalkan jumlah data di masing-masing.

    Sekarang saya tidak mengatakan untuk menanyakan seluruh database ketika Anda hanya perlu satu baris. Apa yang saya katakan adalah, jika Anda memerlukan Customer, Address, Phone, CreditCard, dan Orderbaris semua pada waktu yang sama untuk melayani satu halaman, maka Anda harus meminta untuk mereka semua pada waktu yang sama, tidak mengeksekusi setiap query secara terpisah. Terkadang lebih buruk dari itu, Anda akan melihat kode yang meminta Customercatatan yang sama 5 kali berturut-turut, pertama untuk mendapatkan Id, lalu Name, lalu EmailAddress, kemudian ... itu sangat tidak efisien.

    Bahkan jika Anda perlu menjalankan beberapa query yang semuanya beroperasi pada set data yang sama sekali berbeda, biasanya masih lebih efisien untuk mengirim semuanya ke database sebagai "skrip" tunggal dan mengembalikan beberapa set hasil. Ini adalah overhead yang Anda khawatirkan, bukan jumlah total data.

    Ini mungkin terdengar seperti akal sehat tetapi seringkali sangat mudah untuk kehilangan jejak semua pertanyaan yang sedang dieksekusi di berbagai bagian aplikasi; Penyedia Keanggotaan Anda kueri tabel pengguna / peran, tindakan Header Anda kueri keranjang belanja, tindakan Menu Anda kueri tabel peta situs, tindakan Sidebar Anda menanyakan daftar produk unggulan, dan kemudian mungkin halaman Anda dibagi menjadi beberapa area otonom terpisah yang kueri tabel Riwayat Pesanan, Baru Dilihat, Kategori, dan Inventaris secara terpisah, dan sebelum Anda mengetahuinya, Anda mengeksekusi 20 kueri bahkan sebelum Anda dapat mulai melayani halaman. Itu benar-benar menghancurkan kinerja.

    Beberapa kerangka kerja - dan saya berpikir terutama dari NHibernate di sini - sangat pandai tentang hal ini dan memungkinkan Anda untuk menggunakan sesuatu yang disebut futures yang mengumpulkan seluruh pertanyaan dan mencoba mengeksekusi semuanya sekaligus, pada menit terakhir yang memungkinkan. AFAIK, Anda sendirian jika ingin melakukan ini dengan salah satu teknologi Microsoft; Anda harus membuatnya menjadi logika aplikasi Anda.

  5. Pengindeksan, Predikat, dan Proyeksi

    Setidaknya 50% dari devs yang saya ajak bicara dan bahkan beberapa DBA tampaknya memiliki masalah dengan konsep mencakup indeks. Mereka berpikir, "well, Customer.Namekolomnya diindeks, jadi setiap pencarian yang saya lakukan atas nama harus cepat." Kecuali itu tidak berfungsi seperti itu kecuali Nameindeks mencakup kolom spesifik yang Anda cari. Dalam SQL Server, yang dilakukan dengan INCLUDEdalam CREATE INDEXpernyataan.

    Jika Anda menggunakan secara naif di SELECT *mana-mana - dan itu lebih atau kurang dari apa yang akan dilakukan setiap ORM kecuali Anda secara eksplisit menentukan lain menggunakan proyeksi - maka DBMS mungkin sangat memilih untuk sepenuhnya mengabaikan indeks Anda karena mengandung kolom yang tidak tercakup. Proyeksi berarti bahwa, misalnya, daripada melakukan ini:

    from c in db.Customers where c.Name == "John Doe" select c
    

    Anda melakukan ini sebagai gantinya:

    from c in db.Customers where c.Name == "John Doe"
    select new { c.Id, c.Name }
    

    Dan kehendak ini, untuk sebagian besar ORMs modern, menginstruksikan untuk hanya pergi dan query Iddan Namekolom yang mungkin ditutupi oleh indeks (tapi bukan Email, LastActivityDate, atau apa pun kolom yang kebetulan menempel di sana lain).

    Ini juga sangat mudah untuk sepenuhnya menghilangkan manfaat pengindeksan dengan menggunakan predikat yang tidak pantas. Sebagai contoh:

    from c in db.Customers where c.Name.Contains("Doe")
    

    ... terlihat hampir identik dengan permintaan kami sebelumnya tetapi pada kenyataannya akan menghasilkan tabel penuh atau pemindaian indeks karena diterjemahkan menjadi LIKE '%Doe%'. Demikian pula, permintaan lain yang terlihat sederhana dan mencurigakan adalah:

    from c in db.Customers where (maxDate == null) || (c.BirthDate >= maxDate)
    

    Dengan asumsi Anda memiliki indeks BirthDate, predikat ini memiliki peluang bagus untuk menjadikannya benar-benar tidak berguna. Programmer hipotetis kami di sini jelas telah berusaha membuat semacam kueri dinamis ("hanya filter tanggal lahir jika parameter itu ditentukan"), tetapi ini bukan cara yang tepat untuk melakukannya. Ditulis seperti ini sebagai gantinya:

    from c in db.Customers where c.BirthDate >= (maxDate ?? DateTime.MinValue)
    

    ... sekarang mesin DB tahu bagaimana membuat parameter ini dan melakukan pencarian indeks. Satu perubahan kecil, yang tampaknya tidak signifikan terhadap ekspresi kueri dapat secara drastis memengaruhi kinerja.

    Sayangnya LINQ secara umum membuat semuanya terlalu mudah untuk menulis kueri buruk seperti ini karena kadang - kadang penyedia dapat menebak apa yang Anda coba lakukan dan mengoptimalkan kueri, dan kadang-kadang tidak. Jadi, Anda berakhir dengan hasil yang sangat tidak konsisten yang pasti sangat menyolok (untuk DBA yang berpengalaman), seandainya Anda baru saja menulis SQL lama.

    Pada dasarnya itu semua bermuara pada fakta bahwa Anda benar-benar harus mengawasi baik-baik SQL yang dihasilkan dan rencana eksekusi yang mereka tuju, dan jika Anda tidak mendapatkan hasil yang Anda harapkan, jangan takut untuk mem-bypass Lapisan ORM sesekali dan tangan-kode SQL. Ini berlaku untuk ORM apa pun , tidak hanya EF.

  6. Transaksi dan Penguncian

    Apakah Anda perlu menampilkan data yang terkini hingga milidetik? Mungkin - itu tergantung - tetapi mungkin tidak. Sayangnya, Entity Framework tidak memberi Andanolock , Anda hanya dapat menggunakan READ UNCOMMITTEDdi level transaksi (bukan level tabel). Faktanya tidak ada ORM yang bisa diandalkan tentang hal ini; jika Anda ingin melakukan pembacaan yang kotor, Anda harus turun ke tingkat SQL dan menulis pertanyaan ad-hoc atau prosedur yang tersimpan. Jadi intinya, sekali lagi, adalah betapa mudahnya bagi Anda untuk melakukan itu dalam kerangka kerja.

    Entity Framework telah datang jauh dalam hal ini - versi 1 dari EF (dalam .NET 3.5) sangat mengerikan, membuatnya sangat sulit untuk menembus abstraksi "entitas", tetapi sekarang Anda memiliki ExecuteStoreQuery dan Translate , jadi itu benar-benar lumayan. Bertemanlah dengan orang-orang ini karena Anda akan sering menggunakannya.

    Ada juga masalah menulis penguncian dan kebuntuan dan praktik umum memegang kunci dalam database sesedikit mungkin. Dalam hal ini, sebagian besar ORM (termasuk Entity Framework) sebenarnya cenderung lebih baik daripada SQL mentah karena mereka merangkum unit pola Kerja , yang dalam EF adalah SaveChanges . Dengan kata lain, Anda dapat "menyisipkan" atau "memperbarui" atau "menghapus" entitas ke isi hati Anda, kapan pun Anda mau, aman dengan pengetahuan bahwa tidak ada perubahan yang akan didorong ke database hingga Anda melakukan unit kerja.

    Perhatikan bahwa UOW tidak analog dengan transaksi yang sudah berjalan lama. UOW masih menggunakan fitur konkurensi optimis dari ORM dan melacak semua perubahan dalam memori . Tidak satu pun pernyataan DML yang dikeluarkan sampai komit terakhir. Ini menjaga waktu transaksi serendah mungkin. Jika Anda membangun aplikasi menggunakan SQL mentah, cukup sulit untuk mencapai perilaku yang ditangguhkan ini.

    Apa artinya ini untuk EF secara spesifik: Jadikan unit kerja Anda seringkas mungkin dan jangan komit sampai Anda benar-benar perlu. Lakukan ini dan Anda akan berakhir dengan pertentangan kunci yang jauh lebih rendah daripada yang Anda akan gunakan perintah ADO.NET individu pada waktu yang acak.

Kesimpulannya:

EF benar-benar baik untuk aplikasi lalu lintas tinggi / kinerja tinggi, sama seperti setiap kerangka kerja lainnya baik untuk aplikasi lalu lintas tinggi / kinerja tinggi. Yang penting adalah bagaimana Anda menggunakannya. Berikut ini adalah perbandingan cepat kerangka kerja paling populer dan fitur apa yang mereka tawarkan dalam hal kinerja (legenda: N = Tidak didukung, P = Sebagian, Y = ya / didukung):

                                | L2S | EF1 | EF4 | NH3 | ADO
                                +-----+-----+-----+-----+-----
Lazy Loading (entities)         |  N  |  N  |  N  |  Y  |  N
Lazy Loading (relationships)    |  Y  |  Y  |  Y  |  Y  |  N
Eager Loading (global)          |  N  |  N  |  N  |  Y  |  N
Eager Loading (per-session)     |  Y  |  N  |  N  |  Y  |  N
Eager Loading (per-query)       |  N  |  Y  |  Y  |  Y  |  Y
Level 1 (Identity) Cache        |  Y  |  Y  |  Y  |  Y  |  N
Level 2 (Query) Cache           |  N  |  N  |  P  |  Y  |  N
Compiled Queries                |  Y  |  P  |  Y  |  N  | N/A
Multi-Queries                   |  N  |  N  |  N  |  Y  |  Y
Multiple Result Sets            |  Y  |  N  |  P  |  Y  |  Y
Futures                         |  N  |  N  |  N  |  Y  |  N
Explicit Locking (per-table)    |  N  |  N  |  N  |  P  |  Y
Transaction Isolation Level     |  Y  |  Y  |  Y  |  Y  |  Y
Ad-Hoc Queries                  |  Y  |  P  |  Y  |  Y  |  Y
Stored Procedures               |  Y  |  P  |  Y  |  Y  |  Y
Unit of Work                    |  Y  |  Y  |  Y  |  Y  |  N

Seperti yang Anda lihat, EF4 (versi saat ini) tidak terlalu mahal, tetapi mungkin bukan yang terbaik jika kinerja menjadi perhatian utama Anda. NHibernate jauh lebih matang di bidang ini dan bahkan Linq to SQL menyediakan beberapa fitur peningkatan kinerja yang EF masih belum. Raw ADO.NET sering akan lebih cepat untuk skenario akses data yang sangat spesifik , tetapi, ketika Anda menggabungkan semua bagian, itu benar-benar tidak menawarkan banyak manfaat penting yang Anda dapatkan dari berbagai kerangka kerja.

Dan, hanya untuk memastikan bahwa saya terdengar seperti rekaman yang rusak, semua ini tidak ada masalah sedikitpun jika Anda tidak merancang database, aplikasi, dan strategi akses data Anda dengan benar. Semua item dalam bagan di atas adalah untuk meningkatkan kinerja di luar garis dasar; sebagian besar waktu, baseline itu sendiri adalah yang paling membutuhkan perbaikan.

Aaronaught
sumber
38
Sungguh jawaban yang luar biasa dan komprehensif!
2
+1 (lebih banyak jika saya bisa) - salah satu jawaban terbaik yang pernah saya lihat di sini dan saya belajar satu atau dua hal - terima kasih telah berbagi ini!
BrokenGlass
1
Ini jawaban yang bagus bahkan saya tidak setuju dengan semua yang disebutkan. Tabel yang membandingkan ORM tidak selalu benar. Apa itu pemuatan entitas yang malas? Apakah maksud Anda kolom yang dimuat malas? Itu didukung dalam L2S. Menurut Anda mengapa NH tidak mendukung kueri yang dikompilasi? Saya pikir pertanyaan bernama HQL dapat dikompilasi sebelumnya. EF4 tidak memiliki dukungan untuk beberapa set hasil.
Ladislav Mrnka
11
Saya harus sangat tidak setuju dengan pernyataan "EF yang tidak memenuhi syarat untuk aplikasi lalu lintas tinggi / kinerja tinggi", kami telah melihat berulang kali bahwa ini bukan masalahnya. Memang, mungkin kita tidak setuju tentang apa artinya "kinerja tinggi", tetapi misalnya mengoptimalkan halaman web hingga 500 ms dan memiliki 400ms lebih dari yang dihabiskan secara tidak dapat dijelaskan di dalam kerangka kerja (dan hanya 10ms yang benar-benar mengenai SQL) tidak "baik" untuk beberapa situasi, itu benar-benar tidak dapat diterima untuk tim dev kami.
Nick Craver
1
Catatan sederhana tentang masa depan di EF. Mereka tidak secara resmi disediakan oleh tim MS EF tetapi dapat dicapai melalui proyek pihak ketiga yang menentukan ekstensi Future <> ke IQueryable <>. Misalnya EntityFramework.Extended oleh LoreSoft, tersedia di NuGet. Tes pribadi saya dalam aplikasi produksi menunjukkan peningkatan kinerja hingga 10x saat mengemas lusinan kueri yang tidak bergantung (semua kueri dapat dieksekusi secara paralel, tidak ada yang memerlukan hasil yang sebelumnya) dalam satu batch menggunakan Future. AsNoTracking () juga banyak meningkatkan kinerja ketika hanya membaca banyak catatan, tidak ada pembaruan yang lebih baru.
David Oliván Ubieto
38

Sunting: Berdasarkan pada @Aaronaught jawaban yang bagus Saya menambahkan beberapa poin yang menargetkan kinerja dengan EF. Poin-poin baru diawali oleh Edit.


Peningkatan terbesar dalam kinerja di situs web dengan lalu lintas tinggi dicapai dengan caching (= pertama-tama menghindari pemrosesan server web atau permintaan basis data) diikuti dengan pemrosesan asinkron untuk menghindari pemblokiran thread saat query basis data dilakukan.

Tidak ada jawaban bukti peluru untuk pertanyaan Anda karena selalu tergantung pada persyaratan untuk aplikasi dan pada kompleksitas pertanyaan. Yang benar adalah bahwa produktivitas pengembang dengan EF menyembunyikan kompleksitas di baliknya yang dalam banyak kasus menyebabkan penggunaan EF yang salah dan kinerja yang buruk. Gagasan bahwa Anda dapat mengekspos antarmuka abstrak tingkat tinggi untuk akses data dan itu akan berfungsi dengan baik dalam semua kasus tidak bekerja. Bahkan dengan ORM Anda harus tahu apa yang terjadi di balik abstraksi dan bagaimana menggunakannya dengan benar.

Jika Anda tidak memiliki pengalaman sebelumnya dengan EF, Anda akan menghadapi banyak tantangan saat berhadapan dengan kinerja. Anda dapat membuat lebih banyak kesalahan saat bekerja dengan EF dibandingkan dengan ADO.NET. Juga ada banyak pemrosesan tambahan yang dilakukan di EF, sehingga EF akan selalu jauh lebih lambat daripada ADO.NET asli - itu adalah sesuatu yang dapat Anda ukur dengan bukti sederhana aplikasi konsep.

Jika Anda ingin mendapatkan kinerja terbaik dari EF, Anda kemungkinan besar harus:

  • Sangat hati-hati merevisi akses data Anda dengan SQL profiler dan meninjau permintaan LINQ Anda jika mereka benar menggunakan Linq-to-entitas, bukan Linq-to-objects
  • Sangat hati-hati menggunakan fitur pengoptimalan EF canggih seperti MergeOption.NoTracking
  • Gunakan ESQL dalam beberapa kasus
  • Pra-kompilasi permintaan yang sering dieksekusi
  • Pikirkan tentang mengambil keuntungan dari pembungkus Caching EF untuk mendapatkan "cache level kedua" seperti fitur untuk beberapa pertanyaan
  • Gunakan tampilan SQL atau kueri SQL yang dipetakan khusus (memerlukan pemeliharaan manual file EDMX) dalam beberapa skenario untuk proyeksi atau agregasi yang sering digunakan yang memerlukan peningkatan kinerja
  • Gunakan SQL asli dan prosedur tersimpan untuk beberapa permintaan yang tidak memberikan kinerja yang memadai ketika didefinisikan dalam Linq atau ESQL
  • Sunting: Hati-hati menggunakan kueri - setiap kueri membuat bolak-balik terpisah ke database. EFv4 tidak memiliki batching query karena tidak dapat menggunakan beberapa set hasil per perintah database yang dieksekusi. EFv4.5 akan mendukung beberapa set hasil untuk prosedur tersimpan yang dipetakan.
  • Sunting: Bekerja dengan hati-hati dengan modifikasi data. Lagi-lagi EF sama sekali tidak memiliki batching perintah . Jadi di ADO.NET Anda dapat menggunakan single yang SqlCommandberisi banyak insert, pembaruan atau penghapusan tetapi dengan EF setiap perintah tersebut akan dieksekusi secara terpisah ke database.
  • Sunting: Bekerja dengan hati-hati dengan peta identitas / cache identitas. EF memiliki metode khusus ( GetByKeydi ObjectContext API atau Finddi DbContext API) untuk menanyakan cache terlebih dahulu. Jika Anda menggunakan Linq-to-entitas atau ESQL, ia akan membuat bolak-balik ke database dan setelah itu akan mengembalikan instance yang ada dari cache.
  • Sunting: Hati-hati menggunakan pemuatan bersemangat. Ini tidak selalu merupakan solusi win-win karena menghasilkan satu dataset besar . Seperti yang Anda lihat itu banyak kompleksitas tambahan dan itulah intinya. ORM membuat pemetaan dan materialisasi lebih sederhana tetapi ketika berhadapan dengan kinerja, itu akan membuatnya jauh lebih kompleks dan Anda harus melakukan trade-off.

Saya tidak yakin apakah SO masih menggunakan L2S. Mereka mengembangkan ORM open source baru yang disebut Dapper dan saya pikir poin utama di balik pengembangan ini adalah peningkatan kinerja.

Ladislav Mrnka
sumber
Ladislav, itu jawaban yang sangat membantu. Ini adalah pertama kalinya saya mendengar tentang Dapper (dan akibatnya menemukan PetaPoco, Massive) - dan sepertinya ide yang menarik.
1
SO tampaknya menggunakan campuran LINQ ke SQL dan Dapper sekarang: samsaffron.com/archive/2011/03/30/… Quote: "Kami menggunakan ORM [Dapper] baru kami untuk masalah tertentu: memetakan parameterisasi SQL ke objek bisnis Kami tidak menggunakannya sebagai ORM penuh sesak nafas. Itu tidak melakukan hubungan dan lonceng dan peluit lainnya. Ini memungkinkan kami untuk terus menggunakan LINQ-2-SQL di mana kinerja tidak masalah dan port semua SQL inline kami untuk menggunakan mapper kami, karena lebih cepat dan lebih fleksibel. "
5
@Sumauma baik, itu adalah pernyataan dari bulan lalu, secara umum semua pekerjaan baru pada SO dilakukan di Dapper, misalnya tabel baru yang saya tambahkan hari ini bahkan tidak ada dalam file dbml.
Sam Saffron
1
@ Sam: Apakah ada posting blog baru tentang strategi akses data saat ini di SO? Akan sangat menarik! Apakah Dapper telah diperpanjang sementara itu? Pemahaman saya adalah bahwa Dapper bukan ORM lengkap, tidak ada dukungan hubungan - dan bagaimana dengan pembaruan, menyisipkan, menghapus, transaksi, mengubah pelacakan, dll.