Megosztás:


Teljesítménydiagnosztikák

Ez a szakasz a teljesítményproblémák ef-alkalmazásban való észlelésének módjait ismerteti, és miután azonosított egy problémás területet, hogyan elemezheti tovább őket a kiváltó probléma azonosítása érdekében. Fontos, hogy a következtetések levonása előtt gondosan diagnosztizálja és vizsgálja meg a problémákat, és ne feltételezzük, hogy hol van a probléma gyökere.

Lassú adatbázis-parancsok azonosítása naplózással

A nap végén az EF előkészíti és végrehajtja az adatbázison végrehajtandó parancsokat; relációs adatbázissal, ez azt jelenti, hogy SQL-utasítások végrehajtása a ADO.NET adatbázis API-jával. Ha egy adott lekérdezés túl sok időt vesz igénybe (például azért, mert egy index hiányzik), ez a parancsvégrehajtási naplók vizsgálatával és a tényleges időtartam megfigyelésével tekinthető meg.

Az EF egyszerű naplózással vagy a Microsoft.Extensions.Logging használatával nagyon egyszerűen rögzíti a parancsok végrehajtási idejét:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0")
        .LogTo(Console.WriteLine, LogLevel.Information);
}

A naplózási szint beállításakor LogLevel.Informationaz EF minden parancsvégrehajtáshoz egy naplóüzenetet küld, amely a következő időt veszi igénybe:

info: 06/12/2020 09:12:36.117 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [b].[Id], [b].[Name]
      FROM [Blogs] AS [b]
      WHERE [b].[Name] = N'foo'

A fenti parancs 4 ezredmásodpercig tartott. Ha egy adott parancs a vártnál több időt vesz igénybe, talált egy lehetséges bűnöst egy teljesítményproblémához, és most már arra összpontosíthat, hogy megértse, miért fut lassan. A parancsnaplózás azokat az eseteket is feltárhatja, amikor nem várt adatbázis-kerekítéseket végeznek; ez több parancsként jelenik meg, ahol csak egy várható.

Figyelmeztetés

A parancsvégrehajtás naplózásának engedélyezése az éles környezetben általában rossz ötlet. Maga a naplózás lelassítja az alkalmazást, és gyorsan hatalmas naplófájlokat hozhat létre, amelyek feltölthetik a kiszolgáló lemezét. Javasoljuk, hogy csak rövid ideig maradjon bejelentkezve az adatok gyűjtéséhez – az alkalmazás gondos figyelése mellett –, vagy a naplózási adatok éles üzem előtti rendszereken történő rögzítéséhez.

Adatbázis-parancsok korrelációja LINQ-lekérdezésekkel

A parancsvégrehajtás naplózásának egyik problémája, hogy néha nehéz korrelálni az SQL-lekérdezéseket és a LINQ-lekérdezéseket: az EF által végrehajtott SQL-parancsok nagyon eltérőek lehetnek azoktól a LINQ-lekérdezésektől, amelyekből létrehozták őket. A probléma megoldásához érdemes lehet használni az EF lekérdezéscímkéinek funkcióját, amely lehetővé teszi, hogy egy kis, azonosító megjegyzést szúrjon be az SQL-lekérdezésbe:

var myLocation = new Point(1, 2);
var nearestPeople = await (from f in context.People.TagWith("This is my spatial query!")
                     orderby f.Location.Distance(myLocation) descending
                     select f).Take(5).ToListAsync();

A címke megjelenik a naplókban:

-- This is my spatial query!

SELECT TOP(@__p_1) [p].[Id], [p].[Location]
FROM [People] AS [p]
ORDER BY [p].[Location].STDistance(@__myLocation_0) DESC

Gyakran érdemes így megjelölni egy alkalmazás fő lekérdezéseit, hogy a parancsvégrehajtási naplók azonnal olvashatóbbak legyenek.

Egyéb felületek a teljesítményadatok rögzítéséhez

Az EF naplózási funkciójának különböző alternatívái vannak a parancsvégrehajtási idők rögzítésére, ami hatékonyabb lehet. Az adatbázisok jellemzően saját nyomkövetési és teljesítményelemzési eszközökkel is rendelkeznek, amelyek általában sokkal gazdagabb, adatbázisspecifikus információkat nyújtanak az egyszerű végrehajtási időken túl; a tényleges beállítás, képességek és használat jelentősen eltérnek az adatbázisoktól.

Az SQL Server Management Studio például egy hatékony ügyfél, amely képes csatlakozni az SQL Server-példányhoz, és értékes felügyeleti és teljesítményinformációkat nyújt. A szakasz hatókörén kívül esik a részletekbe, de két olyan képességet érdemes megemlíteni, mint a Tevékenységfigyelő, amely a kiszolgálói tevékenység élő irányítópultját (beleértve a legdrágább lekérdezéseket) és a Kiterjesztett események (XEvent) funkciót biztosítja, amely lehetővé teszi tetszőleges adatrögzítési munkamenetek meghatározását, amelyek pontosan az Ön igényeire szabhatók. Az SQL Server monitorozási dokumentációja további információkat nyújt ezekről a funkciókról, valamint másokról is.

A teljesítményadatok rögzítésének másik módszere az EF vagy az adatbázis-illesztő által automatikusan kibocsátott adatok összegyűjtése a DiagnosticSource felületen keresztül, majd az adatok elemzése vagy megjelenítése egy irányítópulton. Ha az Azure-t használja, akkor az Azure Application Insights olyan hatékony monitorozást biztosít a dobozból, amely integrálja az adatbázis teljesítményét és a lekérdezések végrehajtási idejét a webes kérelmek kézbesítésének gyors elemzésében. Erről további információt az Application Insights teljesítmény-oktatóanyagában és az Azure SQL Analytics oldalán talál.

Lekérdezés-végrehajtási tervek vizsgálata

Miután meghatározta az optimalizálást igénylő problémás lekérdezést, a következő lépés általában a lekérdezés végrehajtási tervének elemzése. Amikor az adatbázisok SQL-utasítást kapnak, általában a terv végrehajtásának tervét készítik el; ez néha bonyolult döntéshozatalt igényel annak alapján, hogy mely indexeket határozták meg, mennyi adat található a táblákban stb. (egyébként magát a tervet általában gyorsítótárazza a kiszolgáló az optimális teljesítmény érdekében). A relációs adatbázisok általában módot biztosítanak a felhasználók számára a lekérdezésterv megtekintésére, valamint a lekérdezés különböző részeinek számított költségszámítására; ez felbecsülhetetlen értékű a lekérdezések javításához.

Az SQL Server használatának megkezdéséhez tekintse meg a lekérdezés-végrehajtási tervek dokumentációját. A tipikus elemzési munkafolyamat az SQL Server Management Studio használata, a fenti eszközök egyikével azonosított lassú lekérdezés SQL-jének beillesztése és egy grafikus végrehajtási terv létrehozása:

SQL Server végrehajtási tervének megjelenítése

Bár a végrehajtási tervek elsőre bonyolultnak tűnhetnek, érdemes egy kis időt tölteni az ismerkedéssel. Különösen fontos megjegyezni a terv egyes csomópontjaihoz kapcsolódó költségeket, és azonosítani, hogyan használják az indexeket (vagy sem) a különböző csomópontokban.

Bár a fenti információk az SQL Serverre vonatkoznak, más adatbázisok általában ugyanazokat az eszközöket biztosítják hasonló vizualizációval.

Fontos

Az adatbázisok néha különböző lekérdezési terveket hoznak létre az adatbázisban lévő tényleges adatoktól függően. Ha például egy tábla csak néhány sort tartalmaz, az adatbázisok dönthetnek úgy, hogy nem indexet használnak a táblán, hanem teljes táblázatvizsgálatot végeznek. Tesztadatbázison történő lekérdezési tervek elemzésekor mindig győződjön meg arról, hogy a rendszerében lévő adatokhoz hasonlóakat tartalmaz.

Mértékek

A fenti szakaszok a parancsokkal kapcsolatos információk lekérésére és a parancsok végrehajtásának módjára összpontosítottak az adatbázisban. Emellett az EF több olyan metrikát is elérhetővé tesz, amelyek alacsonyabb szintű információkat nyújtanak arról, hogy mi történik magában az EF-ben, és hogy az alkalmazás hogyan használja azt. Ezek a metrikák nagyon hasznosak lehetnek bizonyos teljesítményproblémák és teljesítményanomáliák diagnosztizálásához, például a lekérdezések gyorsítótárazási problémáihoz , amelyek állandó újrafordítást, nem feltárt DbContext-szivárgásokat és más problémákat okoznak.

További információért tekintse meg az EF metrikáinak dedikált oldalát.

Teljesítménytesztelés az EF Core-val

A nap végén néha tudnia kell, hogy a lekérdezések írásának vagy végrehajtásának egy adott módja gyorsabb-e, mint egy másik. Fontos, hogy soha ne feltételezzük vagy spekuláljuk meg a választ, és rendkívül könnyű összeállítani egy gyors teljesítménytesztet a válaszhoz. A teljesítménytesztek írásakor erősen ajánlott a jól ismert BenchmarkDotNet-kódtár használata, amely számos olyan buktatót kezel, amelyekkel a felhasználók szembesülnek, amikor saját teljesítményteszteket próbálnak írni: végrehajtott néhány bemelegítési iterációt? Valójában hány iteráció fut a teljesítménytesztben, és miért? Tekintsük át, hogyan néz ki egy EF Core-teljesítményteszt.

Jótanács

Az alábbi forrás teljes referenciaprojektje itt érhető el. Javasoljuk, hogy másolja és használja sablonként a saját teljesítménymutatóihoz.

Egyszerű referenciaforgatókönyvként hasonlítsuk össze az alábbi módszereket az adatbázis összes blogjának átlagos rangsorolásának kiszámításához:

  • Töltse be az összes entitást, foglalja össze az egyes rangsorokat, és számítsa ki az átlagot.
  • A fentiekhez hasonlóan csak nem követési lekérdezést használjon. Ennek gyorsabbnak kell lennie, mivel az identitásfeloldás nem kerül végrehajtásra, és az entitásokról nem készül pillanatkép a változáskövetés céljából.
  • Kerülje a teljes Blog entitás betöltését, és csak a rangsort vetítse ki. Ez megkímél minket a másik, szükségtelen oszlopok átvitelétől a Blog entitástípusban.
  • Az adatbázis átlagának kiszámítása a lekérdezés részévé tételével. Ennek kell lennie a leggyorsabb módszernek, mivel minden számítás az adatbázisban történik, és csak az eredmény kerül vissza az ügyfélnek.

A BenchmarkDotNet használatával a teljesítményteszthez használt kódot egyszerű módszerként kell megírni – akárcsak egy egységtesztet –, és a BenchmarkDotNet automatikusan futtatja az egyes metódusokat a megfelelő számú iterációhoz, megbízhatóan mérve, hogy mennyi ideig tart, és mennyi memóriát foglal le. Íme a különböző módszerek (a teljes referenciakód itt látható):

[Benchmark]
public async Task<double> LoadEntities()
{
    var sum = 0;
    var count = 0;
    using var ctx = new BloggingContext();
    await foreach (var blog in ctx.Blogs.AsAsyncEnumerable())
    {
        sum += blog.Rating;
        count++;
    }

    return (double)sum / count;
}

Az eredmények az alábbi, a BenchmarkDotNet által kinyomtatott módon jelennek meg:

Metódus Jelent Hiba StdDev Medián Arány RatioSD Gen 0 Gen 1 Gen 2 Kiosztott
LoadEntities 2860,4 us 54.31 us 93.68 us 2 844,5 us 4,55 0.33. 210.9375 70.3125 - 1309.56 KB
LoadEntitiesNoTracking 1 353,0 us 21.26 us 18.85 us 1 355,6 us 2.10 0,14 87.8906 3,9063 - 540.09 KB
CsakProjektRangsor 910.9 us 20.91 us 61.65 us 892.9 us 1.46 0,14 41.0156 0.9766 - 252.08 KB
Számítás az adatbázisban 627.1 us 14.58 us 42.54 us 626.4 us 1,00 0.00 4.8828 - - 33.27 KB

Megjegyzés:

Mivel a metódusok példányosítják és felszabadítják a környezetet a metóduson belül, ezeket a műveleteket a rendszer a teljesítményteszthez számítja, habár szigorúan véve nem a lekérdezési folyamat részei. Ez nem számít akkor, ha a cél a két alternatíva összehasonlítása egymással (mivel a környezeti kontextus létrehozása és eltávolítása ugyanaz), és átfogóbb értékelést biztosít a teljes művelet értékelésére.

A BenchmarkDotNet egyik korlátozása, hogy az ön által megadott módszerek egyszerű, egyszálas teljesítményét méri, ezért nem alkalmas egyidejű forgatókönyvek teljesítménymérésére.

Fontos

Mindig győződjön meg arról, hogy az adatbázisban olyan adatok vannak, amelyek hasonlóak az éles adatokhoz a teljesítményértékelés során, ellenkező esetben előfordulhat, hogy a teljesítményteszt eredményei nem a tényleges teljesítményt képviselik az éles környezetben.