Meu conhecimento de bancos de dados e SQL é baseado principalmente nas aulas da universidade. De qualquer forma, passei alguns meses (quase um ano) em uma empresa, onde trabalhava com bancos de dados.
Eu li alguns livros e tenho participado em alguns treinamentos sobre bancos de dados, como MySQL
, PostgreSQL
, SQLite
, Oracle
e também alguns nonSQL
db
s como nós MongoDB
, Redis
, ElasticSearch
etc.
Como eu disse, eu sou iniciante, com muita falta de conhecimento, mas hoje alguém disse algo, o que é totalmente contrário ao conhecimento do meu iniciante.
Deixe-me explicar. Vamos pegar o banco de dados SQL e criar uma tabela simples Person
com poucos registros dentro:
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
Agora, é a parte que eu gostaria de focar - id
é a INDEX
.
Até agora, pensei que funcionasse dessa maneira: quando uma tabela está sendo criada, a INDEX
está vazia. Quando estou adicionando um novo registro à minha tabela, ele INDEX
está sendo recalculado com base em algumas quantidades. Por exemplo:
Agrupando um por um:
1 ... N
N+1 ... 2N
...
XN+1 ... (X+1)N
então, para o meu exemplo com size = 11 elements
e N = 3
será assim:
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
Portanto, quando estou usando a consulta, SELECT * FROM Person WHERE id = 8
ele fará alguns cálculos simples 8 / 3 = 2
; portanto, precisamos procurar esse objeto group2
e, em seguida, essa linha será retornada:
8 | Hubert | 53
Essa abordagem funciona no tempo em O(k)
que k << size
. Obviamente, um algoritmo para organizar linhas em grupos é com certeza muito mais complicado, mas acho que este exemplo simples mostra meu ponto de vista.
Então, agora, eu gostaria de apresentar outra abordagem, que me foi mostrada hoje.
Vamos tomar novamente esta tabela:
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
Agora, estamos criando algo semelhante a Hashmap
(de fato, literalmente, é um mapa de hash) que mapeia id
para a address
linha com esse ID. Digamos:
id | addr
---------
1 | @0001
2 | @0010
3 | @0011
4 | @0100
5 | @0101
6 | @0110
7 | @0111
8 | @1000
9 | @1001
10 | @1010
11 | @1011
Então agora, quando estou executando minha consulta: SELECT * FROM Person WHERE id = 8
ele será mapeado diretamente id = 8
para o endereço na memória e a linha será retornada. Claro que isso é complexidade O(1)
.
Então agora, eu tenho algumas perguntas.
1. Quais são as aventuras e desvantagens de ambas as soluções?
2. Qual deles é mais popular nas implementações atuais de banco de dados? Talvez diferentes dbs usem abordagens diferentes?
3. Existe em dbs não SQL?
Agradeço antecipadamente
COMPARAÇÃO
| 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 - número de registros
Estou certo? E o custo da reconstrução da árvore B e da tabela Hash após cada inserção / exclusão ? No caso da árvore B , precisamos alterar alguns indicadores, mas no caso da árvore b equilibrada, é necessário mais esforço. Também no caso da tabela Hash , temos que fazer poucas operações, principalmente se nossa operação gerar conflitos .
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.
é claro que sei que é muito, muito mais complicado. Então, finalmente, quando digo no meu código INDEX
qual das minhas soluções ( 1 ou 2 ) está mais próxima dessa solução real? E quanto ao tempo necessário para acessar um registro com base INDEX
. É mesmo O(1)
? Com o índice da árvore B, parece muito O(log2(N))
. Estou certo?
O(1)
você acertou! Na primeira maneira, parece que você está descrevendo um índice da árvore B, mas tem algum mal-entendido. Não há cálculo (divisão por 3 ou qualquer coisa), é mais complexo, pois a árvore tem mais níveis (é uma árvore, tem galhos grandes, pequenos e menores, ... e depois sai :) :)