Hur fungerar relationella databaser (Del 1)

Hej, Habr! Jag presenterar översÀttningen av artikeln
"Hur fungerar en relationsdatabas?".

NÀr det kommer till relationsdatabaser kan jag inte lÄta bli att tÀnka att det saknas nÄgot. De anvÀnds överallt. Det finns mÄnga olika databaser, frÄn den lilla och anvÀndbara SQLite till den kraftfulla Teradata. Men det finns bara nÄgra artiklar som förklarar hur en databas fungerar. Du kan sjÀlv söka pÄ "howdoesarelationaldatabasework" för att se hur fÄ resultat det finns. Dessutom Àr dessa artiklar korta. Om du letar efter de senaste trendteknologierna (BigData, NoSQL eller JavaScript) kommer du att hitta fler djupgÄende artiklar som förklarar hur de fungerar.

Är relationsdatabaser för gamla och trĂ„kiga för att förklara utanför universitetskurser, forskningsartiklar och böcker?

Hur fungerar relationella databaser (Del 1)

Som utvecklare avskyr jag att anvÀnda nÄgot jag inte förstÄr. Och om databaser har anvÀnts i mer Àn 40 Är mÄste det finnas en anledning. Under dessa Är har jag spenderat hundratals timmar pÄ att verkligen förstÄ dessa mÀrkliga svarta lÄdor som jag anvÀnder varje dag. Relationsdatabaser Àr mycket intressanta, för de Àr baserade pÄ anvÀndbara och ÄteranvÀndbara koncept.Om du Àr intresserad av att förstÄ databaser, men aldrig haft tid eller lust att grÀva ner dig i detta omfattande Àmne, kommer du att gilla den hÀr artikeln.

Även om titeln pĂ„ denna artikel Ă€r tydlig, Ă€r syftet med denna artikel inte att förstĂ„ hur man anvĂ€nder en databas.DĂ€rför borde du redan veta hur man skriver en enkel join-frĂ„ga och grundlĂ€ggande frĂ„gor; CRUDannars kanske du inte förstĂ„r den hĂ€r artikeln. Det Ă€r det enda du behöver veta, jag kommer att förklara allt annat.

Jag börjar med nÄgra grundlÀggande datavetenskaper, sÄsom tidskomplexitet av algoritmer (BigO). Jag vet att vissa av er avskyr detta koncept, men utan det kan du inte förstÄ nyanserna i databasen. Eftersom det Àr ett omfattande Àmne, kommer jag att fokusera pÄ det som jag anser Àr viktigt.: hur databasen hanterar SQL frÄgan.Jag kommer bara att presentera grundlÀggande koncept inom databaser,sÄ att du i slutet av artikeln har en uppfattning om vad som hÀnder under huven.

Eftersom detta Àr en lÄng och teknisk artikel som innehÄller mÄnga algoritmer och datastrukturer, ta dig tid att lÀsa den. Vissa begrepp kan vara svÄra att förstÄ; du kan hoppa över dem och ÀndÄ fÄ en allmÀn uppfattning.

För er som Àr mer insatta Àr denna artikel uppdelad i 3 delar:

  • Översikt av lĂ„gnivĂ„- och högnivĂ„komponenter i databaser
  • Översikt av queryoptimeringsprocessen
  • Översikt av transaktionshantering och buffertpool

Tillbaka till grunderna

För mĂ„nga Ă„r sedan (i en avlĂ€gsen, avlĂ€gsen galax
) var utvecklare tvungna att exakt kĂ€nna till antalet operationer de kodade. De kunde sina algoritmer och datastrukturer utan och innan, eftersom de inte hade rĂ„d att slösa CPU och minne pĂ„ sina lĂ„ngsamma datorer.

I denna del kommer jag att pÄminna dig om nÄgra av dessa begrepp, eftersom de Àr nödvÀndiga för att förstÄ databaser. Jag kommer ocksÄ att introducera begreppet databasindex.

O(1) vs O(n2)

Idag bryr sig mĂ„nga utvecklare inte om tidskomplexiteten för algoritmer 
 och de har rĂ€tt!

Men nÀr du hanterar stora mÀngder data (jag pratar inte om tusentals) eller om du kÀmpar för millisekunder, blir det kritiskt viktigt att förstÄ detta begrepp. Som du förstÄr mÄste databaser hantera bÄda situationerna! Jag kommer inte att lÄta dig spendera mer tid Àn nödvÀndigt för att fÄnga essensen. Detta kommer att hjÀlpa oss senare att förstÄ begreppet kostnadsbaserad (cost based optimization).

Konceptet

Tidskomplexiteten för en algoritm anvÀnds för att se hur lÄng tid det tar att köra algoritmen för en viss mÀngd data. För att beskriva denna komplexitet anvÀnds matematiska beteckningar av stor O. Denna notation anvÀnds med en funktion som beskriver hur mÄnga operationer algoritmen behöver för en given mÀngd indatan.

Till exempel, nÀr jag sÀger "denna algoritm har komplexitet O (some_function() )", betyder det att för att bearbeta en viss mÀngd data krÀver algoritmen some_function(a_certain_amount_of_data) operationer.

Följaktligen Det Àr viktigt inte mÀngden data**, utan hur ** antalet operationer ökar med ökande datamÀngd. Tidskomplexiteten ger inte ett exakt antal operationer, men det Àr ett bra sÀtt att uppskatta körtiden.

Hur fungerar relationella databaser (Del 1)

I den hÀr grafen kan du se förhÄllandet mellan antalet operationer och mÀngden indata för olika typer av tidskomplexitet. Jag anvÀnde en logaritmisk skala för att visa dem. Med andra ord ökar mÀngden data snabbt frÄn 1 till 1 miljard. Vi kan se att:

  • O(1) eller konstant komplexitet förblir konstant (annars skulle det inte kallas konstant komplexitet).
  • O(log(n)) förblir lĂ„g Ă€ven med miljarder data.
  • Den vĂ€rsta komplexiteten Ă€r - O(n2), dĂ€r antalet operationer vĂ€xer snabbt.
  • De tvĂ„ andra komplexiteterna ökar ocksĂ„ snabbt.

Exempel

Vid smÄ datamÀngder Àr skillnaden mellan O(1) och O(n2) obetydlig. Anta till exempel att du har ett algoritm som behöver bearbeta 2000 element.

  • Algoritm O(1) kostar dig 1 operation
  • Algoritm O(log(n)) kostar dig 7 operationer
  • Algoritm O(n) kostar dig 2 000 operationer
  • Algoritm O(n * log(n)) kostar dig 14 000 operationer
  • Algoritm O(n2) kostar dig 4 000 000 operationer

Skillnaden mellan O(1) och O(n2) verkar stor (4 miljoner operationer) men du kommer att förlora högst 2 ms, bara tiden för att blinka. Faktiskt kan moderna processorer bearbeta hundratals miljoner operationer per sekund.. Det Àr dÀrför prestanda och optimering inte Àr ett problem i mÄnga IT-projekt.

Som jag redan nÀmnt Àr det fortfarande viktigt att förstÄ detta koncept nÀr man arbetar med stora mÀngder data. Om algoritmen den hÀr gÄngen mÄste bearbeta 1 000 000 element (vilket inte Àr sÄ mycket för en databas):

  • Algoritm O(1) kostar dig 1 operation
  • Algoritm O(log(n)) kostar dig 14 operationer
  • Algoritm O(n) kostar dig 1 000 000 operationer
  • Algoritm O(n * log(n)) kostar dig 14 000 000 operationer
  • Algoritm O(n2) kostar dig 1 000 000 000 000 operationer

Jag har inte gjort nÄgra berÀkningar, men jag skulle sÀga att med algoritm O(n2) har du tid att ta en kaffe (till och med tvÄ!). Om du lÀgger till ytterligare 0 till datamÀngden har du tid att ta en tupplur.

LÄt oss gÄ djupare

För referens:

  • Sökning i en bra hash-tabell hittar elementet pĂ„ O(1).
  • Sökning i ett vĂ€lbalanserat trĂ€d ger resultat pĂ„ O(log(n)).
  • Sökning i en array ger resultat pĂ„ O(n).
  • De bĂ€sta sorteringsalgoritmerna har komplexiteten O(n * log(n)).
  • En dĂ„lig sorteringsalgoritm har komplexiteten O(n2).

Obs: i kommande delar kommer vi att se dessa algoritmer och datatyper.

Det finns flera typer av tidskomplexitet för algoritmer:

  • medelklassens scenario
  • bĂ€sta möjliga utfall
  • och vĂ€rsta scenariot

Tidskomplexiteten Àr ofta worst-case scenariot.

Jag har bara pratat om tidskomplexiteten för algoritmen, men komplexitet gÀller Àven för:

  • minnesförbrukningen för algoritmen
  • disk I/O som algoritmen anvĂ€nder

SjĂ€lvklart finns det komplexiteter som Ă€r vĂ€rre Ă€n nÂČ, exempelvis:

  • n⁎: det Ă€r fruktansvĂ€rt! NĂ„gra av de nĂ€mnda algoritmerna har en sĂ„dan komplexitet.
  • 3n: det Ă€r Ă€nnu vĂ€rre! En av algoritmerna som vi kommer att se mitt i den hĂ€r artikeln har denna komplexitet (och den anvĂ€nds faktiskt i mĂ„nga databaser).
  • fakultet n: du kommer aldrig att fĂ„ dina resultat ens med en liten mĂ€ngd data.
  • nËą: om du stöter pĂ„ denna komplexitet, bör du frĂ„ga dig sjĂ€lv om detta verkligen Ă€r ditt omrĂ„de ...

Obs: jag gav dig inte en verklig definition av beteckningen 'stor O', utan bara en idé. Du kan lÀsa den hÀr artikeln för Wikipedia den verkliga (asymptotiska) definitionen.

MergeSort (Sammanslagningssortering)

Vad gör du nÀr du behöver sortera en samling? Vad? Du anropar funktionen sort() ... Okej, bra svar ... Men för databaser mÄste du förstÄ hur den hÀr funktionen sort() fungerar.

Det finns flera bra sorteringsalgoritmer, sÄ jag kommer att fokusera pÄ den viktigaste: sammanslagningssorteringen. Du kanske inte förstÄr varför datorsortering Àr anvÀndbart just nu, men du kommer att förstÄ det efter delen som handlar om optimering av frÄgor. Dessutom kommer förstÄelsen av sammanslagningssortering att hjÀlpa oss senare att förstÄ den allmÀnna operationen join i databaser, som kallas merge join (sammanslagningsjoin).

Merge (slÄ ihop)

Som mÄnga anvÀndbara algoritmer bygger sammanslagningssortering pÄ en finess: att slÄ samman 2 sorterade arrayer med storleken N / 2 till en sorterad array med N element kostar bara N operationer. Denna operation kallas sammanslagning.

LÄt oss titta pÄ vad det hÀr betyder genom ett enkelt exempel:

Hur fungerar relationella databaser (Del 1)

I denna bild ser du att för att bygga den slutliga sorterade arrayen med 8 element behöver du bara utföra en iteration över 2 st 4-elementarrayer. Eftersom bÄda 4-elementarrayerna redan Àr sorterande:

  • 1) du jĂ€mför de aktuella elementen i de tvĂ„ arrayerna (i början Ă€r den aktuella = första)
  • 2) ta sedan tar du den minsta för att placera den i en array med 8 element
  • 3) och gĂ„r vidare till nĂ€sta element i arrayen dĂ€r du tog den minsta elementet
  • och upprepa 1, 2, 3, tills du kommer till det sista elementet i en av arrayerna.
  • Sedan tar du de Ă„terstĂ„ende elementen frĂ„n den andra arrayen för att placera dem i en array med 8 element.

Detta fungerar eftersom bÄda 4-element arrayerna Àr sorterade, och dÀrför behöver du inte 'gÄ tillbaka' i dessa arrayer.

Nu nÀr vi förstÄtt detta trick, hÀr Àr min pseudokod för merge:

array mergeSort(array a)
   if(length(a)==1)
      return a[0];
   end if

   //rekursiva anrop
   [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);

   //sammanfogar de 2 smÄ sorterade arrayerna till en stor
   array result := merge(new_left_array,new_right_array);
   return result;

Merge sort delar upp problemet i mindre problem, och hittar sedan resultaten av de mindre problemen för att fÄ resultatet av det ursprungliga problemet (notera: denna typ av algoritmer kallas dela och hÀrska). Om du inte förstÄr denna algoritm, oroa dig inte; jag förstod det inte första gÄngen jag sÄg det. Om det kan hjÀlpa dig, ser jag denna algoritm som en tvÄfas algoritm:

  • Delningsfas, dĂ€r arrayen delas upp i mindre arrayer
  • Sorteringsfas, dĂ€r smĂ„ arrayer sammanfogas (anvĂ€nder merge) för att bilda en större array.

Delningsfas (Division phase)

Hur fungerar relationella databaser (Del 1)

I delningsfasen delas arrayen upp i enhetsarrayer i 3 steg. Det formella antalet steg Àr log(N) (eftersom N=8, log(N) = 3).

Hur vet jag detta?

Jag Ă€r ett geni! Kort sagt — matematik. IdĂ©n Ă€r att varje steg minskar storleken pĂ„ den ursprungliga arrayen med hĂ€lften. Antalet steg Ă€r det antal gĂ„nger du kan dela den ursprungliga arrayen i tvĂ„. Detta Ă€r den exakta definitionen av logaritmen (med bas 2).

Sorteringsfas (Sorting phase)

Hur fungerar relationella databaser (Del 1)

I sorteringsfasen börjar du med enhetsarrayer (enskilda element). Under varje steg tillÀmpar du ett antal sammanslagningsoperationer, och den totala kostnaden Àr N = 8 operationer:

  • I det första steget har du 4 sammanslagningar som kostar 2 operationer vardera
  • I det andra steget har du 2 sammanslagningar som kostar 4 operationer vardera
  • I det tredje steget har du 1 sammanslagning som kostar 8 operationer

Eftersom det finns log(N) steg, den totala kostnaden N * log(N) operationer.

Fördelar med merge sort

Varför Àr denna algoritm sÄ kraftfull?

För att:

  • Du kan Ă€ndra den för att minska minnesanvĂ€ndningen, sĂ„ att du inte skapar nya arrayer, utan direkt Ă€ndrar den inmatade arrayen.

Observera: denna typ av algoritmer kallas i—plats (sortering utan extra minne).

  • Du kan Ă€ndra den för att anvĂ€nda diskutrymme och ett litet minnesutrymme utan stora kostnader för disk in / ut. IdĂ©n Ă€r att ladda i minnet endast de delar som för nĂ€rvarande bearbetas. Detta Ă€r viktigt nĂ€r du behöver sortera en tabell som Ă€r flera gigabyte stor med en minnesbuffer pĂ„ bara 100 megabyte.

Observera: denna typ av algoritmer kallas extern sortering.

  • Du kan Ă€ndra den för att köras pĂ„ flera processer / trĂ„dar / servrar.

Till exempel Àr distribuerad sammanslagning av sortering en av nyckelkomponenterna Hadoop (som Àr en struktur inom stora data).

  • Denna algoritm kan förvandla bly till guld (verkligen!).

Denna sorteringsalgoritm anvÀnds i de flesta (om inte alla) databaser, men den Àr inte den enda. Om du vill veta mer kan du lÀsa detta forskningsarbete, som diskuterar för- och nackdelar med de vanligaste sorteringsalgoritmerna i databaser.

Array, TrÀd och Hash-Tabell

Nu nÀr vi förstÄr idén om tidskomplexitet och sortering, mÄste jag berÀtta om 3 datatyper. Detta Àr viktigt eftersom de Àr grunden för moderna databaser. Jag kommer ocksÄ att introducera begreppet databasindex.

Array

En tvÄdimensionell array Àr den enklaste datatypen. En tabell kan ses som en array. Till exempel:

Hur fungerar relationella databaser (Del 1)

Denna 2D-array representerar en tabell med rader och kolumner:

  • Varje rad representerar en enhet
  • Kolumnerna lagrar egenskaper som beskriver enheten.
  • Varje kolumn lagrar data av en viss typ (heltal, strĂ€ng, datum ...).

Det Àr sÄ bekvÀmt att lagra och visualisera data, men nÀr du behöver hitta ett visst vÀrde fungerar det inte.

Till exempel, om du vill hitta alla killar som arbetar i Storbritannien mĂ„ste du gĂ„ igenom varje rad för att avgöra om den raden tillhör Storbritannien. Det kommer att kosta dig N operationer, dĂ€r N — antal rader, vilket Ă€r bra, men kan det finnas en snabbare vĂ€g? Nu Ă€r det dags att bekanta oss med trĂ€d.

Observera: de flesta moderna databaser erbjuder utökade matriser för effektiv lagring av tabeller: heap-organized tables och index-organized tables. Men det löser inte problemet med snabb sökning av ett specifikt villkor i en grupp av kolumner.

DatabastrÀd och index

Ett binÀrt söktrÀd Àr ett binÀrt trÀd med en speciell egenskap, nyckeln i varje nod mÄste vara:

  • större Ă€n alla nycklar som lagras i den vĂ€nstra undertrĂ€det
  • mindre Ă€n alla nycklar som lagras i den högra undertrĂ€det

LÄt oss se vad detta betyder visuellt

Tanken

Hur fungerar relationella databaser (Del 1)

Detta trÀd har N = 15 element. Anta att jag letar efter 208:

  • Jag börjar med roten, vars nyckel Ă€r 136. Eftersom 136<208, tittar jag pĂ„ den högra undertrĂ€det av noden 136.
  • 398>208, dĂ€rför tittar jag pĂ„ den vĂ€nstra undertrĂ€det av noden 398
  • 250>208, dĂ€rför tittar jag pĂ„ den vĂ€nstra undertrĂ€det av noden 250
  • 200<208, dĂ€rför tittar jag pĂ„ den högra undertrĂ€det av noden 200. Men 200 har inget högra undertrĂ€d, vĂ€rdet existerar inte (eftersom om det fanns, skulle det vara i det högra undertrĂ€det av 200).

Nu, lÄt oss sÀga att jag letar efter 40

  • Jag börjar med roten, vars nyckel Ă€r 136. Eftersom 136 > 40, tittar jag pĂ„ den vĂ€nstra undertrĂ€det av noden 136.
  • 80 > 40, dĂ€rför tittar jag pĂ„ den vĂ€nstra undertrĂ€det av noden 80
  • 40= 40, noden existerar. Jag hĂ€mtar radens identifierare inom noden (detta finns inte pĂ„ bilden) och tittar i tabellen för den angivna radidentifieraren.
  • Genom att kĂ€nna till radens identifierare kan jag veta exakt var data finns i tabellen, och dĂ€rför kan jag fĂ„ Ă„tkomst till dem omedelbart.

I slutÀndan kommer bÄda sökningarna att kosta mig antal nivÄer inom trÀdet. Om du noggrant lÀser delen om merge sort, bör du se att det finns log (N) nivÄer hÀr. Det visar sig att sökkostnaden Àr log(N), inte dÄligt!

Återkommer till vĂ„rt problem

Men detta Àr mycket abstrakt, sÄ lÄt oss ÄtergÄ till vÄrt problem. IstÀllet för en enkel integer, tÀnk er en strÀng som representerar nÄgon landsnamn i den tidigare tabellen. Anta att du har ett trÀd som innehÄller fÀltet "country" (kolumn 3) i tabellen:

  • Om du vill veta vem som arbetar i Storbritannien
  • tittar du pĂ„ trĂ€det för att fĂ„ noden som representerar Storbritannien
  • inuti "UKnode" hittar du platsen för arbetstagarnas poster i Storbritannien.

Denna sökning kommer att kosta log(N) operationer istÀllet för N operationer om du anvÀnder en array direkt. Det du just har presenterat var databasindex.

Du kan bygga ett indextrĂ€d för vilken grupp av fĂ€lt som helst (strĂ€ng, tal, 2 strĂ€ngar, tal och strĂ€ng, datum
) sĂ„ lĂ€nge du har en funktion för att jĂ€mföra nycklar (dvs. grupper av fĂ€lt) sĂ„ att du kan stĂ€lla in ordningen bland nycklarna (vilket gĂ€ller för alla grundlĂ€ggande typer i databasen).

B+TreeIndex

Även om detta trĂ€d fungerar bra för att fĂ„ ett specifikt vĂ€rde, finns det ett STORT problem nĂ€r du behöver hĂ€mta flera element mellan tvĂ„ vĂ€rden. Det kommer att kosta O(N) eftersom du mĂ„ste titta pĂ„ varje nod i trĂ€det och kontrollera om den ligger mellan dessa tvĂ„ vĂ€rden (t.ex. med en ordnad genomgĂ„ng av trĂ€det). Dessutom Ă€r denna operation inte praktisk för disk I/O eftersom du mĂ„ste lĂ€sa hela trĂ€det. Vi behöver hitta ett sĂ€tt att effektivt utföra intervalförfrĂ„gan. För att lösa detta problem anvĂ€nder moderna databaser en modifierad version av det tidigare trĂ€det som kallas B+Tree. I B+Tree trĂ€det:

  • endast de lĂ€gsta noderna (blad) lagrar information (platsen för rader i den relaterade tabellen)
  • de andra noderna finns hĂ€r för att dirigera till rĂ€tt nod under sökningen.

Hur fungerar relationella databaser (Del 1)

Som du kan se finns det fler noder hÀr (dubbelt sÄ mÄnga). Faktiskt har du ytterligare noder, "beslutsnoder", som hjÀlper dig att hitta rÀtt nod (som lagrar platsen för raderna i den relaterade tabellen). Men sökningens komplexitet Àr fortfarande O(log(N)) (det finns bara en nivÄ till). Den stora skillnaden Àr att noderna pÄ den lÀgre nivÄn Àr kopplade till sina eftertrÀdare.

Med detta B+Tree, om du söker efter vÀrden mellan 40 och 100:

  • Du behöver bara söka efter 40 (eller det nĂ€rmaste vĂ€rdet efter 40, om 40 inte finns), precis som du gjorde med det tidigare trĂ€det.
  • Samla sedan in eftertrĂ€darna till 40 genom att anvĂ€nda direkta lĂ€nkar till eftertrĂ€darna tills du nĂ„r 100.

Antag att du hittade M eftertrÀdare, och trÀdet har N noder. Att söka efter en specifik nod kostar log(N) precis som det tidigare trÀdet. Men efter att ha fÄtt denna nod fÄr du M eftertrÀdare i M operationer med lÀnkar till deras eftertrÀdare. Denna sökning kostar bara M+log(N) operationer jÀmfört med N operationer med det tidigare trÀdet. Dessutom behöver du inte lÀsa hela trÀdet (bara M + log (N) noder), vilket innebÀr mindre diskanvÀndning. Om M Àr litet (till exempel 200 rader) och N stort (1 000 000 rader) kommer detta att göra en STOR skillnad.

Men hÀr finns nya problem (igen!). Om du lÀgger till eller tar bort en rad i databasen (och dÀrmed i den relaterade B+Tree-indexet):

  • du mĂ„ste upprĂ€tthĂ„lla ordningen mellan noderna inom B+Tree, annars kan du inte hitta noder inom ett osorterat trĂ€d.
  • du mĂ„ste behĂ„lla det minimi möjliga antalet nivĂ„er i B+Tree, annars kommer tidskomplexiteten i O(log(N)) att bli O(N).

Med andra ord mÄste B+Tree vara sjÀlvordnande och balanserad. Lyckligtvis Àr detta möjligt med smarta borttagnings- och insÀttningsoperationer. Men detta kostar mycket: insÀttning och borttagning i B+ trÀdet kostar i O(log(N)). Det Àr dÀrför vissa av er har hört att anvÀnda för mÄnga index inte Àr en bra idé.Verkligen, du saktar ner snabb insÀttning/uppdatering/borttagning av en rad i tabellen, eftersom databasen mÄste uppdatera tabellens index med den dyra operationen O(log(N)) för varje index. Dessutom innebÀr tillÀgg av index en större belastning för transaktionshanteraren (kommer att beskrivas i slutet av artikeln).

För mer information kan du se artikeln pÄ Wikipedia om B+trÀd. Om du vill ha ett exempel pÄ implementering av B+Tree i databasen, kolla denna artikel och denna artikel frÄn huvudutvecklaren av MySQL. De Àr bÄda inriktade pÄ hur InnoDB (MySQL-motorn) hanterar index.

Obs: lÀsaren sa mig att pÄ grund av lÄgnivÄoptimeringar mÄste B+ trÀdet vara helt balanserat.

Hash-tabell

VÄr sista viktiga datastruktur Àr hash-tabellen. Den Àr mycket anvÀndbar nÀr du vill snabbt söka efter vÀrden. Dessutom hjÀlper förstÄelsen av hash-tabellen oss senare att förstÄ en allmÀn databasinoperation som kallas hash-join ( hash join). Denna datastruktur anvÀnds ocksÄ av databasen för att lagra vissa interna saker (till exempel, lÄsnings-tabell eller bufferpool, vi kommer att se bÄda dessa begrepp senare).

En hash-tabell Àr en databasstruktur som snabbt hittar ett element utifrÄn dess nyckel. För att skapa en hash-tabell mÄste du definiera:

  • nyckel för dina element
  • hash-funktion för nycklarna. BerĂ€knade hashes av nycklarna ger platsen för elementen (kallade segment) ).
  • en funktion för att jĂ€mföra nycklar.NĂ€r du har hittat rĂ€tt segment mĂ„ste du hitta elementet du söker inuti segmentet med hjĂ€lp av denna jĂ€mförelse.

Ett enkelt exempel

LÄt oss ta ett illustrativt exempel:

Hur fungerar relationella databaser (Del 1)

Denna hash-tabell har 10 segment. Eftersom jag Àr lat, har jag ritat endast 5 segment, men jag vet att ni Àr smarta, sÄ jag lÄter er förestÀlla er de andra 5 sjÀlva. Jag anvÀnde en hash-funktion med mod 10 pÄ nyckeln. Med andra ord, jag behÄller endast sista siffran av elementets nyckel för att hitta dess segment:

  • om den sista siffran Ă€r 0, gĂ„r elementet till segment 0,
  • om den sista siffran Ă€r 1, gĂ„r elementet till segment 1,
  • om den sista siffran Ă€r 2, gĂ„r elementet till segment 2,
  • 


JÀmförelsefunktionen jag anvÀnde Àr helt enkelt jÀmlikhet mellan tvÄ heltal.

Anta att du vill hÀmta elementet 78:

  • Hash-tabellen berĂ€knar hash-koden för 78, vilket Ă€r 8.
  • Hash-tabellen letar i segment 8, och det första elementet den hittar Ă€r 78.
  • Den returnerar elementet 78 till dig.
  • Sökningen kostade bara 2 operationer (en för att berĂ€kna vĂ€rdet av hash-funktionen och en annan för att hitta elementet inuti segmentet).

Nu, lÄt oss sÀga att du vill hÀmta elementet 59:

  • Hash-tabellen berĂ€knar hash-koden för 59, vilket Ă€r 9.
  • Hash-tabellen letar i segment 9, det första hittade elementet Ă€r 99. Eftersom 99!=59 Ă€r elementet 99 inte det rĂ€tta elementet.
  • Med samma logik tas det andra elementet (9), det tredje (79), 
, och sĂ„ vidare tills det sista (29).
  • Elementet hittades inte.
  • Sökningen kostade 7 operationer..

En bra hash-funktion

Som ni ser, beroende pÄ det vÀrde ni söker, Àr kostnaden inte densamma!

Om jag nu Àndrar hash-funktionen till modul 1 000 000 av nyckeln (det vill sÀga, tar de senaste 6 siffrorna), kommer den andra sökningen bara kosta 1 operation, eftersom det i segment 000059 inte finns nÄgra element. Den verkliga uppgiften Àr att hitta en bra hash-funktion som skapar segment som innehÄller ett mycket litet antal element..

I mitt exempel Àr det lÀtt att hitta en bra hash-funktion. Men det Àr ett enkelt exempel, att hitta en bra hash-funktion Àr svÄrare nÀr nyckeln Àr:

  • en strĂ€ng (till exempel - efternamn)
  • 2 strĂ€ngar (till exempel - efternamn och förnamn)
  • 2 strĂ€ngar och ett datum (till exempel - efternamn, förnamn och födelsedatum)
  • 


Med en bra hash-funktion kostar uppslagning i hash-tabellen O(1).

Array vs hash-tabell

Varför inte anvÀnda en array?

Hmm, bra frÄga.

  • Hash-tabellen kan vara delvis inlĂ€st i minnet, medan andra segment kan kvarstĂ„ pĂ„ disken.
  • Med en array mĂ„ste du anvĂ€nda ett sammanhĂ€ngande utrymme i minnet. Om du laddar en stor tabell Ă€r det mycket svĂ„rt att hitta tillrĂ€ckligt sammanhĂ€ngande utrymme.
  • För en hash-tabell kan du vĂ€lja nyckel (till exempel, landet och personens efternamn).

För ytterligare information kan du lÀsa artikeln om JavaHashMap, som Àr en effektiv implementation av hash-tabellen; du behöver inte förstÄ Java för att förstÄ de koncept som beskrivs i den hÀr artikeln.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster