Quantcast
Channel: PostgreSQL – Savepoint
Viewing all articles
Browse latest Browse all 70

Chaves Artificiais no PostgreSQL: desempenho

$
0
0

Falamos sobre a criação de chaves artificiais, sobre como usar UUID ou sequencias, inclusive sobre a nova sintaxe adotada no PostgreSQL 10 utilizando as chamadas IDENTITY COLUMNs. Uma reação comum que eu vi por aí é achar que é mais simples usar UUID sempre, uma vez que você não tem risco de colisão e pode usar em sistemas distribuídos. Bom, a história não é bem assim. Existe um custo adicional ao se escolher UUIDs ou mesmo gerar hashs enormes e armazenar no banco de dados. Vou aqui explorar algumas possibilidades, entre utilizar uma SEQUENCE armazenada num campo INTEGER e índices do tipo BTREE e HASH (que melhorou muito no PostgreSQL 10). Depois vamos utilizar campos do tipo UUID, VARCHAR e CHAR, também com índices BTREE e HASH.

Primeiro vamos criar nossas tabelas:

CREATE TABLE seq_btree (id integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY);
CREATE TABLE seq_hash (id integer  GENERATED BY DEFAULT AS IDENTITY);
CREATE INDEX ON seq_hash USING hash (id);
CREATE TABLE uuid_btree (id uuid PRIMARY KEY);
CREATE TABLE uuid_hash (id uuid );
CREATE INDEX ON uuid_hash USING hash (id);
CREATE TABLE uuid_char_btree (id char(36) PRIMARY KEY);
CREATE TABLE uuid_char_hash (id varchar);
CREATE INDEX ON uuid_char_hash USING hash (id);
CREATE TABLE uuid_varchar_btree (id varchar PRIMARY KEY);
CREATE TABLE uuid_varchar_hash (id varchar);
CREATE INDEX ON uuid_varchar_hash USING hash (id);

Notem que não existem índices UNIQUE do tipo HASH, logo ele não pode ser utilizado em uma PRIMARY KEY. Neste caso adicionamos o índice após a criação da tabela.

INSERT

Agora vamos inserir um milhão de registros em cada uma das tabelas utilizando a função nextval() nas sequencias e a função uuid_generate_v4() para gerar o UUID:

INSERT INTO seq_btree SELECT nextval('seq_btree_id_seq') FROM generate_series(1::integer,1000000::integer);

INSERT INTO  uuid_btree SELECT uuid_generate_v4() FROM generate_series(1,1000000);

Tomei alguns cuidados antes de fazer a carga:

  • Aumentei o valor do WORK_MEM;
  • Rodei um CHECKPOINT antes de cada teste;
  • Realizei todos os teste num mesmo ambiente controlado, sem nada rodando em paralelo.

Vejamos o tempo levado para a carga de cada tabela:

seq_btree           Time: 11152.751 ms (00:11.153)
seq_hash            Time: 11692.158 ms (00:11.692)
uuid_btree          Time: 58822.429 ms (00:58.822)
uuid_hash           Time: 55405.673 ms (00:55.406)
uuid_char_btree     Time: 77064.257 ms (01:17.064)
uuid_char_hash      Time: 57885.347 ms (00:57.885)
uuid_varchar_btree  Time: 75555.282 ms (01:15.555)
uuid_varchar_hash   Time: 57805.156 ms (00:57.805)

Aqui vemos uma clara vantagem em se utilizar sequências! Elas são muito mais rápidas durante o INSERT. Depois vemos que os dados armazenados em UUID são mais rápidos que os armazenados em CHAR ou VARCHAR. Note também que nas tabelas que utilizam UUID, o índice HASH foi mais veloz que o índice BTREE. Para números sequenciais isso se inverte.

Tamanho

Além disso, vemos que o tamanho das tabelas muda, uma vez que uma sequencia ocupa menos espaço:

seq_btree 35 MB
seq_hash 35 MB
uuid_btree 42 MB
uuid_hash 42 MB
uuid_char_btree 65 MB
uuid_char_hash 65 MB
uuid_varchar_btree 65 MB
uuid_varchar_hash 65 MB

Vejam que utilizar UUID é mais eficiente do que armazenar este tipo de dado em CHAR ou VARCHAR, daí o melhor desempenho na carga.

Agora vejamos como fica o tamanho dos índices:

seq_btree_pkey           seq_btree          21 MB
seq_hash_id_idx          seq_hash           37 MB
uuid_btree_pkey          uuid_btree         39 MB
uuid_hash_id_idx         uuid_hash          36 MB
uuid_char_btree_pkey     uuid_char_btree    73 MB
uuid_char_hash_id_idx    uuid_char_hash     37 MB
uuid_varchar_btree_pkey  uuid_varchar_btree 74 MB
uuid_varchar_hash_id_idx uuid_varchar_hash  37 MB

Aqui nós vemos como o índice do tipo HASH tem vantagens em dados aleatórios sobre o BTREE que é melhor em dados sequenciais.

SELECT

Outro ponto de vista importante é referente às estatísticas coletadas pelo ANALYZE. Olhando a tabela pg_stats, vemos algumas coisas interessantes:

tablename      | avg_width | correlation
--------------------+-----------+--------------
 seq_btree          |         4 |            1
 seq_hash           |         4 |            1
 uuid_btree         |        16 |   0.00269653
 uuid_hash          |        16 |   0.00022602
 uuid_char_btree    |        37 |   0.00133542
 uuid_char_hash     |        37 |   0.00420481
 uuid_varchar_btree |        37 |   0.0120523
 uuid_varchar_hash  |        37 |   0.0016304

A primeira coisa que vemos é que o tamanho (avg_width) do campo é muito menor no caso de um INTEGER e muito pior no caso do VARCHAR e CHAR. depois notamos que a correlação (relação entre a distribuição dos dados e a ordem em que eles estão armazenados no disco) é favorável ao uso de sequencias, particularmente quando você quiser trazer vários registros baseados na ordenação.

Vejamos como fica o desempenho das nossas chaves artificiais em operações de leitura. Primeiro vamos pegar um registro apenas de cada tabela e medir o tempo:

SELECT * FROM seq_btree WHERE id = 100001;

seq_btree           Time: 0.390 ms
seq_hash            Time: 0.366 ms
uuid_btree          Time: 0.407 ms
uuid_hash           Time: 0.396 ms
uuid_char_btree     Time: 0.494 ms
uuid_char_hash      Time: 0.391 ms
uuid_varchar_btree  Time: 0.440 ms
uuid_varchar_hash   Time: 0.414 ms

Vemos que a diferença aqui é pequena, com leve vantagem para índices do tipo HASH e para o uso de sequências. Agora vamos utilizar uma ordenação para trazer os dados:

SELECT * FROM seq_btree ORDER BY id LIMIT 1 OFFSET 100000;

seq_btree           Time: 26.792 ms
seq_hash            Time: 217.644 ms
uuid_btree          Time: 100.570 ms
uuid_hash           Time: 507.426 ms
uuid_char_btree     Time: 114.143 ms
uuid_char_hash      Time: 3753.417 ms
uuid_varchar_btree  Time: 109.001 ms
uuid_varchar_hash   Time: 3815.933 ms

Aqui a correlação faz muita diferença e os índices do tipo HASH são uma péssima escolha. Então se você tem o hábito de ordenar os dados baseado na sua chave artificial, as sequências tem uma vantagem enorme, e os índices HASH uma boa desvantagem.

Conclusões

Espero que tenha ficado claro que o uso de UUID tem custo sim e deve ser avaliado com cuidado. Então vejamos algumas considerações finais:

  • Não fiz testes com UPDATE e DELETE aqui, pois considerei que não relevantes para no uso de chaves artificiais.
  • No geral ele ocupa mais espaço (ainda mais se você fizer a besteira de utilizar CHAR ou VARCHAR)
  • UUID e é cerca de 5x mais lento em operações de INSERT
  • UUID e sequências tem desempenho semelhante em consultas simples do tipo “id = xxxx’, mas em consultas complexas as sequences são mais eficientes devido a correlação entre a sequência e o armazenamento físico;
  • Índices do tipo HASH são ligeiramente mais eficientes com UUID, mas não valem à pena quando se utiliza sequences. No entanto, vale lembrar que índices do tipo hash não podem ser utilizados como PK ou UNIQUE.

Observação

Você também pode utilizar o tipo de dados binário bytea para armazenar números hexadecimais com a mesma eficiência que o campo do tipo UUID, gravando dois números hexadecimais por byte, enquanto o CHAR e VARCHAR utilizam pelo menos um byte por caractere. A diferença está na validação e formatação de entrada e saída que fica mais simples no UUID.


Viewing all articles
Browse latest Browse all 70

Trending Articles


FORECLOSURE OF REAL ESTATE MORTGAGE


FORTUITOUS EVENT


Pokemon para colorear


Girasoles para colorear


OFW quotes : Pinoy Tagalog Quotes


Patama Quotes – Tanga love tagalog quotes


“Hanggang s apag tanda natin”


RE: Mutton Pies (frankie241)


Hato lada ym dei namar ka jingpyrshah jong U JJM Nichols Roy (Bah Joy) ngin...


Vimeo 10.7.0 by Vimeo.com, Inc.


UPDATE SC IDOL: TWO BECOME ONE


KASAMBAHAY BILL IN THE HOUSE


Pocoyo para colorear


Sapos para colorear


Long Distance Relationship Tagalog Love Quotes


“BAHAY KUBO HUGOT”


Re:Mutton Pies (lleechef)


Ka longiing longsem kaba skhem bad kaba khlain ka pynlong kein ia ka...


Vimeo Create - Video Maker & Editor 1.5.2 by Vimeo Inc


Vimeo 10.7.1 by Vimeo.com, Inc.