Saya melihat beberapa kinerja yang sangat aneh terkait dengan kueri yang sangat sederhana menggunakan Entity Framework Code-First dengan .NET framework versi 4. Kueri LINQ2Entities terlihat seperti ini:
context.MyTables.Where(m => m.SomeStringProp == stringVar);
Ini membutuhkan lebih dari 3000 milidetik untuk dieksekusi. SQL yang dihasilkan terlihat sangat sederhana:
SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
...
FROM [MyTable] as [Extent1]
WHERE [Extent1].[SomeStringProp] = '1234567890'
Kueri ini berjalan hampir secara instan saat dijalankan melalui Management Studio. Ketika saya mengubah kode C # untuk menggunakan fungsi SqlQuery, ini berjalan dalam 5-10 milidetik:
context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeStringProp] = @param", stringVar);
Jadi, SQL yang sama persis, entitas yang dihasilkan dilacak perubahannya dalam kedua kasus, tetapi perbedaan kinerja yang liar di antara keduanya. Apa yang memberi?
performance
entity-framework
ef-code-first
Brian Sullivan
sumber
sumber
Performance Considerations for Entity Framework 5
Jawaban:
Menemukannya. Ternyata ini masalah tipe data SQL. The
SomeStringProp
kolom dalam database adalah varchar, tapi EF mengasumsikan bahwa NET tipe string adalah nvarchars. Proses penerjemahan yang dihasilkan selama query untuk DB melakukan perbandingan adalah yang membutuhkan waktu lama. Saya pikir EF Prof sedikit menyesatkan saya di sini, representasi yang lebih akurat dari kueri yang sedang dijalankan adalah sebagai berikut:SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp], ... FROM [MyTable] as [Extent1] WHERE [Extent1].[SomeStringProp] = N'1234567890'
Jadi perbaikan yang dihasilkan adalah menganotasi model code-first, yang menunjukkan tipe data SQL yang benar:
public class MyTable { ... [Column(TypeName="varchar")] public string SomeStringProp { get; set; } ... }
sumber
varchar
untuk semuanya, dan memang inilah masalahnya. Saya ingin tahu apakah saya dapat membuat EDMX untuk mempertimbangkan varchar untuk semua kolom string.Alasan memperlambat kueri yang saya buat di EF adalah membandingkan bukan skalar nullable dengan skalar nullable:
long? userId = 10; // nullable scalar db.Table<Document>().Where(x => x.User.Id == userId).ToList() // or userId.Value ^^^^^^^^^ ^^^^^^ Type: long Type: long?
Kueri itu membutuhkan waktu 35 detik. Tapi refactoring kecil seperti itu:
long? userId = 10; long userIdValue = userId.Value; // I've done that only for the presentation pursposes db.Table<Document>().Where(x => x.User.Id == userIdValue).ToList() ^^^^^^^^^ ^^^^^^^^^^^ Type: long Type: long
memberikan hasil yang luar biasa. Hanya butuh 50ms untuk menyelesaikannya. Mungkin saja itu bug di EF.
sumber
Jika Anda menggunakan pemetaan fluent, Anda dapat menggunakan
IsUnicode(false)
sebagai bagian dari konfigurasi untuk mendapatkan efek yang sama -http://msdn.microsoft.com/en-us/data/jj591617.aspx#1.9
http://msdn.microsoft.com/en-us/library/gg696416%28v=vs.103%29.aspx
sumber
Saya memiliki masalah yang sama (kueri cepat saat dijalankan dari SQL manager) tetapi ketika dieksekusi dari EF batas waktu kedaluwarsa.
Ternyata entitas (yang dibuat dari tampilan) memiliki kunci entitas yang salah. Jadi entitas memiliki baris duplikat dengan kunci yang sama, dan saya rasa itu harus melakukan pengelompokan di latar belakang.
sumber
Saya juga menemukan ini dengan kueri ef yang kompleks. Satu perbaikan bagi saya yang mengurangi kueri ef 6 detik menjadi kueri sql sub kedua yang dihasilkannya adalah mematikan pemuatan lambat.
Untuk menemukan pengaturan ini (ef 6) pergi ke file .edmx dan lihat di Properties -> Pembuatan kode -> Lazy Loading Enabled. Setel ke false.
Peningkatan besar dalam kinerja bagi saya.
sumber
Saya punya masalah ini juga. Ternyata penyebab dalam kasus saya adalah SQL-Server parameter sniffing .
Petunjuk pertama bahwa masalah saya sebenarnya karena parameter sniffing adalah bahwa menjalankan kueri dengan "set arithabort off" atau "set arithabort on" menghasilkan waktu eksekusi yang berbeda secara drastis di Management Studio. Ini karena ADO.NET secara default menggunakan "set arithabort off" dan Management Studio default ke "set arithabort on". Cache paket kueri menyimpan paket yang berbeda bergantung pada parameter ini.
Saya menonaktifkan cache paket kueri untuk kueri tersebut, dengan solusi yang dapat Anda temukan di sini .
sumber