C#.NETలో LINQ ప్రశ్నలను ఆప్టిమైజ్ చేయడానికి పద్ధతులు

పరిచయం

В ఈ వ్యాసం కొన్ని ఆప్టిమైజేషన్ పద్ధతులు పరిగణించబడ్డాయి LINQ ప్రశ్నలు.
ఇక్కడ మేము కోడ్ ఆప్టిమైజేషన్‌కు సంబంధించిన మరికొన్ని విధానాలను కూడా అందిస్తున్నాము LINQ ప్రశ్నలు.

అది తెలిసింది లింక్(లాంగ్వేజ్-ఇంటిగ్రేటెడ్ క్వెరీ) అనేది డేటా సోర్స్‌ను ప్రశ్నించడానికి సులభమైన మరియు అనుకూలమైన భాష.

А SQLకి లింక్ DBMSలో డేటాను యాక్సెస్ చేసే సాంకేతికత. డేటాతో పని చేయడానికి ఇది శక్తివంతమైన సాధనం, ఇక్కడ ప్రశ్నలు డిక్లరేటివ్ భాష ద్వారా రూపొందించబడతాయి, అది తర్వాత మార్చబడుతుంది SQL ప్రశ్నలు ప్లాట్‌ఫారమ్ మరియు అమలు కోసం డేటాబేస్ సర్వర్‌కు పంపబడింది. మా విషయంలో, DBMS ద్వారా మేము అర్థం MS SQL సర్వర్.

అయితే, LINQ ప్రశ్నలు ఉత్తమంగా వ్రాసినవిగా మార్చబడవు SQL ప్రశ్నలు, ఇది ఒక అనుభవజ్ఞుడైన DBA ఆప్టిమైజేషన్ యొక్క అన్ని సూక్ష్మ నైపుణ్యాలతో వ్రాయగలదు SQL ప్రశ్నలు:

  1. సరైన కనెక్షన్లు (JOIN) మరియు ఫలితాలను ఫిల్టర్ చేయడం (ఎక్కడ)
  2. కనెక్షన్లు మరియు సమూహ పరిస్థితులను ఉపయోగించడంలో అనేక సూక్ష్మ నైపుణ్యాలు
  3. పరిస్థితులను భర్తీ చేయడంలో అనేక వైవిధ్యాలు INసమర్థులుи IN కాదు, <> ఆన్ సమర్థులు
  4. తాత్కాలిక పట్టికలు, CTE, టేబుల్ వేరియబుల్స్ ద్వారా ఫలితాల ఇంటర్మీడియట్ కాషింగ్
  5. వాక్య వినియోగం (ఎంపిక) సూచనలు మరియు పట్టిక సూచనలతో విత్ (...)
  6. ఎంపికల సమయంలో అనవసరమైన డేటా రీడింగ్‌లను వదిలించుకోవడానికి ఒక సాధనంగా సూచిక వీక్షణలను ఉపయోగించడం

ఫలితంగా ప్రధాన పనితీరు అడ్డంకులు SQL ప్రశ్నలు కంపైల్ చేస్తున్నప్పుడు LINQ ప్రశ్నలు అవి:

  1. ఒక అభ్యర్థనలో మొత్తం డేటా ఎంపిక విధానం యొక్క ఏకీకరణ
  2. ఒకే విధమైన కోడ్ బ్లాక్‌లను నకిలీ చేయడం, ఇది చివరికి బహుళ అనవసరమైన డేటా రీడ్‌లకు దారి తీస్తుంది
  3. బహుళ-భాగాల పరిస్థితుల సమూహాలు (తార్కిక "మరియు" మరియు "లేదా") - AND и OR, సంక్లిష్ట పరిస్థితులలో కలపడం, ఆప్టిమైజర్, అవసరమైన ఫీల్డ్‌లకు తగిన నాన్-క్లస్టర్డ్ ఇండెక్స్‌లను కలిగి ఉండి, చివరికి క్లస్టర్డ్ ఇండెక్స్‌కి వ్యతిరేకంగా స్కాన్ చేయడం ప్రారంభిస్తుంది (ఇండెక్స్ స్కాన్) పరిస్థితుల సమూహాల ద్వారా
  4. సబ్‌క్వెరీల లోతైన గూడు పార్సింగ్‌ను చాలా సమస్యాత్మకంగా చేస్తుంది SQL ప్రకటనలు మరియు డెవలపర్‌ల నుండి ప్రశ్న ప్రణాళిక యొక్క విశ్లేషణ మరియు DBA

ఆప్టిమైజేషన్ పద్ధతులు

ఇప్పుడు నేరుగా ఆప్టిమైజేషన్ పద్ధతులకు వెళ్దాం.

1) అదనపు ఇండెక్సింగ్

ప్రధాన ఎంపిక పట్టికలలో ఫిల్టర్‌లను పరిగణించడం ఉత్తమం, ఎందుకంటే చాలా తరచుగా మొత్తం ప్రశ్న ఒకటి లేదా రెండు ప్రధాన పట్టికలు (అప్లికేషన్‌లు-పీపుల్-ఆపరేషన్‌లు) మరియు ప్రామాణిక సెట్ షరతులతో (ఇస్‌క్లోజ్డ్, క్యాన్సిల్డ్, ఎనేబుల్డ్, స్టేటస్) నిర్మించబడింది. గుర్తించబడిన నమూనాల కోసం తగిన సూచికలను సృష్టించడం ముఖ్యం.

ఈ ఫీల్డ్‌లను ఎంచుకున్నప్పుడు ఈ పరిష్కారం అర్థవంతంగా ఉంటుంది, ఇది ప్రశ్నకు తిరిగి వచ్చిన సెట్‌ను గణనీయంగా పరిమితం చేస్తుంది.

ఉదాహరణకు, మాకు 500000 అప్లికేషన్లు ఉన్నాయి. అయితే, కేవలం 2000 యాక్టివ్ అప్లికేషన్‌లు మాత్రమే ఉన్నాయి. అప్పుడు సరిగ్గా ఎంచుకున్న ఇండెక్స్ మనల్ని రక్షిస్తుంది ఇండెక్స్ స్కాన్ పెద్ద పట్టికలో మరియు క్లస్టర్ కాని ఇండెక్స్ ద్వారా డేటాను త్వరగా ఎంచుకోవడానికి మిమ్మల్ని అనుమతిస్తుంది.

అలాగే, ప్రశ్న ప్రణాళికలను అన్వయించడం లేదా సిస్టమ్ వీక్షణ గణాంకాలను సేకరించడం కోసం ప్రాంప్ట్‌ల ద్వారా సూచికల కొరతను గుర్తించవచ్చు. MS SQL సర్వర్:

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

స్పేషియల్ ఇండెక్స్‌లు మినహా అన్ని వీక్షణ డేటా మిస్సింగ్ ఇండెక్స్‌ల గురించి సమాచారాన్ని కలిగి ఉంటుంది.

అయితే, సూచికలు మరియు కాషింగ్ తరచుగా పేలవంగా వ్రాసిన పరిణామాలను ఎదుర్కోవడానికి పద్ధతులు LINQ ప్రశ్నలు и SQL ప్రశ్నలు.

జీవితం యొక్క కఠినమైన అభ్యాసం చూపినట్లుగా, వ్యాపార లక్షణాలను నిర్దిష్ట గడువులోగా అమలు చేయడం తరచుగా ముఖ్యం. అందువల్ల, భారీ అభ్యర్థనలు తరచుగా కాషింగ్‌తో నేపథ్యానికి బదిలీ చేయబడతాయి.

వినియోగదారుకు ఎల్లప్పుడూ తాజా డేటా అవసరం లేదు మరియు వినియోగదారు ఇంటర్‌ఫేస్ యొక్క ప్రతిస్పందన యొక్క ఆమోదయోగ్యమైన స్థాయి ఉన్నందున ఇది పాక్షికంగా సమర్థించబడుతుంది.

ఈ విధానం వ్యాపార అవసరాలను పరిష్కరించడానికి అనుమతిస్తుంది, అయితే సమస్యలకు పరిష్కారాలను ఆలస్యం చేయడం ద్వారా అంతిమంగా సమాచార వ్యవస్థ పనితీరును తగ్గిస్తుంది.

జోడించడానికి అవసరమైన సూచికల కోసం శోధించే ప్రక్రియలో, సలహాలను గుర్తుంచుకోవడం కూడా విలువైనదే MS SQL కింది పరిస్థితులతో సహా ఆప్టిమైజేషన్ తప్పు కావచ్చు:

  1. ఒకే విధమైన ఫీల్డ్‌లతో ఇప్పటికే సూచికలు ఉంటే
  2. ఇండెక్సింగ్ పరిమితుల కారణంగా పట్టికలోని ఫీల్డ్‌లను ఇండెక్స్ చేయలేకపోతే (మరింత వివరంగా వివరించబడింది ఇక్కడ).

2) లక్షణాలను ఒక కొత్త లక్షణంలో విలీనం చేయడం

కొన్నిసార్లు షరతుల సమూహానికి ఆధారంగా పనిచేసే ఒక టేబుల్ నుండి కొన్ని ఫీల్డ్‌లను ఒక కొత్త ఫీల్డ్‌ని పరిచయం చేయడం ద్వారా భర్తీ చేయవచ్చు.

బిట్ లేదా పూర్ణాంకం రకంగా ఉండే స్థితి ఫీల్డ్‌లకు ఇది ప్రత్యేకంగా వర్తిస్తుంది.

ఉదాహరణకు:

మూసివేయబడింది = 0 మరియు రద్దు చేయబడింది = 0 మరియు ప్రారంభించబడింది = 0 ద్వారా భర్తీ చేయబడుతుంది స్థితి = 1.

ఇక్కడే పూర్ణాంక స్థితి లక్షణం ఈ స్థితిని పట్టికలో నింపబడిందని నిర్ధారించడానికి పరిచయం చేయబడింది. తర్వాత, ఈ కొత్త లక్షణం ఇండెక్స్ చేయబడింది.

పనితీరు సమస్యకు ఇది ప్రాథమిక పరిష్కారం, ఎందుకంటే మేము అనవసరమైన లెక్కలు లేకుండా డేటాను యాక్సెస్ చేస్తాము.

3) వీక్షణ యొక్క మెటీరియలైజేషన్

దురదృష్టవశాత్తు లో LINQ ప్రశ్నలు తాత్కాలిక పట్టికలు, CTEలు మరియు టేబుల్ వేరియబుల్స్ నేరుగా ఉపయోగించబడవు.

అయితే, ఈ సందర్భంలో ఆప్టిమైజ్ చేయడానికి మరొక మార్గం ఉంది - ఇండెక్స్డ్ వీక్షణలు.

కండిషన్ గ్రూప్ (పై ఉదాహరణ నుండి) మూసివేయబడింది = 0 మరియు రద్దు చేయబడింది = 0 మరియు ప్రారంభించబడింది = 0 (లేదా ఇతర సారూప్య పరిస్థితుల సమితి) వాటిని ఇండెక్స్ చేసిన వీక్షణలో ఉపయోగించడానికి మంచి ఎంపిక అవుతుంది, పెద్ద సెట్ నుండి డేటా యొక్క చిన్న స్లైస్‌ను క్యాష్ చేస్తుంది.

కానీ వీక్షణను సాకారం చేసేటప్పుడు అనేక పరిమితులు ఉన్నాయి:

  1. సబ్‌క్వెరీలు, క్లాజుల ఉపయోగం సమర్థులు ఉపయోగించడం ద్వారా భర్తీ చేయాలి JOIN
  2. మీరు వాక్యాలను ఉపయోగించలేరు UNION, యూనియన్ అన్నీ, మినహాయింపు, ఇంటర్‌సెక్ట్
  3. మీరు పట్టిక సూచనలు మరియు నిబంధనలను ఉపయోగించలేరు ఎంపిక
  4. చక్రాలతో పని చేసే అవకాశం లేదు
  5. విభిన్న పట్టికల నుండి ఒకే వీక్షణలో డేటాను ప్రదర్శించడం అసాధ్యం

ఇండెక్స్ చేసిన వీక్షణను ఉపయోగించడం వల్ల కలిగే నిజమైన ప్రయోజనం వాస్తవానికి ఇండెక్స్ చేయడం ద్వారా మాత్రమే సాధించబడుతుందని గుర్తుంచుకోవడం ముఖ్యం.

కానీ వీక్షణకు కాల్ చేస్తున్నప్పుడు, ఈ సూచికలు ఉపయోగించబడకపోవచ్చు మరియు వాటిని స్పష్టంగా ఉపయోగించడానికి, మీరు తప్పనిసరిగా పేర్కొనాలి (NOEXPAND) తో.

లో నుండి LINQ ప్రశ్నలు పట్టిక సూచనలను నిర్వచించడం అసాధ్యం, కాబట్టి మీరు మరొక ప్రాతినిధ్యాన్ని సృష్టించాలి - కింది ఫారమ్ యొక్క “రేపర్”:

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

4) టేబుల్ ఫంక్షన్లను ఉపయోగించడం

తరచుగా లో LINQ ప్రశ్నలు సంక్లిష్టమైన నిర్మాణంతో వీక్షణలను ఉపయోగించి సబ్‌క్వెరీలు లేదా బ్లాక్‌ల యొక్క పెద్ద బ్లాక్‌లు చాలా క్లిష్టమైన మరియు సబ్‌ప్టిమల్ ఎగ్జిక్యూషన్ స్ట్రక్చర్‌తో తుది ప్రశ్నను ఏర్పరుస్తాయి.

టేబుల్ ఫంక్షన్లను ఉపయోగించడం వల్ల కలిగే ముఖ్య ప్రయోజనాలు LINQ ప్రశ్నలు:

  1. వీక్షణల విషయంలో వలె, ఒక వస్తువుగా ఉపయోగించబడే మరియు పేర్కొనబడే సామర్థ్యం, ​​కానీ మీరు ఇన్‌పుట్ పారామితుల సమితిని పాస్ చేయవచ్చు:
    ఫంక్షన్ నుండి(@param1, @param2 ...)
    ఫలితంగా, సౌకర్యవంతమైన డేటా నమూనాను సాధించవచ్చు
  2. టేబుల్ ఫంక్షన్‌ని ఉపయోగించే విషయంలో, పైన వివరించిన ఇండెక్స్డ్ వీక్షణల విషయంలో ఎలాంటి బలమైన పరిమితులు లేవు:
    1. పట్టిక సూచనలు:
      ద్వారా లింక్ మీరు ఏ సూచికలను ఉపయోగించాలో పేర్కొనలేరు మరియు ప్రశ్నిస్తున్నప్పుడు డేటా ఐసోలేషన్ స్థాయిని నిర్ణయించలేరు.
      కానీ ఫంక్షన్ ఈ సామర్థ్యాలను కలిగి ఉంది.
      ఫంక్షన్‌తో, మీరు చాలా స్థిరమైన అమలు ప్రశ్న ప్రణాళికను సాధించవచ్చు, ఇక్కడ సూచికలు మరియు డేటా ఐసోలేషన్ స్థాయిలతో పని చేయడానికి నియమాలు నిర్వచించబడతాయి.
    2. ఇండెక్స్ చేయబడిన వీక్షణలతో పోల్చి చూస్తే, ఫంక్షన్‌ని ఉపయోగించడం అనుమతిస్తుంది:
      • సంక్లిష్ట డేటా నమూనా తర్కం (లూప్‌లను ఉపయోగించి కూడా)
      • అనేక విభిన్న పట్టికల నుండి డేటాను పొందడం
      • ఉపయోగం UNION и సమర్థులు

  3. ఆఫర్ ఎంపిక మేము ఏకకాల నియంత్రణను అందించాల్సిన అవసరం వచ్చినప్పుడు చాలా ఉపయోగకరంగా ఉంటుంది ఎంపిక(MAXDOP N), ప్రశ్న అమలు ప్రణాళిక యొక్క క్రమం. ఉదాహరణకి:
    • మీరు ప్రశ్న ప్రణాళిక యొక్క బలవంతంగా పునఃసృష్టిని పేర్కొనవచ్చు ఎంపిక (రీకంపైల్)
    • ప్రశ్నలో పేర్కొన్న జాయిన్ ఆర్డర్‌ను ఉపయోగించమని ప్రశ్న ప్లాన్‌ను బలవంతం చేయాలా వద్దా అని మీరు పేర్కొనవచ్చు ఎంపిక (ఫోర్స్ ఆర్డర్)

    గురించి మరిన్ని వివరాలు ఎంపిక వివరించబడింది ఇక్కడ.

  4. ఇరుకైన మరియు అత్యంత అవసరమైన డేటా స్లైస్‌ని ఉపయోగించడం:
    కాష్‌లలో పెద్ద డేటా సెట్‌లను నిల్వ చేయవలసిన అవసరం లేదు (ఇండెక్స్ చేసిన వీక్షణల మాదిరిగానే), మీరు ఇప్పటికీ పారామీటర్ ద్వారా డేటాను ఫిల్టర్ చేయాలి.
    ఉదాహరణకు, ఫిల్టర్ ఉన్న పట్టిక ఉంది ఎక్కడ మూడు ఫీల్డ్‌లు ఉపయోగించబడతాయి (ఎ, బి, సి).

    సాంప్రదాయకంగా, అన్ని అభ్యర్థనలు స్థిరమైన స్థితిని కలిగి ఉంటాయి a = 0 మరియు b = 0.

    అయితే, ఫీల్డ్ కోసం అభ్యర్థన c మరింత వేరియబుల్.

    షరతునివ్వండి a = 0 మరియు b = 0 అవసరమైన ఫలిత సెట్‌ను వేలాది రికార్డులకు పరిమితం చేయడంలో ఇది నిజంగా మాకు సహాయపడుతుంది, కానీ షరతు ఆన్‌లో ఉంది с ఎంపికను వంద రికార్డులకు తగ్గించింది.

    ఇక్కడ టేబుల్ ఫంక్షన్ మంచి ఎంపిక కావచ్చు.

    అలాగే, టేబుల్ ఫంక్షన్ అమలు సమయంలో మరింత ఊహించదగినది మరియు స్థిరంగా ఉంటుంది.

ఉదాహరణలు

ప్రశ్నల డేటాబేస్‌ను ఉదాహరణగా ఉపయోగించి ఉదాహరణ అమలును చూద్దాం.

ఒక అభ్యర్థన ఉంది ఎంచుకోండి, ఇది అనేక పట్టికలను మిళితం చేస్తుంది మరియు ఒక వీక్షణను ఉపయోగిస్తుంది (ఆపరేటివ్ ప్రశ్నలు), దీనిలో అనుబంధం ఇమెయిల్ ద్వారా తనిఖీ చేయబడుతుంది (ద్వారా సమర్థులు) నుండి “యాక్టివ్ ప్రశ్నలు” ([ఆపరేటివ్ ప్రశ్నలు]):

అభ్యర్థన సంఖ్య 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])
));

వీక్షణ చాలా క్లిష్టమైన నిర్మాణాన్ని కలిగి ఉంది: ఇది సబ్‌క్వెరీ చేరికలను కలిగి ఉంది మరియు సార్టింగ్‌ని ఉపయోగిస్తుంది విభిన్న, ఇది సాధారణంగా చాలా వనరు-ఇంటెన్సివ్ ఆపరేషన్.

ఆపరేటివ్ ప్రశ్నల నుండి ఒక నమూనా సుమారు పది వేల రికార్డులు.

ఈ ప్రశ్నతో ఉన్న ప్రధాన సమస్య ఏమిటంటే, బయటి ప్రశ్న నుండి రికార్డ్‌ల కోసం, [ఆపరేటివ్ ప్రశ్నలు] వీక్షణలో అంతర్గత సబ్‌క్వెరీ అమలు చేయబడుతుంది, ఇది [ఇమెయిల్] = @p__linq__0 అవుట్‌పుట్ ఎంపికను పరిమితం చేయడానికి అనుమతిస్తుంది (ద్వారా సమర్థులు) వందల కొద్దీ రికార్డులు.

మరియు సబ్‌క్వెరీ రికార్డ్‌లను ఒకసారి [ఇమెయిల్] = @p__linq__0 ద్వారా లెక్కించాలని అనిపించవచ్చు, ఆపై ఈ రెండు వందల రికార్డులను ప్రశ్నలతో Id ద్వారా కనెక్ట్ చేయాలి మరియు ప్రశ్న వేగంగా ఉంటుంది.

వాస్తవానికి, అన్ని పట్టికలకు వరుస కనెక్షన్ ఉంది: ఆపరేటివ్ ప్రశ్నల నుండి Idతో Id ప్రశ్నల అనురూపాన్ని తనిఖీ చేయడం మరియు ఇమెయిల్ ద్వారా ఫిల్టర్ చేయడం.

వాస్తవానికి, అభ్యర్థన అన్ని పదివేల ఆపరేటివ్ ప్రశ్నల రికార్డులతో పని చేస్తుంది, అయితే ఇమెయిల్ ద్వారా ఆసక్తి ఉన్న డేటా మాత్రమే అవసరం.

ఆపరేటివ్ ప్రశ్నలు వచనాన్ని వీక్షించండి:

అభ్యర్థన సంఖ్య 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));

DbContext (EF కోర్ 2)లో ప్రారంభ వీక్షణ మ్యాపింగ్

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

ప్రారంభ 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();

ఈ ప్రత్యేక సందర్భంలో, మేము ఈ సమస్యకు మౌలిక మార్పులు లేకుండా పరిష్కారాన్ని పరిశీలిస్తున్నాము, రెడీమేడ్ ఫలితాలతో (“యాక్టివ్ క్వెరీస్”) ప్రత్యేక పట్టికను పరిచయం చేయకుండా, డేటాతో నింపడానికి మరియు దానిని తాజాగా ఉంచడానికి ఒక మెకానిజం అవసరం. .

ఇది మంచి పరిష్కారం అయినప్పటికీ, ఈ సమస్యను ఆప్టిమైజ్ చేయడానికి మరొక ఎంపిక ఉంది.

ఆపరేటివ్ ప్రశ్నల వీక్షణ నుండి [ఇమెయిల్] = @p__linq__0 ద్వారా ఎంట్రీలను కాష్ చేయడం ప్రధాన ఉద్దేశ్యం.

డేటాబేస్‌లో టేబుల్ ఫంక్షన్ [dbo].[OperativeQuestionsUserMail]ని పరిచయం చేయండి.

ఇమెయిల్‌ను ఇన్‌పుట్ పారామీటర్‌గా పంపడం ద్వారా, మేము విలువల పట్టికను తిరిగి పొందుతాము:

అభ్యర్థన సంఖ్య 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

ఇది ముందే నిర్వచించిన డేటా నిర్మాణంతో విలువల పట్టికను అందిస్తుంది.

OperativeQuestionsUserMailకు సంబంధించిన ప్రశ్నలు సరైనవి కావడానికి మరియు సరైన ప్రశ్న ప్రణాళికలను కలిగి ఉండటానికి, కఠినమైన నిర్మాణం అవసరం మరియు కాదు రిటర్న్స్ టేబుల్ రిటర్న్...

ఈ సందర్భంలో, అవసరమైన ప్రశ్న 1 ప్రశ్న 4గా మార్చబడుతుంది:

అభ్యర్థన సంఖ్య 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]);

DbContext (EF కోర్ 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})");
}

చివరి 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();

అమలు సమయం యొక్క క్రమం 200-800 ms నుండి 2-20 ms, మొదలైన వాటికి పడిపోయింది, అనగా పదుల రెట్లు వేగంగా.

మేము దానిని మరింత సగటుగా తీసుకుంటే, 350 msకి బదులుగా మనకు 8 ms వచ్చింది.

స్పష్టమైన ప్రయోజనాల నుండి మేము కూడా పొందుతాము:

  1. రీడింగ్ లోడ్‌లో సాధారణ తగ్గింపు,
  2. నిరోధించే సంభావ్యతలో గణనీయమైన తగ్గింపు
  3. సగటు బ్లాకింగ్ సమయాన్ని ఆమోదయోగ్యమైన విలువలకు తగ్గించడం

తీర్మానం

డేటాబేస్ కాల్‌ల ఆప్టిమైజేషన్ మరియు ఫైన్-ట్యూనింగ్ MS SQL ద్వారా లింక్ అనేది పరిష్కరించదగిన సమస్య.

ఈ పనిలో శ్రద్ధ మరియు స్థిరత్వం చాలా ముఖ్యమైనవి.

ప్రక్రియ ప్రారంభంలో:

  1. అభ్యర్థన పని చేసే డేటాను తనిఖీ చేయడం అవసరం (విలువలు, ఎంచుకున్న డేటా రకాలు)
  2. ఈ డేటా యొక్క సరైన సూచికను నిర్వహించండి
  3. పట్టికల మధ్య చేరే పరిస్థితుల యొక్క ఖచ్చితత్వాన్ని తనిఖీ చేయండి

తదుపరి ఆప్టిమైజేషన్ పునరావృతం వెల్లడిస్తుంది:

  1. అభ్యర్థన ఆధారంగా మరియు ప్రధాన అభ్యర్థన ఫిల్టర్‌ను నిర్వచిస్తుంది
  2. సారూప్య ప్రశ్న బ్లాక్‌లను పునరావృతం చేయడం మరియు పరిస్థితుల ఖండనను విశ్లేషించడం
  3. SSMS లేదా ఇతర GUIలో SQL సర్వర్ స్వయంగా ఆప్టిమైజ్ చేస్తుంది SQL ప్రశ్న (ఇంటర్మీడియట్ డేటా నిల్వను కేటాయించడం, ఈ నిల్వను ఉపయోగించి ఫలిత ప్రశ్నను రూపొందించడం (అనేక ఉండవచ్చు))
  4. చివరి దశలో, ఫలితాన్ని ప్రాతిపదికగా తీసుకుంటుంది SQL ప్రశ్న, నిర్మాణం పునర్నిర్మించబడుతోంది LINQ ప్రశ్న

ఫలితంగా LINQ ప్రశ్న గుర్తించబడిన ఆప్టిమల్‌కు నిర్మాణంలో ఒకేలా ఉండాలి SQL ప్రశ్న పాయింట్ 3 నుండి.

రసీదులు

సహోద్యోగులకు చాలా ధన్యవాదాలు jobgemws и alex_ozr కంపెనీ నుండి ఫోర్టిస్ ఈ పదార్థాన్ని సిద్ధం చేయడంలో సహాయం కోసం.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి