Բարև բոլորին! Ես բեքենդ ծրագրավորող եմ, գրում եմ միկրով služցեր Java + Spring-ից: Աշխատում եմ Տինկովի ընկերությունում ներքին արտադրանքի զարգացման թիմերից մեկում:

Մեր թիմում հաճախ խոսելիս առաջանում է հարց, թե ինչպես կարելի է օպտիմալացնել հարցումները տվյալների բազայում: Մ siempre տեսանք, որ միշտ ցանկություն կա մի փոքր ավելի արագ աշխատել, բայց միշտ չէ, որ կարելի է խուսափել մտածված կառուցված ինդեքսներից, անհրաժեշտ է գտնել ինչ-որ շրջանցող ճանապարհներ: Եւ այդպիսի մի պաղպաղակների ժամանակ, ես գտա , SQL Performance Explained գրքի հեղինակի: Սա այդ հազվագյուտ տեսակը բլոգների է, որտեղ կարելի է շարունակաբար կարդալ բոլոր հոդվածները:
Ես ուզում եմ թարգմանել ձեզ համար Մարկուսի փոքր հոդվածը: Այն կարելի է անվանել մի տեսակ մանիֆեստ, որն նպատակ ունի ուշադրություն հրավիրել SQL ստանդարտի պրոցեսների offset-ի հին, բայց դեռևս արդիական խնդրին:
Մի քանի վայրերում ես կներդնեմ հեղինակի մեկնաբանություններ և դիտարկումներ: Այսպիսի բոլոր վայրերը ես կնշեմ «փար» նշումով առավելագույն պարզության համար:
Փոքրիկ ներածություն
Կարծում եմ, շատերն գիտեն, թե որքան խնդրահարույց և դանդաղ կարող է լինել էջային ընտրությունները offset-ով: Բայց գիտեք, որ այն կարելի է բավականին հեշտ փոխարինել ավելի արդյունավետ կառուցվածքով?
Ուրեմն, offset բանալի բառը ցույց է տալիս բազայինը` բաց թողնել հարցման մեջ առաջին n գրառումները: Բայց բազան դեռևս պետք է ընթերցի այս առաջին n գրառումները սկանդրագրից, причём տրված կարգով (գտեք դասավորությունը, եթե դա սահմանված է), և միայն հետո հնարավոր կլինի վերադարձնել գրառումները n+1-ից ու դրանից հետո: Լրիվ առյուծ, որ խնդիրը չէ կոնկրետ իրականացումն տվյալների բազայում, այլ սկզբնական սահմանաբանման հարցում:
…the rows are first sorted according to the and then limited by dropping the number of rows specified in the from the beginning…
-SQL:2016, Part 2, 4.15.3 Derived tables (շնորհակալություն.` ներկայումս ամենաուղղակի ստանդարտ)
Այստեղ ամեն բան հիմնական բանը ` այս offset-ը ընդունում է միայն մեկ պարամետր - բաց թողնելու գրառումների քանակը, և այդ բոլորը: Այսպիսի սահմանման հետևելով, տվյալների բազան կարող է միայն գրեթե բոլոր գրառումները ստանալ, իսկ հետո թափել անհարկի: Օ évident, որ նման սահմանումը offset-ի աշխատանքը ստիպում է լրացուցիչ աշխատանք կատարել: Եւ այստեղ նույնիսկ կարեւոր չէ, թե դա SQL է, թե NoSQL:
Մի քիչ ցավ
Offset-ի խնդիրները այստեղ չեն ավարտվում, և ահա թե ինչ կարող է լինել: Եթե գերդաստի երկու էջերով տվյալները ընթերցելով մեկը մյուսի կողքին, մի ուրիշ գործողություն նոր գրառում է ներարկում, ինչ է կատարվում այս դեպքում:

Երբ օգտագործվում է offset՝ թողնելով նախորդ էջերի գրառումները, նոր գրառման միացումից հետո տարբեր էջերի ընթերցման գործողություններով, ամենայն հավանականությամբ, դուք կստանաք կրկնություն (իչ.` սա հնարավոր է, երբ մենք կարդում ենք էջերով` օգտագործելով դասավորության կառուցվածք, այսպես մենք կարող ենք ներգրավվել նոր գրառումը وسطում մեր պարզ կգարծակից):
Պատկերը ակնառապես ցույց է տալիս նման իրավիճակ: Database-ն ընթերցում է առաջին 10 գրառումներն, որից հետո ավելանում է նոր գրառում, որը տեղաշարժում է բոլոր ընթերցված գրառումները 1-ով: Այնուհետև database-ն վերցնում է նոր էջ 10 հաջորդ գրառումներից և սկսում չի 11-րդ, ինչպես պետք է, այլ 10-րդ, կրկնելով այդ գրառումը: Մյուս anomalies նույնպես առկա են այս արտահայտության օգտագործման հետ կապված, բայց այսը ամենատարածվածն է:
Ինչպես արդեն պարզեցինք, դա կոնկրետ DBMS-ների կամ նրանց միավորումների խնդիր չէ: Problema-ն SQL նորմով pagination-ի սահմանման մեջ է: Մենք ասում ենք DBMS-ին, թե որ էջը պետք է վերցնի կամ քանի գրառում պետք է թեքի: Database-ն պարզապես չունի բավարար տեղեկատվություն այդ հարցման օպտիմիզման համար:
Ավելի լավ է հստակեցնել, որ սա կոնկրետ բանալու խնդիր չէ, այլ ավելի շուտ հարցման իմաստը: Վերջում գոյություն ունեն մի շարք նույնական խնդրահարույց սինտաքսիսներ:
- Հիմնական բանալին offset, ինչպես արդեն նշվել է:
- Երկու բանալիի կառուցվածք limit [offset] (մյուս կողմից limit-ը այնքան էլ վատ չէ):
- Մինիմալ սահմաններով ֆիլտրացում, հիմնված գծագրային թվերի վրա (օրինակ ՝ row_number(), rownum և այլն):
Այս բոլոր արտահայտությունները պարզապես ասում են, թե քանի տող պետք է բաց թողնեք, ոչ մի լրացուցիչ տեղեկատվություն կամ համատեքստ:
Մանրամասների համար այս հոդվածում offset բանալին օգտագործվում է բոլոր այս տարբերակների ընդլայնման համար:
Ծանոթությունների կյանք OFFSET-ի առանց:
Եկեք պատկերացնենք, թե ինչպիսին կլիներ մեր աշխարհը այս բոլոր խնդիրների բացակայության պարագայում: Գիտեք, OFFSET-ի absence-ը այնքան բարդ չէ. SELECT-ով կարող եք ընտրել միայն այն տողերը, որ մենք դեռ չենք տեսել (նշում՝ որոնք չեն եղել նախորդ էջում), կիրառելով պայման WHERE-ում:
Այս դեպքում մենք քաշվում ենք այդ փաստից, որ SELECT-ները իրականացվում են կազմակերպված բազմության վրա (հին լավ order by): Ռեկորդը կազմակերպված բազմության առկայության դեպքում, մենք կարող ենք օգտագործել բավականին պարզ ֆիլտր՝ դուրս բերելու միայն այն տվյալները, որոնք գտնվում են նախորդ էջի վերջին գրառման հետևում:
SELECT ...
FROM ...
WHERE ...
AND id < ?last_seen_id
ORDER BY id DESC
FETCH FIRST 10 ROWS ONLYՍա ամբողջ սկզբունքն է նման մոտեցման: Իհարկե, բազմաբառեցման դեպքում ամեն բան ավելի ուրախ է, բայց գաղափարը նույնն է: Կարևոր է նշել, որ այս կառուցվածքը կիրառելի է բազմաթիվ -լուծումների:
Այս մոտեցումը կոչվում է seek method կամ keyset pagination: Դա լուծում է լողացող արդյունքների խնդիրը (նշում.՝ տողերի միջեւ գրանցման իրավիճակը, որը նկարագրվել է վերևում) և, իհարկե, մենք բոլորս սիրում ենք, աշխատում է արագ և կայուն, քան դասական offset-ը: Կայունությունը տեղի է տալիս նրան, որ հարցման մշակման ժամանակը չի մեծանում պահանջվող աղյուսակի համար (նշում.՝ եթե ցանկանում եք ավելի մանրամասն տեղեկություն ստանալ տարբեր pagination մոտեցումների մասին, կարող եք Այ那里 կարող եք գտնել տարբեր մեթոդների փոխեմատական բենչմարկներ:
Մեկ սլայդ , որ բանալիներով էջավերադարձը, իհարկե, ամենաուսումնասիրված չէ՝ այն ունի իր սահմանափակումները։ Ամենակարևորը՝ այն չի կարող կարդալ պատահական էջեր (նշում՝ անկապ շարունակականությամբ)։ Այնուամենայնիվ, հավերժական սկրոլինգի դարաշրջանում (նշում՝ ճակատում) դա այնքան էլ խնդրում չի։ Էջի համար համարի նշումը սեղմելու համար՝ ամեն դեպքում վատ լուծում է UI դիզայնում (նշում՝ հոդվածի հեղինակին է պատկանում կարծիքը)
Ի՞նչ գործիքների մասին է խոսքը։
Բանալիներով էջավերադարձը հաճախ չի համապատասխանում գործիքների առկա աջակցության պատճառով։ Շատ լուսաբաշխման գործիքներ, այդ թվում՝ տարբեր շրջանակներ, չեն տրամադրում ընտրություն, թե ինչպիսի կերպով կկատարի էջավերադարձը։
ԻSituationu worsens that the described method requires end-to-end support in the technologies used – starting from the RDBMS and ending with AJAX-request execution in the browser during infinite scrolling. Instead of specifying just a page number, now it will be necessary to indicate a set of keys for all pages at once.
Այնուամենայնիվ, բանալիներով էջավերադարձը աջակցող շրջանակների քանակը աստիճանաբար աճում է։ Րաաի կառուցվածքը չունի այժմ։
- Java-ի համար;
- Ruby- ի համար;
- և Django- ի համար;
- Python- ի համար;
- — գրանցման API JPA- դյուրակիրների համար;
- Perl- ի համար;
- , мапер для Node.js .
(Նշում՝ որոշ հղումներ ծառայում են, քանի որ թարգմանության պահին որոշ գրադարաններ 2017–2018 թվականներից հետո ապակողմ կառանձնացան: Եթե հետաքրքրում է, քաղաքիան սույն աղբյան մեջ։)
Բանտում հենց այս պահին պահանջում եմ ձեր օգնությունը։ Եթե դուք դիզայներ եք կամ աջակցում եք որևէ շրջանակ, որը ինչ-որ կերպ օգտագործում է էջավերադարձը, խնդրում եմ, կոչ եմ անում, խնդրում եմ՝ կազմակերպել բնորոշ աջակցության համար բանալիներով էջավերադարձի համար։ Եթե հարցեր կամ օգնություն կարող է պահանջվել, բավական ուրախ կլինեմ օգնել (, , ) (նշում՝ իմ փորձից Մարկուսի հետ կարող եմ ասել, որ նա իսկապես ոգեւորությամբ է վերաբերվում այս թեմայի տարածմանը)
Եթե դուք օգտագործում եք պատրաստի լուծումներ, որոնք, ըստ ձեր կարծիքի, արժանի են ունենալ բանալիներով էջավերադարձի աջակցության, — ստեղծեք պահանջ կամ նույնիսկ առաջարկեք պատրաստի լուծում, եթե դա հնարավոր է։ Կարող եք նաև նշում անել նշված հոդվածի հղման մեջ։
Ավարտ
Պատճառը, որ այսքան պարզ ու օգտակար մոտեցումը, ինչպիսին է բանալիներով էջավերադարձը, քիչ տարածված է, այն չէ, որ այն տեխնիկական իրականացման մեջ բարդ է կամ պահանջում է որևէ մեծ ջանքեր։ Ուրիշ պատճառ, որ շատերը նախընտրում են տեսնել և աշխատել offset- ով — այդ մոտեցումը պարտադրվում է հենց ստանդարտի կողմից։
Արդյունքում, քիչ մարդիկ մտածում են էջավերադարձի մոտեցման փոփոխության վրա, և դրան մեծացնում է, որ շրջանակների և գրադարանների առկա աջակցության զարգացումը թույլ է։ Այդ պատճառով, եթե ձեզ մոտ է անվճար էջավերադարձի գաղափարը և նպատակն է, — օգնում ենք տարածել այն!
Ընտանիք:
Հեղինակ: Markus Winand
Ընտանիք: habr.com
