మనకు తెలిసిన అన్ని అప్లికేషన్లలోని సాధారణ దృశ్యాలలో ఒకటి నిర్దిష్ట ప్రమాణాల ప్రకారం డేటా కోసం శోధించడం మరియు దానిని సులభంగా చదవగలిగే రూపంలో ప్రదర్శించడం. సార్టింగ్, గ్రూపింగ్ మరియు పేజింగ్ కోసం అదనపు ఎంపికలు కూడా ఉండవచ్చు. పని, సిద్ధాంతపరంగా, పనికిమాలినది, కానీ దానిని పరిష్కరించేటప్పుడు, చాలా మంది డెవలపర్లు అనేక తప్పులు చేస్తారు, ఇది తరువాత ఉత్పాదకతను దెబ్బతీస్తుంది. ఈ సమస్యను పరిష్కరించడానికి వివిధ ఎంపికలను పరిశీలిద్దాం మరియు అత్యంత ప్రభావవంతమైన అమలును ఎంచుకోవడానికి సిఫార్సులను రూపొందించండి.
పేజింగ్ ఎంపిక #1
సెర్చ్ ఫలితాలను దాని అత్యంత క్లాసిక్ రూపంలో పేజీల వారీగా ప్రదర్శించడం అనేది గుర్తుకు వచ్చే సులభమైన ఎంపిక.
మీ అప్లికేషన్ రిలేషనల్ డేటాబేస్ని ఉపయోగిస్తుందనుకుందాం. ఈ సందర్భంలో, ఈ ఫారమ్లో సమాచారాన్ని ప్రదర్శించడానికి, మీరు రెండు SQL ప్రశ్నలను అమలు చేయాలి:
ప్రస్తుత పేజీ కోసం అడ్డు వరుసలను పొందండి.
శోధన ప్రమాణాలకు అనుగుణంగా మొత్తం పంక్తుల సంఖ్యను లెక్కించండి - పేజీలను ప్రదర్శించడానికి ఇది అవసరం.
పరీక్ష MS SQL డేటాబేస్ని ఉదాహరణగా ఉపయోగించి మొదటి ప్రశ్నను చూద్దాం అడ్వెంచర్ వర్క్స్ 2016 సర్వర్ కోసం. ఈ ప్రయోజనం కోసం మేము Sales.SalesOrderHeader పట్టికను ఉపయోగిస్తాము:
SELECT * FROM Sales.SalesOrderHeader
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY
పైన పేర్కొన్న ప్రశ్న జాబితా నుండి మొదటి 50 ఆర్డర్లను అందిస్తుంది, అదనంగా అవరోహణ తేదీ ద్వారా క్రమబద్ధీకరించబడుతుంది, మరో మాటలో చెప్పాలంటే, 50 అత్యంత ఇటీవలి ఆర్డర్లు.
ఇది టెస్ట్ బేస్లో త్వరగా నడుస్తుంది, అయితే అమలు ప్రణాళిక మరియు I/O గణాంకాలను చూద్దాం:
మీరు ప్రశ్న రన్టైమ్లో SET STATISTICS IO ON కమాండ్ని అమలు చేయడం ద్వారా ప్రతి ప్రశ్నకు I/O గణాంకాలను పొందవచ్చు.
మీరు ఎగ్జిక్యూషన్ ప్లాన్ నుండి చూడగలిగినట్లుగా, జోడించిన తేదీ ప్రకారం సోర్స్ టేబుల్లోని అన్ని అడ్డు వరుసలను క్రమబద్ధీకరించడం అత్యంత వనరు-ఇంటెన్సివ్ ఎంపిక. మరియు సమస్య ఏమిటంటే, పట్టికలో ఎక్కువ వరుసలు కనిపిస్తాయి, సార్టింగ్ "కష్టం" అవుతుంది. ఆచరణలో, అటువంటి పరిస్థితులను నివారించాలి, కాబట్టి అదనంగా తేదీకి సూచికను జోడించి, వనరుల వినియోగం మారితే చూద్దాం:
సహజంగానే ఇది చాలా మెరుగుపడింది. అయితే సమస్యలన్నీ పరిష్కారమయ్యాయా? వస్తువుల మొత్తం ధర $100 కంటే ఎక్కువ ఉన్న ఆర్డర్ల కోసం శోధించడానికి ప్రశ్నను మారుద్దాం:
SELECT * FROM Sales.SalesOrderHeader
WHERE SubTotal > 100
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY
మేము ఒక తమాషా పరిస్థితిని కలిగి ఉన్నాము: ప్రశ్న ప్రణాళిక మునుపటి కంటే చాలా అధ్వాన్నంగా లేదు, కానీ లాజికల్ రీడ్ల వాస్తవ సంఖ్య పూర్తి టేబుల్ స్కాన్తో పోలిస్తే దాదాపు రెండు రెట్లు పెద్దది. ఒక మార్గం ఉంది - మేము ఇప్పటికే ఉన్న ఇండెక్స్ నుండి మిశ్రమ సూచికను తయారు చేసి, రెండవ ఫీల్డ్గా వస్తువుల మొత్తం ధరను జోడిస్తే, మేము మళ్లీ 165 లాజికల్ రీడ్లను పొందుతాము:
CREATE INDEX IX_SalesOrderHeader_OrderDate_SubTotal on Sales.SalesOrderHeader(OrderDate, SubTotal);
ఈ ఉదాహరణల శ్రేణిని చాలా కాలం పాటు కొనసాగించవచ్చు, కానీ నేను ఇక్కడ వ్యక్తం చేయాలనుకుంటున్న రెండు ప్రధాన ఆలోచనలు:
శోధన ప్రశ్నకు ఏదైనా కొత్త ప్రమాణం లేదా క్రమబద్ధీకరణ క్రమాన్ని జోడించడం శోధన ప్రశ్న వేగంపై గణనీయమైన ప్రభావాన్ని చూపుతుంది.
మేము డేటాలో కొంత భాగాన్ని మాత్రమే తీసివేయవలసి వస్తే మరియు శోధన పదాలకు సరిపోలే అన్ని ఫలితాలు కానట్లయితే, అటువంటి ప్రశ్నను ఆప్టిమైజ్ చేయడానికి అనేక మార్గాలు ఉన్నాయి.
ఇప్పుడు ప్రారంభంలో పేర్కొన్న రెండవ ప్రశ్నకు వెళ్దాం - శోధన ప్రమాణాన్ని సంతృప్తిపరిచే రికార్డుల సంఖ్యను లెక్కించే ప్రశ్న. అదే ఉదాహరణను తీసుకుందాం - $100 కంటే ఎక్కువ ఉన్న ఆర్డర్ల కోసం శోధించడం:
SELECT COUNT(1) FROM Sales.SalesOrderHeader
WHERE SubTotal > 100
పైన సూచించిన మిశ్రమ సూచికను బట్టి, మేము పొందుతాము:
సబ్టోటల్ ఫీల్డ్ మొదటి స్థానంలో లేనందున, ప్రశ్న మొత్తం సూచిక గుండా వెళుతుందనే వాస్తవం ఆశ్చర్యం కలిగించదు, కాబట్టి ప్రశ్న దానిని ఉపయోగించదు. సబ్టోటల్ ఫీల్డ్లో మరొక సూచికను జోడించడం ద్వారా సమస్య పరిష్కరించబడుతుంది మరియు ఫలితంగా ఇది 48 లాజికల్ రీడ్లను మాత్రమే ఇస్తుంది.
మీరు పరిమాణాలను లెక్కించడానికి అభ్యర్థనలకు మరికొన్ని ఉదాహరణలను ఇవ్వవచ్చు, కానీ సారాంశం అలాగే ఉంటుంది: డేటా యొక్క భాగాన్ని స్వీకరించడం మరియు మొత్తం మొత్తాన్ని లెక్కించడం అనేది రెండు ప్రాథమికంగా భిన్నమైన అభ్యర్థనలు, మరియు ప్రతిదానికి ఆప్టిమైజేషన్ కోసం దాని స్వంత చర్యలు అవసరం. సాధారణంగా, మీరు రెండు ప్రశ్నలకు సమానంగా పని చేసే సూచికల కలయికను కనుగొనలేరు.
తదనుగుణంగా, అటువంటి శోధన పరిష్కారాన్ని అభివృద్ధి చేస్తున్నప్పుడు స్పష్టం చేయవలసిన ముఖ్యమైన ఆవశ్యకతలలో ఒకటి, కనుగొనబడిన వస్తువుల మొత్తం సంఖ్యను చూడటం వ్యాపారానికి నిజంగా ముఖ్యమా అనేది. లేదు అని తరచుగా జరుగుతుంది. మరియు నిర్దిష్ట పేజీ సంఖ్యల ద్వారా నావిగేషన్ అనేది చాలా ఇరుకైన స్కోప్తో కూడిన పరిష్కారం, ఎందుకంటే చాలా పేజింగ్ దృశ్యాలు "తదుపరి పేజీకి వెళ్లు" లాగా కనిపిస్తాయి.
పేజింగ్ ఎంపిక #2
కనుగొనబడిన వస్తువుల మొత్తం సంఖ్యను తెలుసుకోవడం గురించి వినియోగదారులు పట్టించుకోరని అనుకుందాం. శోధన పేజీని సరళీకృతం చేయడానికి ప్రయత్నిద్దాం:
వాస్తవానికి, మారిన ఏకైక విషయం ఏమిటంటే, నిర్దిష్ట పేజీ సంఖ్యలకు నావిగేట్ చేయడానికి మార్గం లేదు మరియు ఇప్పుడు ఈ పట్టికను ప్రదర్శించడానికి ఎన్ని ఉండవచ్చో తెలుసుకోవలసిన అవసరం లేదు. కానీ ప్రశ్న తలెత్తుతుంది - తదుపరి పేజీకి (“తదుపరి” లింక్ను సరిగ్గా ప్రదర్శించడానికి) డేటా ఉందో లేదో పట్టికకు ఎలా తెలుస్తుంది?
సమాధానం చాలా సులభం: మీరు డేటాబేస్ నుండి డిస్ప్లే కోసం అవసరమైన దాని కంటే ఎక్కువ రికార్డును చదవగలరు మరియు ఈ "అదనపు" రికార్డ్ ఉనికిని తదుపరి భాగం ఉందో లేదో చూపుతుంది. ఈ విధంగా, మీరు ఒక పేజీ డేటాను పొందడానికి ఒక అభ్యర్థనను మాత్రమే అమలు చేయాలి, ఇది పనితీరును గణనీయంగా మెరుగుపరుస్తుంది మరియు అటువంటి కార్యాచరణకు మద్దతు ఇవ్వడాన్ని సులభతరం చేస్తుంది. నా ఆచరణలో, 4-5 సార్లు ఫలితాల పంపిణీని వేగవంతం చేసిన మొత్తం రికార్డుల సంఖ్యను లెక్కించడానికి నిరాకరించినప్పుడు ఒక సందర్భం ఉంది.
ఈ విధానం కోసం అనేక వినియోగదారు ఇంటర్ఫేస్ ఎంపికలు ఉన్నాయి: "వెనుక" మరియు "ఫార్వర్డ్" కమాండ్లు, పై ఉదాహరణలో వలె, "మరిన్ని లోడ్ చేయి" బటన్, ఇది పని చేసే "అనంతమైన స్క్రోల్" అనే ప్రదర్శించబడిన ఫలితాలకు కొత్త భాగాన్ని జోడిస్తుంది. "మరింత లోడ్ చేయి" " అనే సూత్రం ప్రకారం, కానీ తదుపరి భాగాన్ని పొందడానికి సంకేతం వినియోగదారు ప్రదర్శించబడిన అన్ని ఫలితాలను చివరి వరకు స్క్రోల్ చేయడానికి. విజువల్ సొల్యూషన్ ఏమైనప్పటికీ, డేటా నమూనా సూత్రం అలాగే ఉంటుంది.
పేజింగ్ అమలు యొక్క సూక్ష్మ నైపుణ్యాలు
పైన ఇవ్వబడిన అన్ని ప్రశ్న ఉదాహరణలు “ఆఫ్సెట్ + కౌంట్” విధానాన్ని ఉపయోగిస్తాయి, ప్రశ్న ఫలిత వరుసలను ఏ క్రమంలో మరియు ఎన్ని అడ్డు వరుసలను తిరిగి ఇవ్వాలో నిర్దేశించినప్పుడు. ముందుగా, ఈ సందర్భంలో పారామితి ఉత్తీర్ణతను ఎలా నిర్వహించాలో ఉత్తమంగా చూద్దాం. ఆచరణలో, నేను అనేక పద్ధతులను చూశాను:
అభ్యర్థించిన పేజీ యొక్క క్రమ సంఖ్య (పేజీ సూచిక), పేజీ పరిమాణం (పేజీ పరిమాణం).
తిరిగి ఇవ్వాల్సిన మొదటి రికార్డు యొక్క క్రమ సంఖ్య (స్టార్ట్ఇండెక్స్), ఫలితంలోని గరిష్ట రికార్డుల సంఖ్య (గణన).
తిరిగి ఇవ్వాల్సిన మొదటి రికార్డు (స్టార్ట్ఇండెక్స్) యొక్క సీక్వెన్స్ నంబర్, రిటర్న్ చేయాల్సిన చివరి రికార్డ్ యొక్క సీక్వెన్స్ నంబర్ (ఎండ్ఇండెక్స్).
మొదటి చూపులో ఇది చాలా ప్రాథమికమైనది, తేడా లేదు అని అనిపించవచ్చు. కానీ ఇది అలా కాదు - అత్యంత అనుకూలమైన మరియు సార్వత్రిక ఎంపిక రెండవది (స్టార్ట్ఇండెక్స్, కౌంట్). దీనికి అనేక కారణాలు ఉన్నాయి:
పైన ఇచ్చిన +1 ఎంట్రీ ప్రూఫ్ రీడింగ్ విధానం కోసం, pageIndex మరియు pageSizeతో మొదటి ఎంపిక చాలా అసౌకర్యంగా ఉంది. ఉదాహరణకు, మేము ఒక్కో పేజీకి 50 పోస్ట్లను ప్రదర్శించాలనుకుంటున్నాము. పై అల్గోరిథం ప్రకారం, మీరు అవసరమైన దానికంటే ఎక్కువ రికార్డును చదవాలి. ఈ “+1” సర్వర్లో అమలు చేయబడకపోతే, మొదటి పేజీ కోసం మనం 1 నుండి 51 వరకు, రెండవది - 51 నుండి 101 వరకు, మొదలైన వాటి కోసం రికార్డులను అభ్యర్థించాలి. మీరు 51 పేజీ పరిమాణాన్ని పేర్కొని, పేజీ సూచికను పెంచినట్లయితే, రెండవ పేజీ 52 నుండి 102కి తిరిగి వస్తుంది. దీని ప్రకారం, మొదటి ఎంపికలో, తదుపరి పేజీకి వెళ్లడానికి బటన్ను సరిగ్గా అమలు చేయడానికి ఏకైక మార్గం సర్వర్ "అదనపు" పంక్తిని సరిదిద్దడం, ఇది చాలా అవ్యక్త స్వల్పభేదాన్ని కలిగి ఉంటుంది.
మూడవ ఎంపిక అస్సలు అర్ధవంతం కాదు, ఎందుకంటే చాలా డేటాబేస్లలో ప్రశ్నలను అమలు చేయడానికి మీరు చివరి రికార్డ్ యొక్క సూచిక కంటే కౌంట్ను పాస్ చేయాల్సి ఉంటుంది. ఎండ్ఇండెక్స్ నుండి స్టార్ట్ఇండెక్స్ను తీసివేయడం సాధారణ అంకగణిత చర్య కావచ్చు, కానీ ఇక్కడ అది నిరుపయోగంగా ఉంటుంది.
ఇప్పుడు మనం "ఆఫ్సెట్ + పరిమాణం" ద్వారా పేజింగ్ను అమలు చేయడం వల్ల కలిగే నష్టాలను వివరించాలి:
ప్రతి తదుపరి పేజీని తిరిగి పొందడం మునుపటి కంటే ఖరీదైనది మరియు నెమ్మదిగా ఉంటుంది, ఎందుకంటే డేటాబేస్ ఇప్పటికీ శోధన మరియు క్రమబద్ధీకరణ ప్రమాణాల ప్రకారం "ప్రారంభం నుండి" అన్ని రికార్డుల ద్వారా వెళ్ళవలసి ఉంటుంది, ఆపై కావలసిన భాగాన్ని ఆపివేయాలి.
అన్ని DBMSలు ఈ విధానానికి మద్దతు ఇవ్వలేవు.
ప్రత్యామ్నాయాలు ఉన్నాయి, కానీ అవి కూడా అసంపూర్ణమైనవి. ఈ విధానాలలో మొదటిది "కీసెట్ పేజింగ్" లేదా "సీక్ మెథడ్" అని పిలువబడుతుంది మరియు ఇది క్రింది విధంగా ఉంటుంది: ఒక భాగాన్ని స్వీకరించిన తర్వాత, మీరు పేజీలోని చివరి రికార్డ్లోని ఫీల్డ్ విలువలను గుర్తుంచుకోవచ్చు, ఆపై వాటిని పొందేందుకు వాటిని ఉపయోగించవచ్చు తదుపరి భాగం. ఉదాహరణకు, మేము ఈ క్రింది ప్రశ్నను అమలు చేసాము:
SELECT * FROM Sales.SalesOrderHeader
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY
మరియు చివరి రికార్డ్లో మాకు ఆర్డర్ తేదీ విలువ '2014-06-29' వచ్చింది. తదుపరి పేజీని పొందడానికి మీరు దీన్ని ప్రయత్నించవచ్చు:
SELECT * FROM Sales.SalesOrderHeader
WHERE OrderDate < '2014-06-29'
ORDER BY OrderDate DESC
OFFSET 0 ROWS
FETCH NEXT 50 ROWS ONLY
సమస్య ఏమిటంటే, OrderDate అనేది నాన్-యూనిక్ ఫీల్డ్ మరియు పైన పేర్కొన్న షరతు చాలా అవసరమైన అడ్డు వరుసలను కోల్పోయే అవకాశం ఉంది. ఈ ప్రశ్నకు అస్పష్టతను జోడించడానికి, మీరు షరతుకు ఒక ప్రత్యేక ఫీల్డ్ని జోడించాలి (మొదటి భాగం నుండి ప్రాథమిక కీ యొక్క చివరి విలువ 75074 అని భావించండి):
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
ఈ ఐచ్ఛికం సరిగ్గా పని చేస్తుంది, కానీ సాధారణంగా కండిషన్లో OR ఆపరేటర్ ఉన్నందున ఆప్టిమైజ్ చేయడం కష్టం. OrderDate పెరిగేకొద్దీ ప్రాథమిక కీ విలువ పెరిగితే, SalesOrderID ద్వారా ఫిల్టర్ను మాత్రమే వదిలివేయడం ద్వారా పరిస్థితిని సులభతరం చేయవచ్చు. కానీ ప్రైమరీ కీ యొక్క విలువలకు మరియు ఫలితం క్రమబద్ధీకరించబడిన ఫీల్డ్కు మధ్య ఖచ్చితమైన సహసంబంధం లేకుంటే, చాలా DBMSలలో ఈ OR నివారించబడదు. నాకు తెలిసిన మినహాయింపు PostgreSQL, ఇది టుపుల్ పోలికలకు పూర్తిగా మద్దతు ఇస్తుంది మరియు పై పరిస్థితిని "WHERE (OrderDate, SalesOrderID) < ('2014-06-29', 75074)" అని వ్రాయవచ్చు. ఈ రెండు ఫీల్డ్లతో కూడిన కాంపోజిట్ కీ ఇచ్చినట్లయితే, ఇలాంటి ప్రశ్న చాలా సులభంగా ఉండాలి.
రెండవ ప్రత్యామ్నాయ విధానాన్ని కనుగొనవచ్చు, ఉదాహరణకు, లో సాగే శోధన స్క్రోల్ API లేదా కాస్మోస్ DB — ఒక అభ్యర్థన, డేటాతో పాటుగా, మీరు డేటా యొక్క తదుపరి భాగాన్ని పొందగలిగే ప్రత్యేక ఐడెంటిఫైయర్ను అందించినప్పుడు. ఈ ఐడెంటిఫైయర్కు అపరిమిత జీవితకాలం ఉంటే (కామ్సోస్ డిబిలో వలె), అప్పుడు పేజీల మధ్య సీక్వెన్షియల్ ట్రాన్సిషన్తో పేజింగ్ను అమలు చేయడానికి ఇది గొప్ప మార్గం (పైన పేర్కొన్న ఎంపిక #2). దీని సాధ్యమయ్యే నష్టాలు: అన్ని DBMSలలో దీనికి మద్దతు లేదు; ఫలితంగా వచ్చే తదుపరి-చంక్ ఐడెంటిఫైయర్ పరిమిత జీవితకాలం కలిగి ఉండవచ్చు, ఇది సాధారణంగా వినియోగదారు పరస్పర చర్యను అమలు చేయడానికి తగినది కాదు (ElasticSearch స్క్రోల్ API వంటివి).
సంక్లిష్ట వడపోత
పనిని మరింత క్లిష్టతరం చేద్దాం. ఆన్లైన్ స్టోర్ల నుండి ప్రతి ఒక్కరికీ బాగా తెలిసిన ముఖ శోధన అని పిలవబడేదాన్ని అమలు చేయవలసిన అవసరం ఉందని అనుకుందాం. ఈ సందర్భంలో ఆర్డర్ల పట్టికపై ఆధారపడిన ఎగువ ఉదాహరణలు చాలా వివరణాత్మకమైనవి కావు, కాబట్టి AdventureWorks డేటాబేస్ నుండి ఉత్పత్తి పట్టికకు మారండి:
ముఖ శోధన వెనుక ఆలోచన ఏమిటి? వాస్తవం ఏమిటంటే ప్రతి ఫిల్టర్ మూలకం కోసం ఈ ప్రమాణానికి అనుగుణంగా ఉన్న రికార్డుల సంఖ్య చూపబడుతుంది అన్ని ఇతర వర్గాలలో ఎంచుకున్న ఫిల్టర్లను పరిగణనలోకి తీసుకుంటుంది.
ఉదాహరణకు, మేము ఈ ఉదాహరణలో బైక్ల వర్గాన్ని మరియు నలుపు రంగును ఎంచుకుంటే, పట్టిక నలుపు బైక్లను మాత్రమే చూపుతుంది, కానీ:
కేటగిరీల సమూహంలోని ప్రతి ప్రమాణం కోసం, ఆ వర్గంలోని ఉత్పత్తుల సంఖ్య నలుపు రంగులో చూపబడుతుంది.
"కలర్స్" సమూహం యొక్క ప్రతి ప్రమాణం కోసం, ఈ రంగు యొక్క సైకిళ్ల సంఖ్య చూపబడుతుంది.
అటువంటి పరిస్థితుల కోసం ఫలిత అవుట్పుట్ యొక్క ఉదాహరణ ఇక్కడ ఉంది:
మీరు "దుస్తులు" వర్గాన్ని కూడా తనిఖీ చేస్తే, టేబుల్ స్టాక్లో ఉన్న నల్లని దుస్తులను కూడా చూపుతుంది. "రంగు" విభాగంలోని నలుపు ఉత్పత్తుల సంఖ్య కూడా కొత్త షరతుల ప్రకారం తిరిగి లెక్కించబడుతుంది, "కేటగిరీలు" విభాగంలో మాత్రమే ఏమీ మారదు... సాధారణ ముఖ శోధన అల్గారిథమ్ను అర్థం చేసుకోవడానికి ఈ ఉదాహరణలు సరిపోతాయని నేను ఆశిస్తున్నాను.
ఇప్పుడు దీన్ని రిలేషనల్ ప్రాతిపదికన ఎలా అమలు చేయవచ్చో ఊహించుకుందాం. వర్గం మరియు రంగు వంటి ప్రతి ప్రమాణ సమూహానికి ప్రత్యేక ప్రశ్న అవసరం:
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
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
ఈ పరిష్కారంలో తప్పు ఏమిటి? ఇది చాలా సులభం - ఇది బాగా స్కేల్ చేయదు. ప్రతి ఫిల్టర్ విభాగానికి పరిమాణాలను లెక్కించడానికి ప్రత్యేక ప్రశ్న అవసరం మరియు ఈ ప్రశ్నలు సులభమైనవి కావు. ఆన్లైన్ స్టోర్లలో, కొన్ని వర్గాలు అనేక డజన్ల ఫిల్టర్ విభాగాలను కలిగి ఉండవచ్చు, ఇది తీవ్రమైన పనితీరు సమస్య కావచ్చు.
సాధారణంగా ఈ ప్రకటనల తర్వాత నాకు కొన్ని పరిష్కారాలు అందించబడతాయి, అవి:
అన్ని పరిమాణ గణనలను ఒక ప్రశ్నగా కలపండి. సాంకేతికంగా ఇది UNION కీవర్డ్ని ఉపయోగించి సాధ్యమవుతుంది, కానీ ఇది పనితీరుకు పెద్దగా సహాయం చేయదు - డేటాబేస్ ఇప్పటికీ మొదటి నుండి ప్రతి శకలాలను అమలు చేయాల్సి ఉంటుంది.
కాష్ పరిమాణాలు. నేను సమస్యను వివరించిన ప్రతిసారీ ఇది నాకు సూచించబడుతుంది. హెచ్చరిక ఏమిటంటే ఇది సాధారణంగా అసాధ్యం. మనకు 10 "ముఖాలు" ఉన్నాయని అనుకుందాం, వాటిలో ప్రతి ఒక్కటి 5 విలువలను కలిగి ఉంటుంది. అదే ఆన్లైన్ స్టోర్లలో చూడగలిగే దానితో పోలిస్తే ఇది చాలా "నిరాడంబరమైన" పరిస్థితి. ఒక కోణ మూలకం యొక్క ఎంపిక 9 ఇతరులలో పరిమాణాలను ప్రభావితం చేస్తుంది, మరో మాటలో చెప్పాలంటే, ప్రతి ప్రమాణాల కలయికకు పరిమాణాలు భిన్నంగా ఉండవచ్చు. మా ఉదాహరణలో, వినియోగదారు ఎంచుకోగల మొత్తం 50 ప్రమాణాలు ఉన్నాయి; అందువల్ల, 250 సాధ్యమైన కలయికలు ఉంటాయి. అటువంటి డేటా శ్రేణిని పూరించడానికి తగినంత మెమరీ లేదా సమయం లేదు. ఇక్కడ మీరు అభ్యంతరం చెప్పవచ్చు మరియు అన్ని కలయికలు నిజమైనవి కావు మరియు వినియోగదారు అరుదుగా 5-10 కంటే ఎక్కువ ప్రమాణాలను ఎంచుకుంటారు. అవును, లేజీ లోడ్ చేయడం మరియు ఎప్పటికి ఎంచుకోబడిన వాటి మొత్తాన్ని మాత్రమే కాష్ చేయడం సాధ్యమవుతుంది, అయితే ఎక్కువ ఎంపికలు ఉంటే, అటువంటి కాష్ తక్కువ సామర్థ్యంతో ఉంటుంది మరియు ప్రతిస్పందన సమయ సమస్యలు మరింత గుర్తించదగినవిగా ఉంటాయి (ముఖ్యంగా డేటా సెట్ క్రమం తప్పకుండా మారుతుంది)
అదృష్టవశాత్తూ, అటువంటి సమస్య చాలా కాలం పాటు చాలా ప్రభావవంతమైన పరిష్కారాలను కలిగి ఉంది, ఇది పెద్ద మొత్తంలో డేటాపై ఊహించదగినదిగా పని చేస్తుంది. ఈ ఎంపికలలో దేనికైనా, కోణాల రీకాలిక్యులేషన్ మరియు ఫలితాల పేజీని సర్వర్కి రెండు సమాంతర కాల్లుగా విభజించడం మరియు వినియోగదారు ఇంటర్ఫేస్ను నిర్వహించడం సమంజసంగా ఉంటుంది, తద్వారా కోణాల ద్వారా డేటాను లోడ్ చేయడం డిస్ప్లేలో "జోక్యం కలిగించదు" శోధన ఫలితాలు.
సాధ్యమైనంత అరుదుగా "ముఖాలు" యొక్క పూర్తి పునఃగణనను కాల్ చేయండి. ఉదాహరణకు, శోధన ప్రమాణాలు మారిన ప్రతిసారీ అన్నింటినీ తిరిగి లెక్కించవద్దు, బదులుగా ప్రస్తుత పరిస్థితులకు సరిపోయే మొత్తం ఫలితాల సంఖ్యను కనుగొని, వాటిని చూపించమని వినియోగదారుని ప్రాంప్ట్ చేయండి - “1425 రికార్డ్లు కనుగొనబడ్డాయి, చూపించాలా?” వినియోగదారు శోధన పదాలను మార్చడం కొనసాగించవచ్చు లేదా "షో" బటన్ను క్లిక్ చేయవచ్చు. రెండవ సందర్భంలో మాత్రమే ఫలితాలను పొందడం మరియు అన్ని "ముఖాలలో" పరిమాణాలను తిరిగి లెక్కించడం కోసం అన్ని అభ్యర్థనలు అమలు చేయబడతాయి. ఈ సందర్భంలో, మీరు సులభంగా చూడగలిగినట్లుగా, మొత్తం ఫలితాల సంఖ్య మరియు దాని ఆప్టిమైజేషన్ను పొందేందుకు మీరు అభ్యర్థనతో వ్యవహరించాల్సి ఉంటుంది. ఈ పద్ధతి అనేక చిన్న ఆన్లైన్ స్టోర్లలో చూడవచ్చు. సహజంగానే, ఈ సమస్యకు ఇది వినాశనం కాదు, కానీ సాధారణ సందర్భాల్లో ఇది మంచి రాజీగా ఉంటుంది.
ఫలితాలను కనుగొనడానికి మరియు Solr, ElasticSearch, Sphinx మరియు ఇతర అంశాలను లెక్కించడానికి శోధన ఇంజిన్లను ఉపయోగించండి. అవన్నీ "ముఖాలు" నిర్మించడానికి రూపొందించబడ్డాయి మరియు విలోమ సూచిక కారణంగా దీన్ని చాలా సమర్థవంతంగా చేస్తాయి. శోధన ఇంజిన్లు ఎలా పని చేస్తాయి, అటువంటి సందర్భాలలో అవి సాధారణ-ప్రయోజన డేటాబేస్ల కంటే ఎందుకు ఎక్కువ ప్రభావవంతంగా ఉంటాయి, ఏ అభ్యాసాలు మరియు ఆపదలు ఉన్నాయి - ఇది ప్రత్యేక కథనానికి సంబంధించిన అంశం. శోధన ఇంజిన్ ప్రధాన డేటా నిల్వకు ప్రత్యామ్నాయం కాదనే వాస్తవాన్ని ఇక్కడ నేను మీ దృష్టిని ఆకర్షించాలనుకుంటున్నాను; ఇది అదనంగా ఉపయోగించబడుతుంది: శోధనకు సంబంధించిన ప్రధాన డేటాబేస్లో ఏవైనా మార్పులు శోధన సూచికలో సమకాలీకరించబడతాయి; శోధన ఇంజిన్ సాధారణంగా శోధన ఇంజిన్తో మాత్రమే సంకర్షణ చెందుతుంది మరియు ప్రధాన డేటాబేస్ను యాక్సెస్ చేయదు. ఈ సమకాలీకరణను విశ్వసనీయంగా ఎలా నిర్వహించాలనేది ఇక్కడ అత్యంత ముఖ్యమైన అంశాలలో ఒకటి. ఇది అన్ని "ప్రతిస్పందన సమయం" అవసరాలపై ఆధారపడి ఉంటుంది. ప్రధాన డేటాబేస్లో మార్పు మరియు శోధనలో దాని "వ్యక్తీకరణ" మధ్య సమయం క్లిష్టమైనది కానట్లయితే, మీరు ప్రతి కొన్ని నిమిషాలకు ఇటీవల మార్చబడిన రికార్డుల కోసం శోధించే మరియు వాటిని సూచిక చేసే సేవను సృష్టించవచ్చు. మీకు సాధ్యమైనంత తక్కువ ప్రతిస్పందన సమయం కావాలంటే, మీరు ఇలాంటిదే అమలు చేయవచ్చు లావాదేవీ అవుట్బాక్స్ శోధన సేవకు నవీకరణలను పంపడానికి.
కనుగొన్న
సర్వర్-సైడ్ పేజింగ్ని అమలు చేయడం ఒక ముఖ్యమైన సమస్య మరియు వేగంగా అభివృద్ధి చెందుతున్న లేదా పెద్ద డేటా సెట్లకు మాత్రమే అర్ధమే. "పెద్దది" లేదా "వేగంగా అభివృద్ధి చెందుతున్నది" ఎలా అంచనా వేయాలో ఖచ్చితంగా ఖచ్చితమైన వంటకం లేదు, కానీ నేను ఈ విధానాన్ని అనుసరిస్తాను:
సర్వర్ సమయం మరియు నెట్వర్క్ ట్రాన్స్మిషన్ను పరిగణనలోకి తీసుకుని పూర్తి డేటా సేకరణను స్వీకరిస్తే, పనితీరు అవసరాలకు సాధారణంగా సరిపోతుంటే, సర్వర్ వైపు పేజింగ్ను అమలు చేయడంలో ఎటువంటి పాయింట్ లేదు.
తక్కువ డేటా ఉన్నందున, సమీప భవిష్యత్తులో పనితీరు సమస్యలు ఆశించని పరిస్థితి ఉండవచ్చు, కానీ డేటా సేకరణ నిరంతరం పెరుగుతోంది. భవిష్యత్తులో కొంత డేటా సెట్ మునుపటి పాయింట్ను సంతృప్తి పరచకపోతే, వెంటనే పేజింగ్ ప్రారంభించడం మంచిది.
మొత్తం ఫలితాల సంఖ్యను ప్రదర్శించడానికి లేదా పేజీ సంఖ్యలను ప్రదర్శించడానికి వ్యాపారం యొక్క భాగానికి ఎటువంటి కఠినమైన అవసరం లేనట్లయితే మరియు మీ సిస్టమ్కు శోధన ఇంజిన్ లేకపోతే, ఈ పాయింట్లను అమలు చేయకుండా మరియు ఎంపిక #2ని పరిగణించకపోవడమే మంచిది.
ముఖ శోధన కోసం స్పష్టమైన ఆవశ్యకత ఉంటే, పనితీరును త్యాగం చేయకుండా మీకు రెండు ఎంపికలు ఉన్నాయి:
శోధన ప్రమాణాలు మారిన ప్రతిసారీ అన్ని పరిమాణాలను తిరిగి లెక్కించవద్దు.
Solr, ElasticSearch, Sphinx మరియు ఇతర శోధన ఇంజిన్లను ఉపయోగించండి. కానీ ఇది ప్రధాన డేటాబేస్కు ప్రత్యామ్నాయం కాదని అర్థం చేసుకోవాలి మరియు శోధన సమస్యలను పరిష్కరించడానికి ప్రధాన నిల్వకు అదనంగా ఉపయోగించాలి.
అలాగే, ముఖ శోధన విషయంలో, శోధన ఫలితాల పేజీని తిరిగి పొందడం మరియు గణనను రెండు సమాంతర అభ్యర్థనలుగా విభజించడం అర్ధమే. ఫలితాలను పొందడం కంటే పరిమాణాలను లెక్కించడానికి ఎక్కువ సమయం పట్టవచ్చు, అయితే ఫలితాలు వినియోగదారుకు చాలా ముఖ్యమైనవి.
మీరు శోధించడం కోసం SQL డేటాబేస్ని ఉపయోగిస్తుంటే, ఈ భాగానికి సంబంధించిన ఏదైనా కోడ్ మార్పు తగిన డేటా (లైవ్ డేటాబేస్లోని వాల్యూమ్ను మించి) పనితీరు కోసం బాగా పరీక్షించబడాలి. డేటాబేస్ యొక్క అన్ని సందర్భాల్లో మరియు ముఖ్యంగా “లైవ్”లో ప్రశ్న అమలు సమయాన్ని పర్యవేక్షించడం కూడా మంచిది. డెవలప్మెంట్ దశలో క్వెరీ ప్లాన్లతో అంతా బాగానే ఉన్నప్పటికీ, డేటా పరిమాణం పెరిగేకొద్దీ, పరిస్థితి గమనించదగ్గ విధంగా మారవచ్చు.