Entity Framework sorgusu yavaş, ancak SqlQuery'deki aynı SQL hızlı


95

NET framework sürüm 4 ile Entity Framework Code-First kullanan çok basit bir sorgu ile ilgili gerçekten garip performanslar görüyorum. LINQ2Entities sorgusu şuna benzer:

 context.MyTables.Where(m => m.SomeStringProp == stringVar);

Bunun yürütülmesi 3000 milisaniyeden fazla sürer. Oluşturulan SQL çok basit görünüyor:

 SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
 ...
 FROM [MyTable] as [Extent1]
 WHERE [Extent1].[SomeStringProp] = '1234567890'

Bu sorgu, Management Studio üzerinden çalıştırıldığında neredeyse anında çalışır. SqlQuery işlevini kullanmak için C # kodunu değiştirdiğimde, 5-10 milisaniye içinde çalışıyor:

 context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeStringProp] = @param", stringVar);

Yani, tamamen aynı SQL, ortaya çıkan varlıklar her iki durumda da değişim izlenir, ancak ikisi arasında çılgın performans farkı vardır. Ne oluyor?


2
Bence başlatma gecikmeleri görüyorsunuz - muhtemelen derlemeyi görüntüleyin. MSDN'ye bakın:Performance Considerations for Entity Framework 5
Nicholas Butler

Görünümleri önceden oluşturmayı denedim ve yardımcı olmadı. Ayrıca, başlatma işlemlerini dışlamak için yavaş olandan önce başka bir EF sorgusu daha çalıştırıldı. İlk sorgu sırasında içerik ısınması olmasına rağmen yeni sorgu hızlı bir şekilde, yavaş olan ise yine de yavaş çalışıyordu.
Brian Sullivan

1
@marc_s - Hayır, SqlQuery, tamamen somutlaştırılmış ve değişiklik izlenen bir varlık örneği döndürecektir. Bkz. Msdn.microsoft.com/en-us/library/…
Brian Sullivan

EF sorgunuz için oluşturulan SQL aslında parametre değerini satır içinde mi yoksa bir parametre mi kullanıyor? Bu, tek bir sorgu için sorgu hızını etkilememelidir, ancak zamanla sunucuda sorgu planı şişmesine neden olabilir.
Jim Wooley

Aynı sorguyu iki kez / birden çok kez çalıştırmayı denediniz mi? İkinci kez koşmak ne kadar sürdü? Bunu .NET Framework 4.5'te denediniz mi - .NET Framework 4.5'te yardımcı olabilecek bazı EF ile ilgili performans geliştirmeleri vardır.
Pawel

Yanıtlar:


97

Buldum. Bunun SQL veri türleriyle ilgili bir sorun olduğu ortaya çıktı. SomeStringPropVeritabanında sütun varchar, ama EF NET dize türleri nvarchars varsayar. DB'nin karşılaştırmayı yapması için sorgu sırasında ortaya çıkan çeviri işlemi, uzun süren şeydir. Sanırım EF Prof beni biraz şaşırttı, çalıştırılan sorgunun daha doğru bir temsili aşağıdaki gibi olurdu:

 SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
 ...
 FROM [MyTable] as [Extent1]
 WHERE [Extent1].[SomeStringProp] = N'1234567890'

Dolayısıyla, sonuçta ortaya çıkan düzeltme, doğru SQL veri türünü gösteren ilk kod modeline açıklama eklemektir:

public class MyTable
{
    ...

    [Column(TypeName="varchar")]
    public string SomeStringProp { get; set; }

    ...
}

1
Güzel soruşturma. Sorgunuz, burada açıklandığı üzere "örtük dönüşümden" muzdaripti: brentozar.com/archive/2012/07/…
Jaime

Beni birkaç saat hata ayıklamadan kurtardı. Sorun buydu.
Cody

1
Benim durumumda, EDMX'i varcharher şey için kullanan eski bir veritabanı ile kullanıyorum ve gerçekten de sorun buydu. Her şey dizge sütunu için varchar'ı dikkate almak için bir EDMX yapabilir miyim acaba?
Alisson

1
Harika bulucu adam. ancak @Jaime, veritabanı ilk yaklaşımı için ne yapmalıyız çünkü her şey (örneğin, db Modellerinde veri açıklamaları), EF modelini veritabanından güncelledikten sonra silip süpürüyor.
Nauman Khan

Bunu bir süreliğine ana sayfam olarak ayarlayarak böylesine harika bir cevap bulmanın heyecanını bir süre daha yeniden yaşayabileyim. Teşekkür ederim!!!
OJisBad

44

EF'de yapılan sorgularımı yavaşlatmanın nedeni, null yapılamayan skalarları null yapılabilir skalarlarla karşılaştırmaktı:

long? userId = 10; // nullable scalar

db.Table<Document>().Where(x => x.User.Id == userId).ToList() // or userId.Value
                                ^^^^^^^^^    ^^^^^^
                                Type: long   Type: long?

Bu sorgu 35 saniye sürdü. Ancak bunun gibi küçük bir yeniden düzenleme:

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

inanılmaz sonuçlar verir. Tamamlanması sadece 50 ms sürdü. EF'de bir hata olması mümkündür.


13
Bu çok garip
Daniel Cardenas

1
AMAN TANRIM. Bu görünüşe göre IUserId.Id arayüzlerini kullanırken de olabilir, ancak ilk önce Id'yi bir tamsayıya eşleme çalışıyor ... 100.000 satırlık uygulamamdaki tüm sorguları şimdi kontrol etmem gerekiyor mu?
Dirk Boer

bu hata rapor edildi mi? Hala en son sürüm 6.2.0
Dirk Boer

2
Aynı sorun EF Core'da da var. Bunu bulduğunuz için teşekkürler!
Yannickv

Diğer bir öneri, değişkeni LINQ ifadesine koymadan önce işlemektir. Aksi takdirde oluşturulan sql çok daha uzun ve daha yavaş olacaktır. Beni rahatsız eden LINQ ifadesi içinde Trim () ve ToLower () olduğunda deneyimledim.
samheihey


4

Aynı sorunu yaşadım (sorgu SQL yöneticisinden çalıştırıldığında hızlıdır) ancak EF'den çalıştırıldığında zaman aşımı sona erer.

Görünümden oluşturulan varlığın yanlış varlık anahtarlarına sahip olduğu ortaya çıktı. Yani varlık aynı anahtarlara sahip yinelenen satırlara sahipti ve sanırım arka planda gruplama yapması gerekiyordu.


3

Ben de karmaşık bir ef sorgusu ile karşılaştım. Benim için 6 saniyelik bir ef sorgusunu, ürettiği alt ikinci sql sorgusuna indirgeyen bir düzeltme, tembel yüklemeyi kapatmak oldu.

Bu ayarı (ef 6) bulmak için .edmx dosyasına gidin ve Özellikler -> Kod oluşturma -> Geç Yükleme Etkin'e bakın. Yanlış olarak ayarlayın.

Benim için performansta büyük gelişme.


4
Harika, ama afiş sorusuyla hiçbir ilgisi yok.
Jace Rhea

2

Ben de bu sorunu yaşadım. Benim durumumdaki suçlu SQL-Server parametre koklamaktı .

Sorunumun aslında parametre koklamadan kaynaklandığına dair ilk ipucu, sorguyu "set arithabort off" veya "set arithabort on" ile çalıştırmanın Management Studio'da büyük ölçüde farklı yürütme süreleri sağlamasıydı. Bunun nedeni, ADO.NET'in varsayılan olarak "arithabort'u kapat" kullanması ve Management Studio'nun varsayılan olarak "arithabort'u açık" olarak ayarlamasıdır. Sorgu planı önbelleği, bu parametreye bağlı olarak farklı planları korur.

Burada bulabileceğiniz çözümle sorgu için sorgu planı önbelleğe almayı devre dışı bıraktım .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.