INDICE SQL: come funziona?


19

La mia conoscenza di database e SQL si basa in gran parte su classi universitarie. Comunque, ho trascorso pochi mesi (quasi un anno) in un'azienda, dove lavoravo con i database.

Ho letto qualche libro e ho preso parte a pochi corsi di formazione sui database, come MySQL, PostgreSQL, SQLite, Oraclee anche alcuni nonSQL dbs come noi MongoDB, Redis, ElasticSearchetc.

Come ho già detto, sono un mendicante, con molta mancanza di conoscenza, ma oggi qualcuno ha detto qualcosa, ciò che è totalmente contro la conoscenza del mio mendicante.

Lasciatemi spiegare. Prendiamo il database SQL e creiamo una semplice tabella Personcon pochi record all'interno:

id | name   | age
-----------------
1  | Alex   | 24
2  | Brad   | 34
3  | Chris  | 29
4  | David  | 28
5  | Eric   | 18
6  | Fred   | 42
7  | Greg   | 65
8  | Hubert | 53
9  | Irvin  | 17
10 | John   | 19
11 | Karl   | 23

Ora, è la parte su cui vorrei concentrarmi - idè la INDEX.

Finora, ho pensato che funzionasse in questo modo: quando viene creata una tabella INDEXè vuota. Quando aggiungo un nuovo record al mio tavolo, questo INDEXviene ricalcolato in base ad alcuni alghortim. Per esempio:

Raggruppando uno per uno:

1    ... N
N+1  ... 2N
     ...
XN+1 ... (X+1)N

quindi, per il mio esempio con size = 11 elementse N = 3sarà così:

id | name   | age
-----------------
1  | Alex   | 24     // group0
2  | Brad   | 34     // group0
3  | Chris  | 29     // group0
4  | David  | 28     // group1
5  | Eric   | 18     // group1
6  | Fred   | 42     // group1
7  | Greg   | 65     // group2
8  | Hubert | 53     // group2
9  | Irvin  | 17     // group2
10 | John   | 19     // group3
11 | Karl   | 23     // group3

Quindi, quando sto usando la query SELECT * FROM Person WHERE id = 8farà qualche semplice calcolo 8 / 3 = 2, quindi dobbiamo cercare questo oggetto group2e quindi questa riga verrà restituita:

8  | Hubert | 53

inserisci qui la descrizione dell'immagine

Questo approccio funziona nel tempo in O(k)cui k << size. Certo, un algoritmo per organizzare le file in gruppi è sicuramente molto più complicato, ma penso che questo semplice esempio mostri il mio punto di vista.

Quindi ora vorrei presentare un altro approccio, che mi è stato mostrato oggi.

Riprendiamo questa tabella:

id | name   | age
-----------------
1  | Alex   | 24
2  | Brad   | 34
3  | Chris  | 29
4  | David  | 28
5  | Eric   | 18
6  | Fred   | 42
7  | Greg   | 65
8  | Hubert | 53
9  | Irvin  | 17
10 | John   | 19
11 | Karl   | 23

Ora, stiamo creando qualcosa di simile a Hashmap(in effetti, letteralmente è una mappa hash) che si associa ida addressdi fila con questo ID. Diciamo:

id | addr 
---------
1  | @0001
2  | @0010
3  | @0011
4  | @0100
5  | @0101
6  | @0110
7  | @0111
8  | @1000
9  | @1001
10 | @1010
11 | @1011

Quindi ora, quando eseguo la mia query: SELECT * FROM Person WHERE id = 8

verrà mappato direttamente id = 8all'indirizzo in memoria e la riga verrà restituita. Naturalmente la complessità di questo è O(1).

Quindi ora ho alcune domande.

1. Quali sono gli avventaggi e gli svantaggi di entrambe le soluzioni?

2. Quale è più popolare nelle attuali implementazioni del database? Forse dbs diversi usano approcci diversi?

3. Esiste in dbs non SQL?

Grazie in anticipo


CONFRONTO

               |      B-tree     |   Hash Table
----------------------------------------------------
----------------   one element   -------------------
----------------------------------------------------
SEARCHING      |  O(log(N))      | O(1) -> O(N)  
DELETING       |  O(log(N))      | O(1) -> O(N)
INSERTING      |  O(log(N))      | O(1) -> O(N)
SPACE          |  O(N)           | O(N)
----------------------------------------------------
----------------    k elements   -------------------
----------------------------------------------------
SEARCHING      |  k + O(log(N))  | k * O(1) -> k * O(N)
DELETING       |  k + O(log(N))  | k * O(1) -> k * O(N)
INSERTING      |  k + O(log(N))  | k * O(1) -> k * O(N)
SPACE          |  O(N)           | O(N)

N - numero di record

Ho ragione? Che dire del costo di ricostruzione della tabella B-tree e Hash dopo ogni inserimento / cancellazione ? Nel caso di B-tree dobbiamo cambiare alcuni puntatori ma in caso di b-tree bilanciato ha bisogno di più sforzo. Anche nel caso della tabella hash dobbiamo fare poche operazioni, specialmente se la nostra operazione genera conflitti .


2
Nel secondo modo, stai descrivendo un indice hash. La parte su di O(1)te ha capito bene! Nel primo modo, sembra che tu stia descrivendo un indice B-tree ma hai dei malintesi. Non esiste alcun calcolo (divisione per 3 o altro), è più complesso in quanto l'albero ha più livelli (è un albero, ha rami grandi, piccoli, più piccoli, ... e poi lascia :)
ypercubeᵀᴹ

3
BTrees: en.m.wikipedia.org/wiki/B-tree sorpreso che non ci fosse un corso di algoritmi nella tua università che lo spiegasse
Philᵀᴹ

@ypercube Ciao, grazie per la tua risposta. Così come ho scritto: Of course, an alghoritm to organise rows in groups is for sure much more complicated but I think this simple example shows my point of view.certo che so che è molto molto più complicato. Quindi, infine, quando sto dicendo nel mio codice INDEXquale delle mie soluzioni ( 1 ° o 2 ° ) è più vicina a questa vera? E che dire del tempo necessario per accedere a un record basato su INDEX. È davvero O(1)? Con l'indice B-tree sembra molto simile O(log2(N)). Ho ragione?
Ruhungry,

@FreshPhilOfSO Immagino (ancora di più, ne sono sicuro) ci sono state delle lezioni a riguardo. Probabilmente, mi sono perso qualcosa ...
Ruhungry

ElasticSearch utilizza indici invertiti, totalmente diversi dagli alberi B elastic.co/blog/found-elasticsearch-from-the-bottom-up
Lluis Martinez

Risposte:


12

Stai sostanzialmente descrivendo un indice B-tree e un indice hash. Entrambi hanno un posto, ma entrambi sono più adatti per diversi lavori.

Vantaggi e svantaggi

Gli indici B-tree (e B + -tree) sono generalmente bilanciati. Ciò significa che la ricerca di un valore richiederà sempre la stessa quantità di tempo, indipendentemente da dove si trova nell'albero (O (log n)). Generalmente, il numero di livelli nell'albero è limitato, quindi tende a diventare "più ampio" e non "più profondo". Per insiemi di dati di piccole dimensioni, tuttavia, il costo di mantenimento e utilizzo dell'albero B può essere più che una semplice lettura di tutte le righe. Gli indici B-tree sono utili per set di dati di grandi dimensioni, set di dati con bassa selettività o set di dati in cui si intende selezionare un intervallo di oggetti non solo un oggetto.

Le tabelle hash sono ideali per piccoli set di dati. Gli indici hash hanno un numero predefinito di bucket hash, a seconda dell'algoritmo di hashing utilizzato. Questo perché un determinato algoritmo di hash può produrre solo così tanti hash unici, quindi diventa solo "più profondo" e non "più ampio". Una volta che il motore di database ha trovato il bucket giusto, passa attraverso tutti gli oggetti in quel bucket per trovare quello desiderato. Con set di dati piccoli e altamente selettivi, ogni bucket contiene un numero molto piccolo di oggetti e viene risolto abbastanza rapidamente. Con set di dati più grandi, i bucket diventano molto più affollati. Quindi, se l'oggetto di cui hai bisogno si trova in un piccolo secchio o è vicino all'inizio del secchio, ritorna piuttosto velocemente. Se è alla fine di un grande secchio, ci vuole più tempo. L'indice non è bilanciato, quindi le prestazioni vanno da O (1) a O (n).

Popolarità

In generale, ho incontrato di più gli alberi B. Gli indici bitmap sono anche un'altra opzione per i valori con una cardinalità bassa (pensa a valori booleani o forse di genere). Questo varierà a seconda del motore del database per quanto riguarda i tipi di indice disponibili.

NoSQL

I database NoSQL supportano sicuramente gli indici. La maggior parte supporta B-tree o una variazione su B-tree. La maggior parte sembra supportare anche gli indici con hash.


4
Non penso che il numero di livelli negli alberi B + sia fisso. Almeno non in SQL Server, per quanto ne so.
ypercubeᵀᴹ

1
È vero. Un albero B potrebbe avere un numero qualsiasi di livelli, ma è generalmente limitato a 3 o 4. Ho modificato la mia risposta.
sarme,

Ciao @sarme. Mi piace molto la tua risposta. Spiega molto. Non ti dispiace se inizio a generarmi per questa domanda? Forse qualcuno aggiungerà qualcosa di interessante.
Ruhungry,

1
Non intendi una cardinalità bassa per l'indice bitmap?
Mihai,

1
Giusto, BASSA cardinalità. Devo smettere di rispondere alle domande poco prima di coricarmi :). Risposta aggiornata
Sarme,

4

Quali sono gli avventaggi e gli svantaggi di entrambe le soluzioni? La seconda soluzione non può eseguire scansioni dell'intervallo. È ottimo per selezionare un singolo ID. Ma cosa succede se si desidera ID da 3 a 8? Deve prendere tutti i record individuali che nel mondo reale non sono solo O (1) * 6 record da recuperare. In un grande database di produzione con un indice HashMap otterrai record su diverse pagine, richiedendo di colpire il disco e leggere sei diverse pagine in memoria.

In una struttura B-Tree, come il modo in cui verrebbe effettivamente implementata la tua prima situazione, gli ID sarebbero sequenziali su disco e una singola pagina conterrebbe probabilmente gli ID 3 - 8 aumentando la velocità delle scansioni dell'intervallo renderebbe l'accesso individuale O (log n) .

Quale è più popolare nelle attuali implementazioni di database? Forse dbs diversi usano approcci diversi? Non ho una grande esperienza in molti database diversi. So che Sql Server utilizza principalmente B-Trees, ma SQl 2014 ha alcuni nuovi indici hash che è possibile utilizzare su determinate tabelle. Sento un sacco di database No SQL e database di memorizzazione nella cache basati sul recupero di singoli record che usano anche indici hash. Ciò ha senso per le cache poiché si desidera il record per l'utente A e non è necessario eseguire scansioni dell'intervallo.

Esiste in dbs non SQL? Sì. Dando una rapida occhiata alla documentazione di creazione dell'indice per postgressql, vedo che supporta sia gli indici Hash e B-Tree, sia alcuni altri.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.