Բարև, Հաբր! Ջենեցի ձեր ուշադրությանը հոդվածի թարգմանությունը
.
Երբ խոսքը վերաբերում է համակարգված տվյալների բազաներին, ես անհնար է չմտածեմ, որ ինչ-որ բան պակասում է: Դրանք օգտագործվում են ամենուր: Կան բազմաթիվ տարբեր տվյալների բազաներ՝ փոքր և օգտակար SQLite-ից մինչև հզոր Teradata: Բայց միայն մի քանիսը հոդվածներ կան, որոնք բացատրում են, թե ինչպես է գործում տվյալների բազան: Դուք կարող եք ինքներդ փնտրել запросով "howdoesarelationaldatabasework"՝ տեսնելու համար, թե որքան քիչ արդյունքներ կան: Բացի այդ, այդ հոդվածները՝ կարճ են: Եթե էլ փնտրում եք վերջին նորաձև տեխնոլոգիաներ (BigData, NoSQL կամ JavaScript), դուք կգտնեք ավելի խորը հոդվածներ, որոնք բացատրում են, թե ինչպես են դրանք աշխատում։
Համակարգված տվյալների բազաները արդյոք չափազանց հնում են և չափազանց չափազանցներ, որպեսզի բացատրեն համալսարանի դասախոսությունների, հետազոտական աշխատանքների և գրքերի սահմաններից դուրս։

Որպես ծրագրավորող, ես ատում եմ օգտագործել այն, ինչ չեմ հասկանում: Եվ եթե տվյալների բազաները օգտագործվում են ավելի քան 40 տարի, դրա համար պետք է լինեն պատճառներ: Այդ տարիների ընթացքում ես ծախսել եմ հարյուրավոր ժամեր, որպեսզի իսկապես հասկանամ այդ տարօրինակ սև լուցկիները, որոնք օգտագործում եմ ամեն օր։ Համակարգված տվյալների բազաներ ամենաշատ հետաքրքիր են, որովհետև դրանք հիմնված են օգտակար և բազմակի օգտագործվող կոնցեպցիաների վրա. Եթե ձեզ հետաքրքրում է տվյալների բազայի ըմբռնումը, բայց երբեք չեք ունեցել ժամանակ կամ ցանկություն այս լայն թեման ուսումնասիրելու, ապա ձեզ պետք է խորշում այս հոդվածը։
Չնայած այս հոդվածի վերնագիրը ինքորոշիչ է, այս հոդվածի նպատակը տվյալների բազայի օգտագործումը հասկանալ չի։Այսպիսով, դուք արդեն պետք է իմանաք, ինչպես գրել պարզ միացություն և հիմնարար запросներ CRUD; հակառակ դեպքում, դուք կարող եք չհասկանալ այս հոդվածը։ Սա միակ բանն է, որը պետք է իմանաք, ես կբացատրեմ մնացածը։
Ես կսկսեմ որոշ հիմունքներից՝ մաթեմատիկական առարկաները, ինչպիսիք են ալգորիթմների ժամանակային բարդությունը (BigO): Ես գիտեմ, որ որոշ մարդկանց դա ատելի է, բայց առանց դրա դուք չեք կարող հասկանալ տվյալների բազայի ներսում տեղի ունեցող նրբությունները։ Քանի որ սա լայն թեմա է, ես կկենտրոնանամ այն բանի վրա, ինչը ես գտնում եմ կարևոր: ինչպես տվյալների բազան մշակել է SQL запрос. Ես կներկայացնեմ միայն հիմնական տվյալների բազայի կոնցեպցիաները, որպեսզի հոդվածի վերջում դուք հասկանաք, թե ինչ է տեղի ունենում մեքենայի տակ։
Քանի որ սա երկար և տեխնիկական հոդված է, որը ներառում է բազմաթիվ ալգորիթմներ և տվյալների կառուցվածքներ, մի շտապեք այն կարդալ: Որոշ կոնցեպցիաներ կարող են դժվար լինել ըմբռնելու համար; դուք կարող եք դրանք բաց թողնել և որոշակի պատկերացում ունենալ՝ ընդհանուր իմանալու համար։
Մանրամասներին ծանոթ այն մարդկանց համար, այս հոդվածը բաժանվում է 3 մասի՝
- Տվյալների բազայի ցածր մակարդակի և բարձր մակարդակի բաղադրիչների վերանայումը
- Запросների օպտիմիզացման գործընթացի վերանայումը
- Տեղեկատվական գործառնությունների և բուֆերային պուլների կառավարման վերանայումը
Վերադառնալով հիմունքներին
Անդհար ծովին ինչպես մի երկար ժամանակ առաջ (մի հեռավոր, հեռավոր համաստեղության մեջ…), մշակողներին պետք էր ճշգրտորեն իմանալ, թե որքան գործողություն են կոդավորում: Նրանք առանձին իմացել էին իրենց ալգորիթմները և տվյալների կառուցվածքները, քանի որ չէին կարող թույլ տալ վերացնել կենտրոնական գործընթացը և իրենց սխալ համակարգչային հիշողությունը:
Այս հատվածում ես ձեզ կպատմեմ որոշակի այս գաղափարների մասին, քանի որ դրանք անհրաժեշտ են տվյալների բազայի հասկանալու համար: Ես նաև ներդրելու եմ հասկացությունը դիտարկման տվյալների բազայից.
O(1) մարտի վրա O(n2)
Այժմ շատ մշակողներ չեն հոգարում ալգորիթմների ժամանակին բարդության մասին ... և նրանք իրավացի են!
Բայց երբ դուք աշխատում եք շատ տվյալների հետ (ես չեմ խոսում հազարների մասին), կամ երբ դուք պայքարում եք մահճակալների համար, շատ կարևոր է հասկանալ այս գաղափարը: Եվ ինչպես դուք գիտեք, տվյալների բազաները պետք է ունենալ գործ սխալ ու վիճակ գործը!: Ես ձեզ ստիպել չեմ, որ ավելորդ ժամանակ ծախսեք, քան անհրաժեշտ է իր էությունը հավաքելու համար: Սա մեզ կօգնի հետագայում հասկանալ ծախսերի վրա հիմնված օպտիմիզացիայի հասկացությունը (ծախս հիմնված օպտիմիզացիա).
Конցեպցիան
Ալգորիթմի ժամանակային բարդությունը օգտագործվում է տեսնելու, թե որքան ժամանակ է ծախսելու ալգորիթմն տվյալ տվյալների քանակի համար. Այս բարդությունը նկարագրելու համար օգտագործվում են մեծ O-ի մաթեմատիկական նշումները: այս նոտացիան օգտագործվում է ֆունկցիայով, որը նկարագրում է, թե քանի գործողություն է անհրաժեշտ ալգորիթմին որոշ տվյալների մուտքերի համար:
Օրինակ, երբ ես ասում եմ "այս ալգորիթմը ունի O (some_function() ) բարդությունը", դա նշանակում է, որ որոշակի տվյալների համար ալգորիթմը պահանջում է some_function(a_certain_amount_of_data) գործողություններ:
Այս դեպքում կարևոր չէ տվյալների քանակը, այլ թե ինչպես ով վերածվում է գործողությունների քանակը տվյալների քանակի աճով. Ժամանակային բարդությունը չի տալիս գործողությունների ճիշտ քանակ, սակայն լավ միջոց է իրականացման ժամանակի գնահատման համար:

Այս գծապատկերը դուք կարող եք տեսնել գործողությունների քանակի և մուտքային տվյալների քանակի հարաբերությունը տարբեր տեսակի ժամանակային բարդությունների ալգորիթմների համար: Ես օգտագործել եմ մարմաուման սկալի, որպեսզի պատկերեմ դրանք: Նշանակում է, որ տվյալների քանակը արագ աճում է 1-ից մինչև 1 միլիարդ: Մենք կարող ենք տեսնել, որ:
- O(1) կամ մշտական բարդություն մնում է անընդհատ (այլապես դա չի կոչվելու մշտական բարդություն):
- O(log(n)) մնում է ցածր անգամ միլիարդնոր տվյալներ.
- Ամենաընթանումբարդությունը՝ O(n2), որտեղ գործողությունների քանակը արագ մեծանում է.
- Երկու մյուս բարդությունները նույնպես արագ աճում են:
Օրինակներ
Փոքր տվյալների քանակի դեպքում O(1) և O(n2) միջև տարբերությունը չնչին է: Օրինակ, ենթադրենք, որ ունեք ալգորիթմ, որը պետք է մշակել 2000 տարրեր:
- O (1) ալգորիթմը ձեզ կարժենա 1 գործողություն
- O (log (n)) ալգորիթմը ձեզ կարժենա 7 գործողություն
- O (n) ալգորիթմը ձեզ կարժենա 2000 գործողություն
- O (n * log (n)) ալգորիթմը ձեզ կարժենա 14 000 գործողություն
- O (n2) ալգորիթմը ձեզ կարժենա 4 000 000 գործողություն
O(1) և O(n2) միջև տարբերությունը թվում է մեծ (4 միլիոն գործողություն), բայց դուք կկորցնեք առավելագույնը 2 մ.թ., պարզապես աչքերը փորփրելու ժամանակ։ Իրականում, ժամանակակից պրոցեսորները կարող են մշակում կատարել ։ Ահա ինչու կատարողականությունն ու օպտիմիզացումը բազմաթիվ ԻՏ նախագծերում աննշում չեն։
Ինչպես ես արդեն ասել եմ, դեռ կարևոր է գիտակցել այս հասկացությունը, աշխատելիս մեծ քանակությամբ տվյալների հետ։ Եթե այս անգամ ալգորիթմը պետք է մշակել 1,000,000 տարր (ինչը այնքան էլ շատ չէ տվյալների բազայի համար):
- O (1) ալգորիթմը ձեզ կարժենա 1 գործողություն
- O (log (n)) ալգորիթմը ձեզ կարժեցնի 14 գործողություն
- O (n) ալգորիթմը ձեզ կարժեցնի 1,000,000 գործողություն
- O (n * log (n)) ալգորիթմը ձեզ կարժեցնի 14,000,000 գործողություն
- O (n2) ալգորիթմը ձեզ կարժեցնի 1,000,000,000,000 գործողություն
Ես հաշվարկներ չեմ կատարել, բայց կասեմ, որ O (n2) ալգորիթմով դուք կունենաք ժամանակ սուրճ խմել (բ nawet երկու անգամ!)։ Եթե դուք ավելացնեք մեկ 0 տվյալների ծավալին, կունենաք ժամանակ քնելու ժամանակ։
Գտնվենք խորքում
ՀREFERENCE նորերս՝
- Լավ հեշ-թաբլում որոնումը գտնում է տարրը O (1) ժամանակահատվածում։
- Լավ բալանսավորված ծառում որոնումը կատարվում է O (log (n)) ժամանակահատվածում։
- Ամրագրում որոնումը կատարվում է O (n) ժամանակահատվածում։
- Լավագույն դասակարգման ալգորիթմները ունեն O (n * log (n)) բարդություն։
- Ախորժակային դասակարգման ալգորիթմը ունի O (n2) բարդություն։
Նշում՝ հաջորդ մասերում մենք կտեսնենք այս ալգորիթմներն ու տվյալների կառուցվածքները։
Կան մի քանի ժամանակային բարդության ալգորիթմի տեսակներ՝
- միջին դեպքերի սցենար
- լավագույն դեպքի տարբերակ
- և վատագույն սցենար
Ժամանակային բարդությունը հաճախ վատագույն սցենարն է։
Ես խոսեցի միայն ալգորիթմի ժամանակային բարդության մասին, բայց բարդությունը նաև վերաբերվում է՝
- ալգորիթմի հիշողության սպառմանը
- ալգորիթմի սկավառակային մուտք/հետադարձ մուտքին
Իհարկե, կան ավելի վատ բարդություններ, քան n2, օրինակ՝
- n4: դա ահավոր է! Որոշ նշված ալգորիթմներ ունեն այսպիսի բարդություն։
- 3n: դա դեռ էլ ավելի վատ է! Հիմնականում մենք այդ ալգորիթմներից մեկը տեսնելու ենք այս հատվածի մեջ (և այն իսկապես օգտագործվում է բազմաթիվ տվյալների բազաներում):
- ֆակտորական n: դուք երբեք չեք ստանա ձեր արդյունքները նույնիսկ փոքր թվերով։
- nn: եթե դուք հանդիպում եք այդ բարդությանը, պետք է հարցնեք ինքներդ ձեզ, արդյոք սա իսկապես ձեր bereik է…
Նշում՝ ես ձեզ տվեցի ոչ իրական սահմանում «մեծ O» նշանադրության, այլ պարզապես գաղափար։ Դուք կարող եք կարդալ այս հոդվածը մեջ իրական (ասիմպտոտիկ) սահմանման համար։
MergeSort (Միացումի դասակարգում)
Ինչ եք անում, երբ ձեզ պետք է դասակարգել հավաքածու։ Ինչ? Դուք զանգում եք sort() ֆունկցիան… լա՛վ, լավ պատասխան… Բայց տվյալների բազայի համար դուք պետք է հասկանալ, թե ինչպես է աշխատում այդ sort() ֆունկցիան։
Կա մի քանի լավ դասակարգման ալգորիթմներ, այնպես որ ես կկենտրոնանամ ամենակարևորին՝ միացումի դասակարգմանըԲայց դուք այժմ չեք հասկանում, թե ինչու է տվյալների սորտավորումը օգտակար, սակայն պետք է հասկանաք, երբ հասկանաք հարցերի օպտիմացման մասին։ Բացի այդ, միաձուլման սորտավորման հասկացությունը կօգնի մեզ ավելի ուշ հասկանալ ընդհանուր join օպերացիան, որն իրականացնում են տվյալների բազաները: merge join (միավորում՝ միաձուլմամբ).
Merge (միավորում)
Ինչպես շատ օգտակար ալգորիթմներ, միաձուլման սորտավորումը հիմնված է հնարքի վրա։ 2 դասավորված N/2 չափի զանգվածների միավորումը N-էլեմենտ դրանդասավորված զանգված ունենալու համար պահանջում է всего N գործողություն։ Այս գործողությունը կոչվում է միավորում։
Եկեք տեսնենք, թե ինչ է դա նշանակում պարզ օրինակով։

Այս նկարում երևում է, որ 8 ձևավորում ունեցող ծայրահեղ դասավորված զանգված ստեղծելու համար անհրաժեշտ է միայն մեկ անգամ անցնել 2 4-էլեմենտի զանգվածների միջոցով։ Քանի որ երկու 4-էլեմենտային զանգվածները արդեն դասավորված են.
- 1) դուք համեմատում եք երկու զանգվածների текущим էլեմենտները (սկզբում текущий = առաջինին)
- 2) հետո վերցնում եք փոքրագույնը, որպեսզի տեղադրեք այն 8-էլեմենտի զանգվածում
- 3) և անցնում եք հաջորդ էլեմենտին զանգվածում, որտեղ վերցրել եք ամենափոքր էլեմենտը
- և կրկնում եք 1, 2, 3 մինչև հասնեք մեկ զանգվածներից մեկի վերջին էլեմենտին։
- Հետո դուք վերցնում եք մյուս զանգվածից մնացած էլեմենտները, որպեսզի տեղադրեք դրանք 8-էլեմենտի զանգվածում։
Դա գործում է, որովհետև երկու 4-էլեմենտի զանգվածները դասավորված են, և հետևաբար ձեզ անհրաժեշտ չէ «վերադառնալ» այդ զանգվածներում։
Այժմ, երբ մենք հասկացանք այս հնարքը, ահա իմ հնարովի կոդը merge-ի համար։
array mergeSort(array a)
if(length(a)==1)
return a[0];
end if
//recursive calls
[left_array right_array] := split_into_2_equally_sized_arrays(a);
array new_left_array := mergeSort(left_array);
array new_right_array := mergeSort(right_array);
//merging the 2 small ordered arrays into a big one
array result := merge(new_left_array,new_right_array);
return result;Միաձուլման սորտավորումը կրճատում է խնդիրը փոքր խնդիրների, ապա գտնում է փոքր խնդիրների արդյունքները, որպեսզի ստանա ելքի արդյունքը (նկատի ունեմ, որ այս տեսակի ալգորիթմները կոչվում են բաժանմունք և իշխանություն)։ Եթե դուք չեք հասկանում այս ալգորիթմը, մի անհանգստացեք։ Ես առաջին անգամ տեսնելով դա չեմ հասկացել։ Եթե սա կարող է ձեզ օգնել, ես տեսնում եմ այս ալգորիթմը որպես երկու փուլային ալգորիթմ։
- Բաժանման փուլը, որտեղ զանգվածը բաժանվում է փոքր զանգվածների
- Սորտավորման փուլը, որտեղ փոքր զանգվածները միանում են (օգտագործելով միավորում), որպեսզի ձևավորեն ավելի մեծ զանգված։
Division phase (բաժանման փուլ)

Բաժանման փուլում զանգվածը բաժանվում է մեկ երկրի զանգվածների 3 քայլով։ Формальное количество шагов — log(N) (քանի որ N=8, log(N) = 3):
Որտեղից գիտեմ այս մասին։
Ես շնորհալի եմ! Մի խոսքով՝ մաթեմատիկա։ Ելք կա առ այն, որ յուրաքանչյուր քայլ բաժանում է սկզբնական զանգվածի չափը 2։ Քայլերի քանակը՝ դա այն քանակն է, որը դուք կարող եք բաժանել սկզբնական զանգվածը երկուսում։ Սա է ճիշտ սահմանումը ռ Logarithm-ի (2 հիմքով):
Sorting phase (սորտավորման փուլ)

Անհատական (միաելեմենտային) զանգվածներով սկսում եք դասակարգման փուլում: Ամեն փուլում դուք մի քանի միավորումներ եք կիրառում, և ընդհանուր արժեքը կազմում է N = 8 գործողություն:
- Առաջին փուլում ունեք 4 միավորում, որոնք արժեն 2 գործողություն յուրաքանչյուր:
- Երկրորդ քայլում ունեք 2 միավորում, որոնք արժեն 4 գործողություն յուրաքանչյուր:
- Երրորդ քայլում ունեք 1 միավորում, որը արժե 8 գործողություն:
Որպեսզի լինի log (N) քայլեր, ընդհանուր արժեքը N * log(N) գործողություն.
Միավորման կարգավորումների առավելությունները
Ինչու է այս ալգորիթմը այդքան ուժեղ?
Որովհետև:
- Դուք կարող եք փոփոխել այն, որպեսզի նվազեցնեք հիշողության ծավալը՝ այդպիսով նոր զանգվածներ չստեղծելով, այլ անմիջապես փոփոխելով մուտքային զանգվածը:
Նշում՝ այս տեսակի ալգորիթմները կոչվում են (միաժամանակյա հիշողության առանց հավելյալ հիշողության):
- Դուք կարող եք փոփոխել այն՝ օգտագործելով դիսկի տարածություն և նվազագույն հիշողություն՝ առանց նշանակալի ծախսերի դիսկի մուտք/արտահանումում: Ինքնաբառը թույլ է տալիս միայն այն մասերն, որոնք ներկայումս մշակում եք, բեռնել հիշողություն: Սա կարևոր է, երբ պետք է դասակարգեք Several գիգաբայթանոց աղյուսակը, միայն 100 մեգաբայթ հիշողության բուֆերով:
Նշում՝ այս տեսակի ալգորիթմները կոչվում են .
- Դուք կարող եք փոփոխել այն՝ միաժամանակյա գործընթացների/թափանցիկների/ծառաների վրա աշխատելու համար:
Օրինակ, տարածված միավորման դասակարգումը հանդիսանում է հիմնական բաղադրիչներից մեկը (որը մեծ տվյալների կառուցավարում է):
- Այս ալգորիթմը կարող է պղինձը ոսկի դարձնել (այո, ճիշտ է!).
Այս դասակարգման ալգորիթմը օգտագործվում է մեծ մասում (եթե ոչ բոլորում) տվյալների բազաներում, բայց դա միայն միակը չէ: Եթե ցանկանում եք ավելին իմանալ, կարող եք կարդալ այս , որը քննարկում է տվյալների բազաներում սովորական դասակարգման ալգորիթմների կողմերն ու հակառակ կողմերը:
Զանգված, Ծառ և Հաշվողական-աթղթաբաժին
Այժմ, երբ հասկանում ենք ժամանակի բարդության և դասակարգման գաղափարը, պետք է ձեզ պատմեմ 3 տվյալների կառուցվածքների մասին: Սա կարևոր է, որովհետև նրանք ներդրումներ են արդարացված ժամանակակից տվյալների բազաների համար:. Ես նաև կներդեմ հասկացություն դիտարկման տվյալների բազայից.
Զանգված
Երկրորդական զանգվածը ամենադյուրին տվյալների կառուցվածքն է: Աղյուսակը կարելի է դիտել, որպես զանգված: Օրինակ:

Այս 2-վերադարձային զանգվածը ներկայացնում է աղյուսակ տողերով և շարքերով:
- Երկարությունը ներկայացնում է բնույթը
- Շարքերը պահում են բնույթի նկարագրող հատկությունները:
- Յուրաքանչյուր շարք պահում է որոշակի սեռի տվյալներ (integer, string, date ...):
Այ如此 удобно хранить и визуализировать данные однако, когда вам нужно найти определенное значение, это не подходит.
Օրինակ, եթե ցանկանում եք գտնել բոլոր տղաներին, որոնք աշխատում են Մեծ Բրիտանիայում, ձեզ հարկավոր է անցնել յուրաքանչյուր տող, որպեսզի որոշեք, արդյոք այս տողը պատկանում է Մեծ Բրիտանիային: Այս հարցումն արժե ձեզ N գործողություն, где N — տողերի քանակը բավականին մեծ է, բայց կա՞ ավելի արագ տարբերակ: Վերջապես, ժամանակ է ծանոթանալու ծառերին։
Փսկայիր՝ արդի տվյալների բազաները մեծամասամբ առաջարկում են ընդլայնված զանգվածներ՝ արդյունավետ աղյուսակներ պահելու համար՝ heap-organized tables և index-organized tables։ Բայց դա չի փոխի խնդիրը՝ արագ որոնելու որոշակի պայմաններ մի շարք սյուներում։
Ծառ և տվյալների բազայի ինդեքս
Երկրաչափական ծառը որոնման երկիր է, որն ունի հատուկ հատկություն՝ յուրաքանչյուր հանգույցի բանալին պետք է լինել՝
- բոլոր բանալիներից ավելի մեծ, որոնք պահվում են ձախ մյուս ծառում
- բոլոր բանալիներից փոքր, որոնք պահվում են աջ մյուս ծառում
Չենք հիմա տեսնենք, թե դա ինչ է նշանակում տեսողականորեն
Ուղղություն

Այս ծառն ունի N = 15 տարր։ Թող ընդունենք, որ ես փնտրում եմ 208։
- Ես սկսում եմ արմատից, որի բանալին 136 է։ Քանի որ 136 < 208, ես գնում եմ 136-ի աջ ծառը։
- 398 > 208, հետևաբար, ես գնում եմ 398-ի ձախ ծառը
- 250 > 208, հետևաբար, ես գնում եմ 250-ի ձախ ծառը
- 200 < 208, հետևաբար, ես գնում եմ 200-ի աջ ծառը։ Բայց 200-ը չունի աջ ծառ, valued չկ կարելի է գտնել (քանի որ եթե այն գոյություն ունենար, այն կլինի 200-ի աջ ծառում)։
Այժմ, ասենք, ես փնտրում եմ 40
- Ես սկսում եմ արմատից, որի բանալին 136 է։ Քանի որ 136 > 40, ես գնում եմ 136-ի ձախ ծառը։
- 80 > 40, հետևաբար, ես գնում եմ 80-ի ձախ ծառը
- 40= 40, անգամից գոյություն ունեմ։. Ես դուրս են բերում պտույտի նույնականացնողը ներսում հանգույցը (այն չի երևում նկարում) և նայում եմ տվյալների բազայում այդ նույնականացնողի համար։
- Մտավոր ազդանշանն, որը ես ունեմ, թույլ է տալիս ինձ հասկանալ, որտեղ տվյալները գտնվում են աղյուսակում, և ուստի կարող եմ ստանալ դրանք անմիջապես։
Ի վերջո, երկու որոնումները ինձ կանեն ծառի բարդություններ։ Եթե դուք ուշադիր կարդաք միաձուլման մասին, դուք պետք է տեսնեք, որ այստեղ log(N) մակարդակներ են։ Ի վերջո, կոնտրոլը որոնման log(N), լավ է, չէ՞!
Վերադառնանք մեր խնդրին
Բայց դա շատ աբստրակտ է, ուստի եկեք վերադառնանք մեր խնդրին։ Յուրաքանչյուր պարզ integer-ի փոխարեն պատկերացրեք մի գիծ, որը ներկայացնում է ինչ-որ երկրի անունը նախորդ աղյուսակում։ Ուրեմն, ունեք ծառ, որը պարունակում է "country" (սյուն 3)՝ աղյուսակում։
- Եթե ուզում եք իմանալ, թե ով է աշխատում Մեծ Բրիտանիայում
- Դուք նայում եք ծառին, որպեսզի ստանաք հանգույց, որը ներկայացնում է Մեծ Բրիտանիան
- մեջ "UKnode" դուք կգտնեք տեղեկությունների գտնվելու վայրերը Մեծ Բրիտանիայում աշխատողների։
Այս որոնումը կարժենա log(N) գործողություններ փոխարեն N գործողությունների, եթե դուք ուղիղ օգտագործեք զանգվածը։ Այդ բան, որը դուք հենց նոր ներկայացնում եք, պարզապես տվյալների բազայի ինդեքս.
Դուք կարող եք կառուցել ինդեքսային ծառ ցանկացած դաշտերի խմբի՝ (տող, թիվ, 2 տող, թիվ և տող, ամսաթիվ...) այնքան ժամանակ, մինչև ունեք բանալիների համեմատության ֆունկցիա (այսինքն, դաշտերի խումբ), որպեսզի կարողանաք հաստատել բանակը բանալիների միջև (ինչը տեղի է ունենում ցանկացած հիմնական տիպի համար տվյալների բազայում):
B+TreeIndex
Չնայած այս ծառը լավ է գործում որոշակի արժեք ձեռք բերելու համար, կա ՄՏՈՒ ՆԱԽԱԳԾՈՒ եղանակ ընտրելու մեծ խնդիրը։ որպեսզի ստանաք մի քանի տարրեր երկու արժեքների միջև.. Սա կարժենա O(N), քանի որ պետք է ստուգել յուրաքանչյուր հանգույցի վրա և տեսնել, թե արդյոք այն այդ երկու արժեքների միջև է (օրինակ, ծառիOrdered обходի միջոցով): Նմանապես, այս գործողությունը հեշտ չէ սկավառակի մուտքի-գործողության համար, քանի որ պետք է կարդալ սալիկների ամբողջը: Թողնենք ուղին պահպանելով հարմար ձև կատարել. տարածության հարց.. Այդ խնդրի լուծման համար ժամանակակից տվյալների բազաները օգտագործում են նախորդ ծառի փոխված տարբերակը, որը կոչվում է B+Tree: B+Tree-ի ծառում՝
- միայն ամենացածր հանգույցները (տերևները) պահպանված տեղեկատվություն է. (հոտերի գտնվելու վայրեր կապված սկումրջելու մեջ)
- մնացած հանգույցները այստեղ են ուղղորդելու համար ճիշտ հանգույցի մուտքի ժամանակ. Որպեսզի տեսանելի լինի, այստեղ հանգույցներ շատ են (երկուս անգամ): Իրապես ունեք լրացուցիչ հանգույցներ, «երկրապահ հետազոտության հանգույցներ», որոնք կօգնեն գտնել ճիշտ հանգույցը (որը պահում է հոտերի գտնվելու վայրերը): Բայց որոնման բարդությունը դեռ O(log(N)) է (նստեք միայն մեկ մակարդակի): Մեծ տարբերությունը կայանում է նրանում, որ.

նացել միմյանց հետ կապված հարևաններին. Այս B+Tree-ի կոմբինացիայով, եթե որոնում եք արժեքները 40-ից 100:.
Դուք պարզապես պետք է որոնեք 40-ը (կամ մոտակա արժեքը 40-ի, եթե 40-ը առկա չէ), ինչպես դա արել եք նախորդ ծառի հետ:
- Այնուհետև հավաքեք 40-ի ժառանգորդներին, օգտագործելով ուղղակի հղումներ ժառանգորդներին, մինչև հասնեք 100:
- Բանը, որ գտնվում է M ժառանգորդներ, և ծառ ունի N հանգույցներ: Իրական հանգույցը գտնելու արժեքը مشابه է նախորդ ծառին: Բայց, ստանալով այս հանգույցը, դուք ստանում եք M ժառանգորդներ M գործողություններով, հարմտենելով նրանց ժառանգությանը:
Այս որոնումը արժե միայն M+log(N) գործողություններ, իսկ նախորդ ծառի N գործողությունները: Ավելին, ձեզ չի անհրաժեշտ կարդալ ամբողջ ծառը (միայն M + log (N) հանգույցները), ինչը նշանակում է կամաց-կամաց օգտագործվող սկավառակ: Եթե M-ը քիչ է (օրինակ, 200 տող), իսկ N-ը մեծ (1,000,000 տող), սա կլինի ՄՏՈՒ մեծ տարբերություն: Բայց այստեղ նոր խնդիրներ կան (մի անգամ ևս!)։ Եթե դուք ավելացնում կամ հեռացնում եք տողն տվյալների բազայում (и, հետեւաբար, կապված B+Tree-ի փուլում):
պետք է պահպանեք կարգը B+Tree-ի հետ կապված նվազագույն փուլերի միջև, հակառակ դեպքում դուք չեք կարող գտնել հանգույցները դասի չբոլոր փոթորիկներում:
- պետք է պահպանել B+Tree-ում հնարավորինս քիչ մակարդակներ, հակառակ դեպքում ժամանակի բարդությունը O (log (N)) վերածվում է O (N):
- պետք է պահպանեք B+Tree-ում հնարավորինս քիչ մակարդակներ, այլապես O (log (N)) ժամանակային բարդությունը կդառնա O (N):
Անունի այլ խոսքով, B+Tree-ը պետք է ինքնուրույն դասավորված և հավասարակշռված լինի: Luckily, this is possible with smart insertion and deletion operations. But it comes at a cost: insertion and deletion in a B+ tree cost O(log(N)). This is why some of you have heard that մտածել չափից շատ ինդեքսներ ունենալը ոչ այնքան լավ գաղափար է:Իրոք, դուք դանդաղեցնում եք արագ մեկնում / թարմացում / հեռացում տիրույթից, քանի որ տվյալներ պետք է թարմացնել ինդեքսները թիմի համար ՝ յուրաքանչյուր ինդեքսի համար անհանգիստ O(log(N)) գործողության միջոցով: Բացի այդ, ինդեքսների ավելացումը նշանակում է ավելի մեծ բեռ տեղեկատվությունների կառավարիչի համար (քիչ առաջ կնկատվի հոդվածի վերջում):
Լրացուցիչ տեղեկությունների համար կարող եք դիտել Վիքի հոդվածը . Եթե ցանկանում եք B+Tree-ի կիրառում, նայեք և MySQL-ի առաջատար ծրագրավորողի կողմից: Նրանք երկուսն էլ կենտրոնանում են, թե ինչպես է InnoDB-ն (MySQL-ի շարժիչը) մշակել ինդեքսները:
Նշում. ընթերցողն ասաց, որ ցածր մակարդակի օպտիմիզացումների պատճառով B+Tree-ն ամբողջական է պետք լինել:
Hashtable (Հաշվողական աղյուսակ)
Մեր վերջին կարևոր տվյալների կառուցվածքը հաշվողական աղյուսակն է: Սա շատ օգտակար է, երբ ցանկանում եք արագ փնտրել արժեքներ: Բացի այդ, հաշվողական աղյուսակի հասկացությամբ մենք ավելի հեշտությամբ կհասկանալով մի ընդհանուր գործողություն базы данных կոչված, որը կոչվում է հաշվողական միացում ( hash join). Սա տվյալների կառուցվածքը նույնպես օգտագործում է база данных այլ ներքին բաներ պահելու համար (օրինակ, արգելափակման աղյուսակ կամ բուֆերային պուլ, մենք կտեսնենք երկուսը էլ ավելի ուշ):
Հաշվողական աղյուսակը տվյալների կառուցվածք է, որը արագ գտնում է տարրերը ըստ դրա բանալիի: Հաշվողական աղյուսակ կառուցելու համար պետք է որոշեք:
- վանկան ձեր տարրերի համար
- հաշվողական գործառույթ բանալիքներին: Հաշվարկված բանալիքների հեշերը տալիս են տարրերի դիրքը (դրանք կոչված են սեգմենտներ ).
- բանալիքի համեմատման ֆունկցիա: Երբ ճիշտ սեգմենտը գտնում եք, պետք է գտնել այն տարրը, որը դուք փնտրում եք սեգմենտի ներսում՝ օգտագործելով այս համեմատությունը:Արագ օրինակ
Եկեք վերցնենք շատ պարզ օրինակ:
Այս հաշվողական աղյուսակը ունի 10 սեգմենտ: Քանի որ ես ծույլ եմ, ես նկարել եմ միայն 5 սեգմենտ, բայց գիտեմ, որ դուք խելացի եք, հետևաբար թույլ եմ տալիս ձեզ պատկերացնել 5 այլ սեփական: Ես օգտագործել եմ բանալիի վրա 10 մոդուլի հաշվարկելիություն: Անվանել մյուս բառերով, ես պահում եմ բանալիի վերջին թվանիշը, որպեսզի գտնել սեգմենտը:

եթե վերջին թվանիշը համապատասխան է 0-ին, ապա տարրը ընկնում է 0 սեգմենտ:
- եթե վերջին թվանիշը համապատասխան է 1-ին, ապա տարրը ընկնում է 1 սեգմենտ:
- եթե վերջին թվանշանը համապատասխան է 2-ին, ապա տարրը ընկնում է սեգմենտ 2:
- Օգտագործած համեմատության ֆունկցիան պարզապես երկու целый чиселի նկատմամբ հավասարության է:
- …
Երբ ցանկանում եք դուրս բերել 78 տարրը:
Հաշվողական աղյուսակը հաշվարկում է 78-ի հեշ-կոդը, որը հավասար է 8:
- Հաշվետվության աղյուսակը հաշվում է 78-ի համար հեշ-կոդը, որն հավասար է 8:
- Հեշ-տեսանը նայում է 8 սեգմենտի, և առաջին տարրը, որը նա գտնում է, դա 78 է։
- Նա ձեզ վերադարձնում է 78 տարրը։
- Որոնումն արժե ընդամենը 2 գործողություն։ (մեկը հեշ-ֆունկցիայի արժեքը հաշվարկելու համար, և մյուսը սեգմենտում տարրը որոնելու համար):
Այժմ, կարծում են, որ ուզում եք ստանալ 59 տարրը՝
- Հեշ-տեսանը հաշվում է 59-ի հեշ-կոդը, որը հավասար է 9-ի։
- Հեշ-տեսանը որոնում է 9 սեգմենտում, առաջին գտնված տարրը՝ 99 է։ Թեև 99!=59, 99-ը ճիշտ տարր չէ։
- Այսzelfde տրամաբանությամբ, վերցվում է երկրորդ տարրը (9), երրորդ (79), …, վերջին (29):
- Տարրերը չեն գտնվել։
- Որոնումը արժեցավ 7 գործողություն։.
Լավ հեշ-ֆունկցիա։
Ինչպես տեսնում եք, կախված նրանից, թե ինչ արժեք եք որոնում, արժեքը չի նույնական։
Եթե այժմ փոխեմ հեշ-ֆունկցիան 1 000 000-ով գումարում վկայակոչելու համար (այսինքն՝ վերջին 6 թվերն առնելու համար), երկրորդ որոնումն արժեցած կլինի միայն 1 գործողություն, քանի որ 000059 սեգմենտում տարրեր չկան։ Ինքն օրակարգի խնդիրն է գտնել լավ հեշ-ֆունկցիա, որը կստեղծի սեգմենտներ, որոնք պարունակել են շատ քիչ տարրեր։.
Իմ օրինակով գտնել լավ հեշ-ֆունկցիա հեշտ է։ Բայց դա պարզ օրինակ է, լավ հեշ-ֆունկցիա գտնել ավելի դժվար է, երբ բանալի՝
- լար (օրինակ՝ ազգանուն),
- 2 լար (օրինակ՝ ազգանուն և անուն),
- 2 լար և ամսաթիվ (օրինակ՝ ազգանուն, անուն և ծննդյան ամսաթիվ)։
- …
Լավ հեշ-ֆունկցիայի դեպքում հեշ-տեսակում որոնումը արժի O(1)։.
Մասիվ vs հեշ-տեսակ։
Ինչու՞ չօգտագործել մասիվ։
Հմ, լավ հարց։
- Հեշ-տեսանը կարող է լինել մասնակի թվայնացված հիշողության մեջ,, մյուս սեգմենտները կարող են մնալ դիսկում։
- Մասիվի դեպքում դուք պետք է օգտագործեք հին տարածք հիշողության մեջ։ Եթե դուք լիցքավորում եք մեծ աղյուսակ, շատ դժվար է գտնել բավականաչափ հին տարածք։.
- Հեշ-տեսոցի համար դուք կարող եք ընտրել անհրաժեշտ բանալին (օրինակ՝ երկրի և մարդու ազգանունը):
Ավելին տեղեկություններ համար կարող եք կարդալ հոդվածը , որը արդյունավետ իրականացման հեշ-տեսակ է; ձեզ պետք չէ հասկանալ Java, որպեսզի հասկանաք այս հոդվածում ներկայացված գաղափարները։
Ընտանիք: habr.com
