Modhanna chun fiosrúcháin LINQ a bharrfheabhsú in C#.NET

Réamhrá

В an t-alt seo breithníodh roinnt modhanna optamaithe Ceisteanna LINQ.
Anseo cuirimid i láthair freisin roinnt cur chuige níos mó maidir le leas iomlán a bhaint cód a bhaineann le Ceisteanna LINQ.

Tá sé ar eolas go LINQIs teanga shimplí agus áisiúil é (Ceist Chomhtháite Teanga) chun foinse sonraí a cheistiú.

А LINQ go SQL teicneolaíocht is ea é chun sonraí a rochtain i DBMS. Is uirlis chumhachtach é seo chun oibriú le sonraí, áit a ndéantar fiosrúcháin a thógáil trí theanga dhearbhaithe, a thiontófar ansin ina Ceisteanna SQL ardán agus a sheoladh chuig an bhfreastalaí bunachar sonraí lena fhorghníomhú. Inár gcás, is éard atá i gceist againn le DBMS Freastalaí MS SQL.

Mar sin féin, Ceisteanna LINQ nach ndéantar iad a thiontú go cinn scríofa barrmhaith Ceisteanna SQL, a d'fhéadfadh DBA taithí a scríobh leis na nuances de bharrfheabhsú Ceisteanna SQL:

  1. naisc optamach (Join) agus na torthaí a scagadh (ÁIT)
  2. go leor nuances in úsáid naisc agus coinníollacha grúpa
  3. go leor éagsúlachtaí i gcoinníollacha athsholáthair IN ar ANNи NÍ IN, <> ar ANN
  4. taisceadh idirmheánach torthaí trí tháblaí sealadacha, CTE, athróga tábla
  5. úsáid na habairte (ROGHA) le treoracha agus leideanna tábla LE (...)
  6. amhairc innéacsaithe a úsáid mar cheann de na bealaí chun fáil réidh le léamha sonraí iomarcacha le linn roghnúcháin

Na scrogaill feidhmíochta is mó de na torthaí Ceisteanna SQL agus iad ag tiomsú Ceisteanna LINQ Is iad sin:

  1. an sásra roghnúcháin sonraí iomlán a chomhdhlúthú in aon iarraidh amháin
  2. dúbláil bloic chomhionanna de chód, as a dtagann i ndeireadh na dála illéamh sonraí neamhriachtanach
  3. grúpaí de choinníollacha ilchomhpháirteacha (loighciúil “agus” agus “nó”) - AGUS и OR, agus iad á gcomhcheangal i gcoinníollacha casta, go dtosaíonn an t-uasmhéadaitheoir, agus innéacsanna neamhchnuasaithe oiriúnacha aige do na réimsí riachtanacha, ar deireadh ag scanadh i gcoinne an innéacs cnuasaithe (scan INDEX) ag grúpaí coinníollacha
  4. Cruthaíonn neadú domhain subqueries an-fhadhbanna don pharsáil Ráitis SQL agus anailís ar an bplean ceiste ó fhorbróirí agus DBA

Modhanna leas iomlán a bhaint

Anois, a ligean ar bogadh go díreach chuig modhanna leas iomlán a bhaint.

1) Innéacsú breise

Is fearr scagairí a mheas ar na príomhtháblaí roghnúcháin, mar is minic a dhéantar an cheist iomlán a thógáil timpeall ar cheann amháin nó dhá phríomhtháblaí (iarratais-daoine-oibríochtaí) agus le sraith coinníollacha caighdeánach (Closed, Cealed, Enabled, Stádas). Tá sé tábhachtach innéacsanna cuí a chruthú do na samplaí sainaitheanta.

Tá ciall leis an réiteach seo agus na réimsí seo á roghnú, cuireann sé srian suntasach ar an tacar a chuirtear ar ais chuig an gceist.

Mar shampla, tá 500000 iarratas againn. Mar sin féin, níl ach 2000 feidhmchlár gníomhach. Ansin sábhálfaidh innéacs a roghnaíodh i gceart sinn scan INDEX ar tábla mór agus ligfidh sé duit sonraí a roghnú go tapa trí innéacs neamhchnuasaithe.

Chomh maith leis sin, is féidir an easpa innéacsanna a aithint trí leideanna chun pleananna fiosrúcháin a pharsáil nó trí staitisticí maidir le hamharc córais a bhailiú Freastalaí MS SQL:

  1. sys.dm_db_missing_index_groups
  2. sys.dm_db_missing_index_group_stats
  3. sys.dm_db_missing_index_details

Tá faisnéis faoi innéacsanna in easnamh sna sonraí amhairc go léir, cé is moite d’innéacsanna spáis.

Mar sin féin, is minic a bhíonn innéacsanna agus taisceadh mar mhodhanna chun na hiarmhairtí a bhaineann le droch-scríbhinn a chomhrac Ceisteanna LINQ и Ceisteanna SQL.

Mar a léiríonn cleachtas crua an tsaoil, is minic a bhíonn sé tábhachtach do ghnóthas gnéithe gnó a chur i bhfeidhm faoi spriocdhátaí áirithe. Agus dá bhrí sin, is minic a aistrítear iarratais throm go dtí an cúlra le caching.

Tá call leis seo go páirteach, ós rud é nach mbíonn na sonraí is déanaí de dhíth ar an úsáideoir i gcónaí agus go bhfuil leibhéal inghlactha freagrúlachta ag an gcomhéadan úsáideora.

Ligeann an cur chuige seo riachtanais ghnó a réiteach, ach ar deireadh laghdaítear feidhmíocht an chórais faisnéise trí mhoill a chur ar réitigh ar fhadhbanna.

Is fiú cuimhneamh freisin go bhfuil sa phróiseas cuardach a dhéanamh ar na hinnéacsanna is gá a chur leis, moltaí MS SQL féadfaidh an leas iomlán a bhaint a bheith mícheart, lena n-áirítear faoi na coinníollacha seo a leanas:

  1. má tá innéacsanna ann cheana le sraith réimsí comhchosúla
  2. mura féidir na réimsí sa tábla a innéacsú mar gheall ar shrianta innéacsaithe (cur síos níos mine air anseo).

2) Tréithe a chumasc in aon tréith nua amháin

Uaireanta is féidir réimse nua amháin a thabhairt isteach in ionad roinnt réimsí ó tábla amháin, a fheidhmíonn mar bhunús do ghrúpa coinníollacha.

Tá sé seo fíor go háirithe maidir le réimsí stádais, a bhíonn beagán nó ina slánuimhir de ghnáth.

Sampla:

IsClosed = 0 AGUS Cealaithe = 0 AGUS Cumasaithe = 0 in ionad Stádas = 1.

Seo an áit a dtugtar an tréith Stádais slánuimhir isteach chun a chinntiú go bhfuil na stádais sin daonra sa tábla. Ansin, tá an tréith nua seo innéacsaithe.

Is é seo an réiteach bunúsach ar an bhfadhb feidhmíochta, mar gheall ar Tá rochtain ar shonraí gan ríomhaireachtaí neamhriachtanach.

3) Ábharization an dearcadh

Ar an drochuair i Ceisteanna LINQ Ní féidir táblaí sealadacha, CTEanna, ná athróga tábla a úsáid go díreach.

Mar sin féin, tá bealach eile ann le leas iomlán a bhaint as an gcás seo - tuairimí innéacsaithe.

Grúpa riochtaí (ón sampla thuas) IsClosed = 0 AGUS Cealaithe = 0 AGUS Cumasaithe = 0 (nó sraith de choinníollacha comhchosúla eile) ina rogha mhaith iad a úsáid i radharc innéacsaithe, ag taisceadh slice beag sonraí ó thacar mór.

Ach tá roinnt srianta ann agus radharc á léiriú:

  1. úsáid subqueries, clásail ANN ba chóir a chur in ionad ag baint úsáide as Join
  2. ní féidir leat abairtí a úsáid AONTAIS, AONAD GACH, EISCEACHT, IDIRNÁISIÚNTA
  3. Ní féidir leat leideanna tábla agus clásail a úsáid ROGHA
  4. aon deis a bheith ag obair le timthriallta
  5. Ní féidir sonraí a thaispeáint i radharc amháin ó tháblaí éagsúla

Tá sé tábhachtach a mheabhrú nach féidir an fíorbhuntáiste a bhaineann le hamharc innéacsaithe a úsáid a bhaint amach ach é a innéacsú.

Ach nuair a ghlaonn tú radharc, ní féidir na hinnéacsanna seo a úsáid, agus chun iad a úsáid go sainráite, ní mór duit a shonrú LE (NOEXPAND).

Ó i Ceisteanna LINQ Níl sé dodhéanta leideanna tábla a shainiú, mar sin caithfidh tú léiriú eile a chruthú - “fillteán” den fhoirm seo a leanas:

CREATE VIEW ИМЯ_представления AS SELECT * FROM MAT_VIEW WITH (NOEXPAND);

4) Ag baint úsáide as feidhmeanna tábla

Go minic i Ceisteanna LINQ Is éard atá i mbloic mhóra focheisteanna nó bloic a úsáideann radhairc a bhfuil struchtúr casta acu ná fiosrúchán deiridh le struchtúr forghníomhaithe an-chasta agus fo-optamach.

Buntáistí Buntábhachtacha a bhaineann le Feidhmeanna Tábla a Úsáid i Ceisteanna LINQ:

  1. An cumas, mar atá i gcás radharcanna, a úsáid agus a shonrú mar rud, ach is féidir leat sraith paraiméadair ionchuir a rith:
    Ó FEIDHME (@param1, @param2 ...)
    Mar thoradh air sin, is féidir sampláil sonraí solúbtha a bhaint amach
  2. I gcás feidhm tábla a úsáid, níl aon srianta láidre mar atá i gcás na radharcanna innéacsaithe a gcuirtear síos orthu thuas:
    1. Leideanna tábla:
      trí LINQ Ní féidir leat a shonrú cé na hinnéacsanna ba chóir a úsáid agus an leibhéal leithlisithe sonraí a chinneadh nuair a bhíonn tú ag fiosrú.
      Ach tá na cumais seo ag an bhfeidhm.
      Leis an bhfeidhm, is féidir leat plean fiosrúcháin atá cothrom seasmhach a bhaint amach, ina sainmhínítear rialacha maidir le bheith ag obair le hinnéacsanna agus leibhéil leithlisithe sonraí
    2. Trí úsáid a bhaint as an bhfeidhm is féidir, i gcomparáid le radhairc innéacsaithe, na nithe seo a leanas a fháil:
      • loighic samplála sonraí casta (fiú ag baint úsáide as lúba)
      • ag fáil sonraí ó go leor táblaí éagsúla
      • an úsáid a bhaint as AONTAIS и ANN

  3. Tairiscint ROGHA an-úsáideach nuair is gá dúinn rialú concurrency a sholáthar ROGHA(MAXDOP N), ord an phlean forghníomhaithe cheist. Mar shampla:
    • is féidir leat athchruthú éigeantach ar an bplean fiosrúcháin a shonrú ROGHA (RECOMPILE)
    • is féidir leat a shonrú cé acu an gcuirfidh tú iallach ar an bplean fiosrúcháin an t-ord ceangail atá sonraithe sa cheist a úsáid ROGHA (ORDÚ FÓRSA)

    Tuilleadh sonraí faoi ROGHA cur síos anseo.

  4. Ag baint úsáide as an slice sonraí is cúinge agus is mó a theastaíonn:
    Ní gá tacair mhóra sonraí a stóráil i caches (mar atá i gcás radhairc innéacsaithe), óna gcaithfidh tú fós na sonraí a scagadh de réir paraiméadar.
    Mar shampla, tá tábla a bhfuil a scagaire ÁIT úsáidtear trí réimse (a, b, c).

    Go traidisiúnta, tá riocht leanúnach ag gach iarratas a = 0 agus b = 0.

    Mar sin féin, an t-iarratas ar an réimse c níos athróg.

    Lig an riocht a = 0 agus b = 0 Cabhraíonn sé go mór linn an tacar toradh atá ag teastáil a theorannú go dtí na mílte taifead, ach an coinníoll ar с caolaíonn sé an rogha síos go dtí céad taifead.

    Anseo b'fhéidir gur rogha níos fearr an fheidhm tábla.

    Chomh maith leis sin, tá feidhm tábla níos intuartha agus comhsheasmhach in am forghníomhaithe.

Примеры

Breathnaímid ar shampla a chur i bhfeidhm ag baint úsáide as an mbunachar sonraí Ceisteanna mar shampla.

Tá iarratas ann ROGHNAIGH, a chomhcheanglaíonn roinnt táblaí agus a úsáideann radharc amháin (OperativeQuestions), ina ndéantar cleamhnacht a sheiceáil trí ríomhphost (trí ANN) chuig “Ceisteanna Gníomhacha” ([Ceisteanna Oibriúcháin]):

Iarratas Uimh. 1

(@p__linq__0 nvarchar(4000))SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Join2].[Object_Id] AS [Object_Id],
[Join2].[ObjectType_Id] AS [ObjectType_Id],
[Join2].[Name] AS [Name],
[Join2].[ExternalId] AS [ExternalId]
FROM [dbo].[Questions] AS [Extent1]
INNER JOIN (SELECT [Extent2].[Object_Id] AS [Object_Id],
[Extent2].[Question_Id] AS [Question_Id], [Extent3].[ExternalId] AS [ExternalId],
[Extent3].[ObjectType_Id] AS [ObjectType_Id], [Extent4].[Name] AS [Name]
FROM [dbo].[ObjectQuestions] AS [Extent2]
INNER JOIN [dbo].[Objects] AS [Extent3] ON [Extent2].[Object_Id] = [Extent3].[Id]
LEFT OUTER JOIN [dbo].[ObjectTypes] AS [Extent4] 
ON [Extent3].[ObjectType_Id] = [Extent4].[Id] ) AS [Join2] 
ON [Extent1].[Id] = [Join2].[Question_Id]
WHERE ([Extent1].[AnswerId] IS NULL) AND (0 = [Extent1].[Exp]) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[OperativeQuestions] AS [Extent5]
WHERE (([Extent5].[Email] = @p__linq__0) OR (([Extent5].[Email] IS NULL) 
AND (@p__linq__0 IS NULL))) AND ([Extent5].[Id] = [Extent1].[Id])
));

Tá struchtúr sách casta ag an radharc: tá nascanna subquery aige agus úsáideann sé sórtáil DÍOSPÓID, atá go ginearálta ina oibríocht sách dian ar acmhainní.

Tá tuairim is deich míle taifead i sampla ó OperativeQuestions.

Is í an phríomhfhadhb a bhaineann leis an gceist seo ná go gcuirtear focheist inmheánach i bhfeidhm ar an amharc [OperativeQuestions] i gcás na dtaifead ón gceist sheachtrach, agus ba cheart go gceadódh sé sin do [Ríomhphost] = @p__linq__0 rogha an aschuir a theorannú (via ANN) suas go dtí na céadta taifead.

Agus b'fhéidir go bhfuil an chuma air gur cheart don fhocheist na taifid a ríomh uair amháin le [R-phost] = @p__linq__0, agus ansin ba cheart na cúpla céad taifead seo a nascadh le Id le Ceisteanna, agus beidh an cheist go tapa.

Déanta na fírinne, tá nasc seicheamhach idir na táblaí go léir: seiceáil an comhfhreagras idir Ceisteanna Id le haitheantas ó OperativeQuestions, agus scagadh le Ríomhphost.

Go deimhin, oibríonn an t-iarratas leis na mílte taifead de Cheisteanna Oibriúcháin, ach ní gá ach na sonraí spéise trí R-phost.

Féach ar an téacs Ceisteanna Oibriúcháin:

Iarratas Uimh. 2

 
CREATE VIEW [dbo].[OperativeQuestions]
AS
SELECT DISTINCT Q.Id, USR.email AS Email
FROM            [dbo].Questions AS Q INNER JOIN
                         [dbo].ProcessUserAccesses AS BPU ON BPU.ProcessId = CQ.Process_Id 
OUTER APPLY
                     (SELECT   1 AS HasNoObjects
                      WHERE   NOT EXISTS
                                    (SELECT   1
                                     FROM     [dbo].ObjectUserAccesses AS BOU
                                     WHERE   BOU.ProcessUserAccessId = BPU.[Id] AND BOU.[To] IS NULL)
) AS BO INNER JOIN
                         [dbo].Users AS USR ON USR.Id = BPU.UserId
WHERE        CQ.[Exp] = 0 AND CQ.AnswerId IS NULL AND BPU.[To] IS NULL 
AND (BO.HasNoObjects = 1 OR
              EXISTS (SELECT   1
                           FROM   [dbo].ObjectUserAccesses AS BOU INNER JOIN
                                      [dbo].ObjectQuestions AS QBO 
                                                  ON QBO.[Object_Id] =BOU.ObjectId
                               WHERE  BOU.ProcessUserAccessId = BPU.Id 
                               AND BOU.[To] IS NULL AND QBO.Question_Id = CQ.Id));

Mapáil tosaigh radhairc in DbContext (EF Core 2)

public class QuestionsDbContext : DbContext
{
    //...
    public DbQuery<OperativeQuestion> OperativeQuestions { get; set; }
    //...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Query<OperativeQuestion>().ToView("OperativeQuestions");
    }
}

Ceist tosaigh LINQ

var businessObjectsData = await context
    .OperativeQuestions
    .Where(x => x.Email == Email)
    .Include(x => x.Question)
    .Select(x => x.Question)
    .SelectMany(x => x.ObjectQuestions,
                (x, bo) => new
                {
                    Id = x.Id,
                    ObjectId = bo.Object.Id,
                    ObjectTypeId = bo.Object.ObjectType.Id,
                    ObjectTypeName = bo.Object.ObjectType.Name,
                    ObjectExternalId = bo.Object.ExternalId
                })
    .ToListAsync();

Sa chás áirithe seo, táimid ag smaoineamh ar réiteach ar an bhfadhb seo gan athruithe bonneagair, gan tábla ar leith a thabhairt isteach le torthaí réamhdhéanta (“Ceisteanna Gníomhacha”), a d’éileodh meicníocht chun é a líonadh le sonraí agus a choimeád cothrom le dáta. .

Cé gur réiteach maith é seo, tá rogha eile ann chun an fhadhb seo a bharrfheabhsú.

Is é an príomhchuspóir ná iontrálacha a thaisceadh le [Ríomhphost] = @p__linq__0 ón amharc OperativeQuestions.

Cuir an fheidhm tábla [dbo].[OperativeQuestionsUserMail] isteach sa bhunachar sonraí.

Trí Ríomhphost a sheoladh mar pharaiméadar ionchuir, faighimid tábla luachanna ar ais:

Iarratas Uimh. 3


CREATE FUNCTION [dbo].[OperativeQuestionsUserMail]
(
    @Email  nvarchar(4000)
)
RETURNS
@tbl TABLE
(
    [Id]           uniqueidentifier,
    [Email]      nvarchar(4000)
)
AS
BEGIN
        INSERT INTO @tbl ([Id], [Email])
        SELECT Id, @Email
        FROM [OperativeQuestions]  AS [x] WHERE [x].[Email] = @Email;
     
    RETURN;
END

Filleann sé seo tábla luachanna le struchtúr sonraí réamhshainithe.

Ionas gur féidir fiosrúcháin chuig OperativeQuestionsUserMail a bheith optamach agus pleananna fiosrúcháin barrmhaithe a bheith acu, tá struchtúr docht ag teastáil, agus ní AN TÁBLA AR AIS MAR THAIRISCEADH...

Sa chás seo, déantar Iarratas 1 a thiontú ina Cheist 4:

Iarratas Uimh. 4

(@p__linq__0 nvarchar(4000))SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Join2].[Object_Id] AS [Object_Id],
[Join2].[ObjectType_Id] AS [ObjectType_Id],
[Join2].[Name] AS [Name],
[Join2].[ExternalId] AS [ExternalId]
FROM (
    SELECT Id, Email FROM [dbo].[OperativeQuestionsUserMail] (@p__linq__0)
) AS [Extent0]
INNER JOIN [dbo].[Questions] AS [Extent1] ON([Extent0].Id=[Extent1].Id)
INNER JOIN (SELECT [Extent2].[Object_Id] AS [Object_Id], [Extent2].[Question_Id] AS [Question_Id], [Extent3].[ExternalId] AS [ExternalId], [Extent3].[ObjectType_Id] AS [ObjectType_Id], [Extent4].[Name] AS [Name]
FROM [dbo].[ObjectQuestions] AS [Extent2]
INNER JOIN [dbo].[Objects] AS [Extent3] ON [Extent2].[Object_Id] = [Extent3].[Id]
LEFT OUTER JOIN [dbo].[ObjectTypes] AS [Extent4] 
ON [Extent3].[ObjectType_Id] = [Extent4].[Id] ) AS [Join2] 
ON [Extent1].[Id] = [Join2].[Question_Id]
WHERE ([Extent1].[AnswerId] IS NULL) AND (0 = [Extent1].[Exp]);

Amharcanna agus feidhmeanna a mhapáil in DbContext (EF Core 2)

public class QuestionsDbContext : DbContext
{
    //...
    public DbQuery<OperativeQuestion> OperativeQuestions { get; set; }
    //...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Query<OperativeQuestion>().ToView("OperativeQuestions");
    }
}
 
public static class FromSqlQueries
{
    public static IQueryable<OperativeQuestion> GetByUserEmail(this DbQuery<OperativeQuestion> source, string Email)
        => source.FromSql($"SELECT Id, Email FROM [dbo].[OperativeQuestionsUserMail] ({Email})");
}

Ceist dheireanach LINQ

var businessObjectsData = await context
    .OperativeQuestions
    .GetByUserEmail(Email)
    .Include(x => x.Question)
    .Select(x => x.Question)
    .SelectMany(x => x.ObjectQuestions,
                (x, bo) => new
                {
                    Id = x.Id,
                    ObjectId = bo.Object.Id,
                    ObjectTypeId = bo.Object.ObjectType.Id,
                    ObjectTypeName = bo.Object.ObjectType.Name,
                    ObjectExternalId = bo.Object.ExternalId
                })
    .ToListAsync();

Tá ord an ama feidhmithe tite ó 200-800 ms, go 2-20 ms, etc., i.e. deich n-uaire níos tapúla.

Má ghlacaimid níos mó ar an meán é, ansin in ionad 350 ms fuaireamar 8 ms.

Ó na buntáistí soiléire a fhaighimid freisin:

  1. laghdú ginearálta ar ualach léitheoireachta,
  2. laghdú suntasach ar an dóchúlacht go dtarlóidh blocáil
  3. an meán-am blocála a laghdú go luachanna inghlactha

Aschur

Optamú agus mionchoigeartú glaonna bunachar sonraí MS SQL trí LINQ is fadhb í is féidir a réiteach.

Tá aire agus comhsheasmhacht an-tábhachtach san obair seo.

Ag tús an phróisis:

  1. is gá na sonraí lena n-oibríonn an t-iarratas a sheiceáil (luachanna, cineálacha sonraí roghnaithe)
  2. innéacsú cuí a dhéanamh ar na sonraí seo
  3. seiceáil i gceart na coinníollacha ceangail idir táblaí

Nochtann an chéad atriall leas iomlán a bhaint eile:

  1. bhonn an iarratais agus sainmhíníonn sé an príomhscagaire iarratais
  2. bloic ceisteanna comhchosúla a athrá agus anailís a dhéanamh ar thrasnú na gcoinníollacha
  3. in SSMS nó GUI eile le haghaidh SQL Server optimizes féin Ceist SQL (stóráil sonraí idirmheánach a leithdháileadh, an cheist a tháinig dá bharr a thógáil ag baint úsáide as an stóras seo (d’fhéadfadh go mbeadh roinnt díobh ann))
  4. ag an gcéim dheireanach, ag tógáil mar bhonn leis an toradh Ceist SQL, tá an struchtúr á atógáil Ceist LINQ

An toradh Ceist LINQ Ba chóir go n-éireodh sé mar an gcéanna ó thaobh struchtúr leis an mbarrfheabhsú aitheanta Ceist SQL ó phointe 3.

Buíochas

Míle buíochas a chomhghleacaithe postgemws и alex_ozr ón gcuideachta Fortis chun cuidiú leis an ábhar seo a ullmhú.

Foinse: will.com

Add a comment