Otsingutulemuste vÀljund ja jÔudlusprobleemid

Üks tĂŒĂŒpiline stsenaarium, millega me oma rakendustes kokku puutume, on andmete otsimine teatud kriteeriumide alusel ja nende kuvamine lugemiseks mugaval viisil. Samuti vĂ”ivad olla lisavĂ”imalused, nagu sortimine, rĂŒhmitamine ja lehekĂŒljed. Ülesanne nĂ€ib esmapilgul triviaalne, kuid selle lahendamisel teevad paljud arendajad mitmeid vigu, mis mĂ”jutavad hiljem jĂ”udlust. Proovime vaadata erinevaid lahenduste variante ja formuleerida soovitusi, kuidas valida tĂ”husaim rakenduse tĂ€ideviimine.

Otsingutulemuste vÀljund ja jÔudlusprobleemid

LehekĂŒljendamise variant #1

Lihtsaim variant, mis pĂ€he tuleb, on postitada otsingu tulemused klassikalisel viisil lehekĂŒljendatult.

Otsingutulemuste vÀljund ja jÔudlusprobleemid
Oletame, et rakenduses kasutatakse relationaalset andmebaasi. Sel juhul peab sellise vormingu jaoks toimuma kaks SQL pÀringut:

  • Saama read praegusele lehekĂŒljele.
  • Arvutama vĂ€lja koguarvu read, mis vastavad otsingukriteeriumidele — see on vajalik lehtede nĂ€itamiseks.

Vaadakem esimest pÀringut testimise MS SQL andmebaasi pÔhjal AdventureWorks 2016 serveri jaoks. Selleks kasutame tabelit Sales.SalesOrderHeader:

SELECT * FROM Sales.SalesOrderHeader
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY

Ülaltoodud pĂ€ring kuvab esimesed 50 tellimust loendist, mis on sorteeritud lisamise kuupĂ€eva jĂ€rgi, teisisĂ”nu — 50 viimast tellimust.

KÀib see testimise andmebaasis kiiresti, kuid vaatame, mis juhtub plaaniga ja sisend-vÀljund statistikaga:

Otsingutulemuste vÀljund ja jÔudlusprobleemid

Tabel 'SalesOrderHeader'. Skaneeringute arv 1, loogilised lugemised 698, fĂŒĂŒsilised lugemised 0, eelnevad lugemised 0, lob loogilised lugemised 0, lob fĂŒĂŒsilised lugemised 0, lob eelnevad lugemised 0.

Iga pÀringu sisend-vÀljund statistika saamiseks saab kÀivitada pÀringute keskkonnas kÀsu SET STATISTICS IO ON.

Nagu tÀitmisplaanist nÀha, on kÔige ressursimahukam kogu algsete tabeli ridade sortimine lisamise kuupÀeva jÀrgi. Probleem on siiski selles, et mida rohkem ridu tabelisse lisandub, seda 'raskem' on sortimine. Praktiliselt tuleks selliseid olukordi vÀltida, seetÔttu lisame sortimisekuva kuupÀevale indeksi ja vaatame, kas ressursikasutus on muutunud:

Otsingutulemuste vÀljund ja jÔudlusprobleemid

Tabel 'SalesOrderHeader'. Skaneeringute arv 1, loogilised lugemised 165, fĂŒĂŒsilised lugemised 0, eelnevad lugemised 5, lob loogilised lugemised 0, lob fĂŒĂŒsilised lugemised 0, lob eelnevad lugemised 0.

Ilmselt on asjad palju paremaks muutunud. Kuid kas kĂ”ik probleemid on lahendatud? Muudame pĂ€ringu tellimuste leidmiseks, kus kaupade koguhind ĂŒletab 100 dollarit:

SELECT * FROM Sales.SalesOrderHeader
WHERE SubTotal > 100
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY

Otsingutulemuste vÀljund ja jÔudlusprobleemid

Tabel 'SalesOrderHeader'. Skaneerimise arv 1, loogilised lugemised 1081, fĂŒĂŒsilised lugemised 0, lugemise eelvaated 0, lob loogilised lugemised 0, lob fĂŒĂŒsilised lugemised 0, lob lugemise eelvaated 0.

KĂ€es on naljakas olukord: pĂ€ringu plaan ei ole palju halvem eelmisest, kuid tegelik loogiliste lugemiste arv on peaaegu kaks korda suurem kui kogu tabeli skaneerimise korral. Lahendus on olemas — kui olemasolevast indeksist teha kombineeritud ja teiseks vĂ€ljaks lisada kaupade koguhind, saame jĂ€lle 165 loogilist lugemist:

CREATE INDEX IX_SalesOrderHeader_OrderDate_SubTotal ON Sales.SalesOrderHeader(OrderDate, SubTotal);

Seda nÀidete seeriat saab jÀtkata veel kaua, kuid kaks peamist mÔtet, mida siin soovin vÀljendada, on jÀrgmised:

  • Iga uue kriteeri vĂ”i sortimisjĂ€rjestuse lisamine pĂ€ringusse vĂ”ib oluliselt mĂ”jutada selle tĂ€itmise kiirus.
  • Kuid kui me peame vĂ€lja vĂ”tma ainult osa andmetest, mitte kĂ”iki otsingutingimustele vastavaid tulemusi — on palju viise, kuidas sellist pĂ€ringut optimeerida.

NĂŒĂŒd liigume teise pĂ€ringu juurde, mida mainiti alguses — selle juurde, mis loendab rekordite arvu, mis vastavad otsingutingimustele. VĂ”tame sama nĂ€ite — otsing tellimuste leidmiseks, mis maksavad rohkem kui 100 dollarit:

SELECT COUNT(1) FROM Sales.SalesOrderHeader
WHERE SubTotal > 100

Kui vastata sellele koostatud indeksiga, saame:

Otsingutulemuste vÀljund ja jÔudlusprobleemid

Tabel 'SalesOrderHeader'. Skaneeringute arv 1, loogilised lugemised 698, fĂŒĂŒsilised lugemised 0, eelnevad lugemised 0, lob loogilised lugemised 0, lob fĂŒĂŒsilised lugemised 0, lob eelnevad lugemised 0.

Et pĂ€ring lĂ€bib kogu indeksi, ei ole ĂŒllatav, kuna vĂ€li SubTotal ei ole esimeses positsioonis, seega ei saa pĂ€ring seda Ă€ra kasutada. Probleem lahendatakse lisades veel ĂŒhe indeksi vĂ€ljale SubTotal, mis annab kokku juba vaid 48 loogilist lugemist.

VĂ”in tuua veel mĂ”ned nĂ€ited pĂ€ringute jaoks, mis loendavad arvu, kuid pĂ”himĂ”te jÀÀb samaks: andmete kogumise ja koguarvu arvestamine — need on kaks fundamentaalselt erinevat pĂ€ringut, ja igaĂŒks nĂ”uab oma meetmeid optimeerimiseks. Üldiselt ei ole vĂ”imalik leida indeksite kombinatsiooni, mis töötab sama hĂ€sti mĂ”lema pĂ€ringu jaoks.

Seega, ĂŒks olulisemaid nĂ”udeid, mida tuleb sellise otsingulahenduse arendamisel tĂ€psustada, on see, kas ettevĂ”ttele on oluline nĂ€ha leitud objektide koguarvu. Sageli ei ole see nii. Ja navigeerimine konkreetsete lehekĂŒlgede numbrite vahel on minu arvates lahendus, millel on vĂ€ga kitsas rakendamisala, kuna enamiku lehekĂŒlgede vahetamise stsenaariumide puhul on see pigem "mine jĂ€rgmisele lehele".

LehekĂŒlgede vahetamise variant #2

Oletame, et kasutajatele ei ole ĂŒldise leitud objektide arvu teadmine oluline. Proovime lihtsustada otsingulehte:

Otsingutulemuste vÀljund ja jÔudlusprobleemid
Fakt on, et muutunud on ainult see, et ei ole vĂ”imalik liikuda konkreetsete lehekĂŒlgede numbrite vahel ning nĂŒĂŒd ei pea sellele tabelile teadma, kui palju lehekĂŒlgi kokku vĂ”ib olla. Kuid tekib kĂŒsimus — kuidas tabel saab teada, kas jĂ€rgmise lehekĂŒlje andmed on olemas (et Ă”igesti nĂ€idata linki „JĂ€rgmine”)?

Vastus on vĂ€ga lihtne: andmebaasist saab lugeda ĂŒhe kirje rohkem, kui on vaja kuvada, ja see "lisakirje" nĂ€itabki, kas jĂ€rgmine partii on olemas. Seega, et saada ĂŒhte andmelehte, tuleb teha vaid ĂŒks pĂ€ring, mis oluliselt parandab jĂ”udlust ja lihtsustab sellise funktsionaalsuse toetust. Minu praktikas oli juhtum, kus koguarvu arvestamisest loobumine kiirendas tulemuste vĂ€ljundit 4-5 korda.

Selle lĂ€henemise jaoks on olemas mitmeid kasutajaliidese valikuid: kĂ€sklused „tagasi” ja „edasi”, nagu eelnevas nĂ€ites, nupp „lae veel”, mis lihtsalt lisab uue partii kuvatud tulemustele, „lĂ”pmatu kerimine”, mis toimib „lae veel” pĂ”himĂ”tte jĂ€rgi, kuid jĂ€rgmise partii saamise signaaliks on kasutaja kerimine kĂ”ikide kuvatud tulemusteni lĂ”puni. ÜkskĂ”ik, milline on visuaalne lahendus, jÀÀb andmete valimise pĂ”himĂ”te samaks.

LehekĂŒlgede vahetamise rakendamise nĂŒansid

KĂ”igis ĂŒlaltoodud pĂ€ringute nĂ€idetes kasutatakse lĂ€henemist „silmus + arv”, kus pĂ€ringus mĂ€rgitakse Ă€ra, millise jĂ€rjekorra jĂ€rgi tulemus ja kui palju ridu tuleb tagastada. Esiteks vaatame, kuidas on parim korraldada parameetrite edastamine sellisel juhul. Praktikas olen kohanud mitmeid viise:

  • Soovitava lehe jĂ€rjestusnumber (pageIndex), lehe suurus (pageSize).
  • Esimese salvestuse jĂ€rjestusnumber, mille me saame (startIndex), maksimaalne salvestuste arv tulemuses (count).
  • Esimese salvestuse jĂ€rjestusnumber, mille me salvestame (startIndex), viimase salvestuse jĂ€rjestusnumber, mille me salvestame (endIndex).

Esmapilgul vĂ”ib tunduda, et see on nii elementaarne, et mingit vahet pole. Kuid see ei ole nii — kĂ”ige mugavam ja universaalsem variant on teine (startIndex, count). Sellel on mitu pĂ”hjust:

  • Selle lĂ€henemise puhul, kus loetakse +1 salvestust, on esimene variant pageIndex ja pageSize ÀÀrmiselt ebamugav. NĂ€iteks tahame lehe peal kuvada 50 salvestust. Vastavalt eelmisele algoritmile tuleb lugeda ĂŒhe salvestuse vĂ”rra rohkem, kui tegelikult on vajalik. Kui see „+1“ pole serveris ette nĂ€htud, siis selgub, et esimese lehe jaoks peame kĂŒsima salvestusi vahemikus 1 kuni 51, teise jaoks — 51 kuni 101 jne. Kui mÀÀrata lehe suuruseks 51 ja suurendada pageIndex, siis teine leht tagastab salvestused vahemikus 52 kuni 102 jne. Seega on esimese variandi puhul ainus viis korralikult rakendada jĂ€rgmise lehe juurde mineku nuppu — ette nĂ€ha serveris â€žĂŒhe liigse“ rea lugemist, mis on vĂ€ga ebaselge nĂŒanss.
  • Kolmas variant pole ĂŒldse mĂ”istlik, kuna enamikus andmebaasides tuleb pĂ€ringute tegemiseks edastada ikkagi arv, mitte viimase salvestuse indeks. Olgu see startIndex lahutamine endIndex'ist ja elementaarne aritmeetiline tehe, kuid see on siinkohal ĂŒleliigne.

NĂŒĂŒd tuleks kirjeldada puudusi rakendamisel, mis kasutab „nihet + kogust“:

  • Iga jĂ€rgmise lehe saamine osutub kallimaks ja aeglasemaks kui eelmine, kuna andmebaas peab ikkagi lĂ€bi lugema kĂ”ik salvestused „algusest“ vastavalt otsingukriteeriumidele ja sortimisele ning seejĂ€rel peatuma vajalikul fragmendil.
  • Kaugeltki mitte kĂ”ik andmebaaside haldamise sĂŒsteemid (СУБД) ei pruugi seda lĂ€henemist toetada.

Alternatiive on, kuid needki ei ole ideaalsed. Esimene nendest lĂ€henemistest nimetatakse „keyset paging” vĂ”i „seek method” ja see seisneb jĂ€rgmisest: pĂ€rast andmeportsjoni saamist saab salvestada viimasel lehel olevate salvestuste vĂ€ljade vÀÀrtused ja seejĂ€rel kasutada neid jĂ€rgmise portsjoni saamiseks. NĂ€iteks sooritasime sellise pĂ€ringu:

SELECT * FROM Sales.SalesOrderHeader
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY

Ja viimasest kirjest saime tellimuse kuupÀeva vÀÀrtuse '2014-06-29'. Siis jÀrgmise lehe saamiseks saab proovida jÀrgmist:

SELECT * FROM Sales.SalesOrderHeader
WHERE OrderDate < '2014-06-29'
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY

Probleem on selles, et OrderDate ei ole ainulaadne vĂ€li ja ĂŒlaltoodud tingimus lĂ”petab tĂ”enĂ€oliselt paljude vajalike ridade vahelejĂ€tmise. Selle pĂ€ringu selguse tagamiseks tuleb tingimusele lisada ainulaadne vĂ€li (eeldame, et 75074 on viimane esmane vĂ”tme vÀÀrtus esimesest osast):

SELECT * FROM Sales.SalesOrderHeader
WHERE (OrderDate = '2014-06-29' AND SalesOrderID < 75074)
   OR (OrderDate < '2014-06-29')
ORDER BY OrderDate DESC, SalesOrderID DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY

See variant töötab kenasti, kuid ĂŒldiselt on seda raske optimeerida, kuna tingimus sisaldab OR operaatorit. Kui OrderDate kasvab koos esmane vĂ”tme vÀÀrtusega, saab tingimust lihtsustada, jĂ€ttes alles ainult SalesOrderID filtri. Kuid kui esmane vĂ”tme vÀÀrtuste ja tulemuste sorteerimise aluseks oleva vĂ€ljade vahel ei ole ranget korrelatsiooni - enamikus andmebaasihaldussĂŒsteemides ei Ă”nnestu vĂ€ltida seda OR-i. Minule teadaolev erand on PostgreSQL, kus ridade vĂ”rdlemine toetatakse tĂ€ielikult ja ĂŒlaltoodud tingimust saab kirjutada kui "WHERE (OrderDate, SalesOrderID) < ('2014-06-29', 75074)". Kui on olemas komposiitvĂ”ti nende kahe vĂ€lja jaoks, peaks selline pĂ€ring olema piisavalt kerge.

Teine alternatiivne lĂ€henemine vĂ”ib esineda nĂ€iteks ElasticSearch scroll API vĂ”i Cosmos DB — kus pĂ€ring ei tagasta mitte ainult andmeid, vaid ka spetsiaalset identifikaatorit, mille abil saab saada jĂ€rgmise andmepartii. Kui see identifikaator on piiramatu elueaga (nagu Cosmos DB-s), siis on see suurepĂ€rane viis lehekeste jĂ€rkjĂ€rguliseks navigeerimiseks (ĂŒlaltoodud variants #2). Selle vĂ”imalikke puudusi: ei toetata kaugeltki kĂ”igis andmebaaside haldamise sĂŒsteemides; saadud jĂ€rgmise partii identifikaatoril vĂ”ib olla piiratud eluiga, mis ĂŒldjuhul ei sobi kasutajate interaktsiooni rakendamiseks (nĂ€iteks ElasticSearch scroll API).

Kompleksne filtreerimine

TĂ€itame ĂŒlesannet veelgi keerulisemaks. Oletame, et on tekkinud nĂ”ue rakendada nn faceted search, mida kĂ”ik kindlasti tunnevad e-poodide kontekstis. Ülaltoodud nĂ€ited tellimuste tabelist ei ole siin vĂ€ga nĂ€itlikud, seega lĂŒlitume AdventureWorks andmebaasi Product tabelisse:

Otsingutulemuste vÀljund ja jÔudlusprobleemid
Mis on faceted search idee? See seisneb selles, et iga filtri elemendi jaoks nÀidatakse vastava kriteeriumi kohta vastavate kirjeid arvu. arvestades filtreid, mis on valitud kÔigis teistes kategooriates..

NÀiteks, kui valime selles nÀites kategooria Bikes ja vÀrvi Black, kuvab tabel ainult mustade vÀrvi jalgrattaid, kuid samas:

  • Iga "Categories" grupi kriteeriumi jaoks nĂ€idatakse musta vĂ€rvi tooteid, mis kuuluvad sellesse kategooriasse.
  • Iga "Colors" grupi kriteeriumi jaoks nĂ€idatakse mustade jalgrataste arvu.

Siin on nÀide selliste tingimuste tulemuste vÀljundist:

Otsingutulemuste vÀljund ja jÔudlusprobleemid
Kui lisaks valida kategooria "Clothing", kuvab tabel ka musta vÀrvi riideid, mis on saadaval. Mustade toodete arvu "Color" sektsioonis arvutatakse samuti uute tingimuste jÀrgi, ent "Categories" sektsioonis ei muutu midagi... Loodan, et need nÀited on piisavad, et mÔista tuttavat faceted searchi töökorraldust.

NĂŒĂŒd kujutame ette, kuidas seda relatsioonilises andmebaasis rakendada. Iga kriteeriumigrupp, nagu Category ja Color, vajab eraldi pĂ€ringut:

SELECT pc.ProductCategoryID, pc.Name, COUNT(1) FROM Production.Product p
  INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
  INNER JOIN Production.ProductCategory pc ON ps.ProductCategoryID = pc.ProductCategoryID
WHERE p.Color = 'Black'
GROUP BY pc.ProductCategoryID, pc.Name
ORDER BY COUNT(1) DESC

Otsingutulemuste vÀljund ja jÔudlusprobleemid

SELECT Color, COUNT(1) FROM Production.Product p
  INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE ps.ProductCategoryID = 1 --Bikes
GROUP BY Color
ORDER BY COUNT(1) DESC

Otsingutulemuste vÀljund ja jÔudlusprobleemid
Mis on valesti sellega lahendusega? VĂ€ga lihtne — see ei skaala hĂ€sti. Iga filtreerimisosakond nĂ”uab eraldi pĂ€ringut koguste arvestamiseks ja need pĂ€ringud ei ole just kerged. E-poes vĂ”ib mĂ”nes kategoorias olla ka mitu tosinat filtreerimisosakonda, mis vĂ”ib olla tĂ€iendavaks probleemiks jĂ”udlusest.

Tavaliselt pÀrast neid vÀiteid pakuvad mulle mÔned lahendused, nimelt:

  • Kombineeri kĂ”ik koguse arvestused ĂŒheks pĂ€ringuks. Tehniliselt on see vĂ”imalik kasutada UNION vĂ”tmesĂ”na, kuid see ei paranda jĂ”udlust — andmebaasil tuleb ikkagi iga osa "nullist" lĂ€bi viia.
  • Kata arvestused. Seda soovitatakse mulle peaaegu igal korral, kui ma probleemi kirjeldan. Detail on see, et see on ĂŒldiselt vĂ”imatu. Oletame, et meil on 10 "fasaadi", milles igas on 5 vÀÀrtust. See on vĂ€ga "moderne" olukord vĂ”rreldes sellega, mida nĂ€ha sama internetipoe puhul. Ühe fasaadi elemendi valik mĂ”jutab 9 teise koguseid, teisisĂ”nu, iga kriteeriumi kombinatsiooni jaoks vĂ”ivad kogused olla erinevad. Kokku on meie nĂ€ites 50 kriteeriumi, mida kasutaja saab valida, seega on vĂ”imalikke kombinatsioone 250. Sellise andmemassiivi tĂ€itmiseks ei piisa ei mĂ€lust ega ajast. Siin vĂ”ib vastu vaielda ja öelda, et mitte kĂ”ik kombinatsioonid ei ole reaalsed ja kasutaja valib harva rohkem kui 5-10 kriteeriumi. Jah, on vĂ”imalik teha laisk laadimine ja koguste cache ainult nende jaoks, mida on kunagi valitud, kuid mida rohkem on valikuvĂ”imalusi, seda vĂ€hem efektiivne on selline cache ja seda silmatorkavamad on vastamise ajaga seotud probleemid (eriti kui andmekogum muutub regulaarselt).

Õnneks on sellisel ĂŒlesandel juba ammu olemas piisavalt efektiivsed lahendused, mis ennustatavalt töötavad suurte andmemahtude poole. Iga ĂŒhte neist variantidest on mĂ”ttekas jagada fassaadide ĂŒlearvutamine ja tulemuste lehe saamine kaheks paralleelseks pĂ€ringuks serverisse ning korraldada kasutajaliides selliselt, et fassaadide andmete laadimine "ei sega" otsingutulemuste kuvamist.

  • Kutsuge tĂ€ielikku "fassaadide" ĂŒmberarvestust nii harva kui vĂ”imalik. NĂ€iteks, Ă€rge arvutage kĂ”ike iga otsingukriteeriumi muutmise korral, vaid leidke ĂŒldine vastuste arv, mis vastab praegustele tingimustele, ja pakkuda kasutajale nende kuvamist — "leidub 1425 kirjet, nĂ€idata?" Kasutaja vĂ”ib kas jĂ€tkata otsingutingimuste muutmist vĂ”i vajutada nuppu „nĂ€ita“. Alles teisel juhul tehakse kĂ”ik pĂ€ringud tulemuste saamiseks ja kĂ”igi "fassaadide" arvu ĂŒmberarvestamiseks. Samuti tuleb silmas pidada, et tuleb tegeleda pĂ€ringuga ĂŒldise vastuste arvu saamiseks ja selle optimeerimisega. Sellist meetodit vĂ”ib leida paljudest vĂ€ikestest veebipoodidest. On selge, et see ei ole imeravim, kuid lihtsates olukordades vĂ”ib olla kokkuvĂ”tteks hea kompromiss.
  • Kasutage otsingumootoreid tulemuste otsimiseks ja fassaadide arvestamiseks, nagu Solr, ElasticSearch, Sphinx ja teised. KĂ”ik need on loodud "fassaadide" loomiseks ja teevad seda piisavalt tĂ”husalt, kasutades pööratud indekseerimist. Kuidas otsingumootorid töötavad, miks nad nendes olukordades on tĂ”husamad kui tavalised andmebaasid, millised on praktika ja takistused — see on eraldi artikli teema. Kuid soovin tĂ€helepanu juhtida sellele, et otsingumootor ei saa olla peamise andmehoidla asendaja; see on lisa: kĂ”ik muudatused peamises andmebaasis, mis on otsingu jaoks olulised, sĂŒnkroniseeritakse otsinguindeksisse; otsingumehhanism suhtleb tavaliselt ainult otsingumootoriga ega pöördu peamise andmebaasi poole. Üks olulisemaid aspekte on see, kuidas korraldada sĂŒnkroniseerimist usaldusvÀÀrselt. KĂ”ik sĂ”ltub "reaktsiooniaja" nĂ”uetest. Kui aeg peamise andmebaasi muutmise ja selle "kuvamise" vahel otsingus ei ole kriitiline, saab luua teenuse, mis vaatab iga paari minuti tagant hiljaaegu muudetud kirjeid ja indekseerib need. Kui nĂ”utav on vĂ”imalikult minimaalne reaktsiooniaeg, saab rakendada midagi taolist. transactional outbox uuenduste saatmiseks otsinguteenusesse.

JĂ€reldused

  1. Server-side paging implementation is a serious complication, and it should only be applied for rapidly growing or simply large datasets. There is no absolutely precise recipe for evaluating what constitutes 'large' or 'rapidly growing,' but I would adhere to the following approach:
    • If obtaining the complete dataset, considering server time and data transfer, fits within performance requirements, then there is no point in implementing server-side paging.
    • It may happen that there are currently no performance issues due to having little data, but the data collection is constantly growing. If a dataset might eventually no longer satisfy the previous point, it's better to lay the groundwork for paging right away.
  2. If there is no strict business requirement for showing the total number of results or displaying page numbers, and your system does not have a search engine, it is better not to implement these aspects and instead consider option #2.
  3. If there is a clear requirement for faceted search, you have two options to avoid sacrificing performance:
    • Do not recalculate all counts with every change in search criteria.
    • Use search engines such as Solr, ElasticSearch, Sphinx, and others. However, it should be understood that it cannot replace the main database and should be used as a complement to the primary storage to solve search tasks.
  4. Also, in the case of faceted search, it makes sense to separate the retrieval of the search results page and the count of quantities into two parallel requests. The count of quantities may take longer than retrieving the results, while the results are more important for the user.
  5. If you are using an SQL database for searching, any code changes related to this part must be thoroughly tested for performance against the relevant volume of data (exceeding the volume in the 'live' database). It is also advisable to monitor query execution times on all database instances, especially on the 'live' one. Even if everything was fine during the development phase with the query plans, the situation may change significantly as the volume of data grows.

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster