Texto extraído do site da FIREBASE
www.firebase.com.br
Banco de Dados de um Terabyte
por: Carlos H. Cantu
DEGRADAÇÃO DE PERFORMANCE COM FIREBIRD
Uma das preocupações mais importantes em relação a bancos de dados é a degradação de performance. Muitos usuários alegam que suas aplicações de bases de dados começam a ter problemas de performance quando a base atinge um determinado limiar: pode ser 3Gb, 5Gb, tamanho da memória RAM, 20Gb, etc. A queixa mais comum é quando o tamanho da base ultrapassa a quantidade de RAM disponível no servidor. Será verdade?
Vamos realizar uma série de testes para checar se há realmente degradação de performance relacionada com o crescimento da base de dados. Para tanto, simulamos o crescimento da base de dados com a mesma carga e o mesmo hardware, realizando 11 testes com bases de dados entre 9GB e 30GB.
- HARDWARE UTILIZADO
CPU = AMD FX8350
RAM = 16GB
HD (database) = RAID 2 x 4 TB, SATA, Segate
Como se pode ver, é uma máquina com configuração modesta, podendo ser considerado um servidor típico de baixo custo, talvez exceto pelos drives SATA de alta capacidade, mas de acordo com o fabricante, drives de 1TB e 4TB tem praticamente a mesma velocidade.
- SOFTWARE UTILIZADO
Sistema Operacional = Windows Server 2008R2 (64 bits).
Firebird = Firebird SuperServer 64bits
Loader = Custom loader from tpc-based test
Como o objetivo do teste é medir a variação de performance de um sistema tradicional, nós usamos o Firebird SuperServer 64bits, e não o Classic, para simular o cenário mais comum em pequenas empresas, que geralmente usa o que foi instalado há anos. Como você deve saber, o SuperServer, por padrão, usa apenas uma CPU/Core, portanto, provavelmente o Classic/SuperClassic (que usa todos os processadores) poderia mostrar resultados melhores, mas o objetivo do teste não é ajuste de performance.
- CONFIGURAÇÃO DO ARQUIVO DE BANCO DE DADOS E DO FIREBIRD (SGBD)
Alteramos dois parâmetros do firebird.conf, conforme sempre recomendamos aos nosso usuários: aumentamos o page buffers para 10.000 e o espaço temporário para sort. Todas as bases de dados utilizadas foram criadas com page size de 16.384 bytes.
- PROCESSO DE CARREGAMENTO DOS DADOS
Cada teste era composto de duas etapas: carga e simulação de 20 terminais que realizavam inserts, updates e deletes. A carga dos dados foi executada pela aplicação load.exe, que insere dados em diversas tabelas. Como se vê na figura abaixo (linha vermelha), a velocidade de inserção dos dados variou entre 35 MB/seg a 1 MB/seg.
A diferença de velocidade é devida ao próprio design da aplicação de carga, e não ao Firebird: o loader foi desenhado de forma que insira rapidamente 70% dos dados desejados, e lentamente insera o restante das informações. Esse comportamento foi repetido nos testes com todas as bases de dados, pois é importante executar exatamente as mesmas operações em todos os testes, para que possamos fazer a média de velocidade de carga.
É importante mencionar que o loader.exe insere apenas dados, sendo que os índices são criados após a carga estar completa.
Abaixo temos a tabela com os valores obtidos com a carga nos 11 bancos de dados com tamanhos variando entre 9GB e 30GB.
# |
Tamanho da base (GB) |
Tempo de carga (seg) |
Velocidade de carga (MB/seg) |
1 |
9,04 |
2535 |
3,65166075 |
2 |
10,80 |
3197 |
3,45924304 |
3 |
13,00 |
4057 |
3,281242297 |
4 |
15,50 |
4698 |
3,378458919 |
5 |
17,30 |
5455 |
3,24751604 |
6 |
19,90 |
6037 |
3,375451383 |
7 |
21,60 |
6473 |
3,417024564 |
8 |
24,20 |
7539 |
3,287014193 |
9 |
26,00 |
7779 |
3,422547885 |
10 |
28,60 |
8851 |
3,308823862 |
11 |
30,30 |
9266 |
3,348499892 |
Como podemos ver, os dados são relativamente estáveis, e a media de variação da velocidade de carga variou entre 3.3-3.4MB/sec. Não há sinais que a performance caia quando a base de dados passa a quantidade de RAM disponível (após a base #5, com 17.3GB).
- PERFORMANCE
O tempo de carga foi bastante promissor, mas e quanto aos resultados de performance? Antes de comentar, vamos rever rapidamente o processo de simulação.
A simulação roda 20 threads, e cada uma delas realiza diversas operações de negócio: cria pedidos, processa pagamentos, faz contagem de estoque, processa o envio dos pedidos, etc. Como você pode perceber, simulamos um ambiente normal de uma aplicação de vendas.
A aplicação de teste mede o número de operações de negócio por segundo, e reporta a média. Obviamente, esse número é um parâmetro artificial, mas é bom o suficiente para comparação.
# |
Tamanho do BD (GB) |
Performance (SATA RAID1) |
1 |
9,04 |
494,73 |
2 |
10,80 |
491,94 |
3 |
13,00 |
480,36 |
4 |
15,50 |
469,11 |
5 |
17,30 |
446,42 |
6 |
19,90 |
431,61 |
7 |
21,60 |
426,85 |
8 |
24,20 |
424,5 |
9 |
26,00 |
414,04 |
10 |
28,60 |
409,14 |
11 |
30,30 |
407,97 |
Como se pode observar, existe uma lenta degradação de performance conforme o tamanho da base aumenta – quanto maior a base de dados, mais lenta será (no mesmo hardware). Não há grande degradação de performance quando a base de dados ultrapassa a quantidade de RAM. O crescimento da base de dados de 9GB para 30GB leva praticamente a 20% de perda de performance.
Bases de dados Firebird com 30GB atualmente são facilmente encontradas pelo mundo afora, e continuam crescendo com o passar do tempo.
E o que acontecerá com a performance do banco, quando a base se tornar maior? Ou melhor, MUITO MAIOR!
- BANCO DE DADOS 1.77 TERABYTES
Para responder a pergunta anterior, decidimos realizar um teste com uma base de 1.77 Terabytes, no mesmo hardware, com a mesma configuração.
- PROCESSO DE CARREGAMENTO DOS DADOS
A carga durou 566.448 segundos – 157 horas, 6.55 dias. É muito tempo, mas a media de velocidade de carga foi de 3.28MB/seg
Tamanho da base, Gb |
Tempo de carga, seg |
Velocidade de carga, MB/seg |
1813,969025 |
566448 |
3,279214122 |
- PERFORMANCE DO BANCO DE 1,77 TERABYTE
Após a carga, realizamos novamente o teste de performance, dessa vez com a base de 1.77TB.
O resultado confirma que há uma lenta e estável queda de performance no Firebird – enquanto a base de dados cresceu 60 vezes (de 30GB para 1.7713GB), a queda de performance foi de 2.4 vezes (de 407 para 169 pontos).
Não é comum que uma base de dados cresça tanto sem que se melhore o hardware do servidor, mas mesmo nessa situação, o Firebird continua funcionando.
# |
Tamanho do BD (GB) |
Performance (SATA RAID1) |
1 |
9,04 |
494,73 |
2 |
10,80 |
491,94 |
3 |
13,00 |
480,36 |
4 |
15,50 |
469,11 |
5 |
17,30 |
446,42 |
6 |
19,90 |
431,61 |
7 |
21,60 |
426,85 |
8 |
24,20 |
424,5 |
9 |
26,00 |
414,04 |
10 |
28,60 |
409,14 |
11 |
30,30 |
407,97 |
12 |
1813,969025 |
169,33 |
Após completar a série de testes com um hardware de baixo custo, decidimos checar como seria o resultado usando outro tipo de tecnologia de armazenamento, e instalamos um drive SSD no mesmo servidor.
- TESTANDO O BANCO DE DADOS DE 1,77 TERABYTES COM DRIVES SSD
Foi instalado um drive Plextor PX-256M M5 Pro, e executados a mesma série de testes (com exceção da base de 1.77TB), com as mesmas configurações.
Os resultados foram adicionados no gráfico comparativo com os dispositivos SATA, conforme figura ao lado.
O tempo de carga no drive SSD é praticamente o mesmo do SATA. Isso é esperado, pois a velocidade de escrita sequencial é praticamente a mesma entre drives SATA e SSD.
- PERFORMANCE
Como podemos observar, a performance com operações de I/O randômicas mostra uma performance 8x melhor para o drive SSD. Nossa experiência com clientes mostra que drives SSD são de 30 a 50% mais rápidos no uso de aplicações reais, mas um ganho de 8x é tremendamente alto.
No entanto, esse teste é artificial e especialmente desenhado para simular uma alta carga de operações de OLTP, com muitos updates e deletes, mas sem grandes recuperações de informação. As aplicações de bases de dados mais comuns não trabalham dessa forma todo o tempo. Isso explica porque o SSD mostra um resultado tão bom nesse caso específico.
- CONCLUSÃO DOS TESTES
Primeiro – a performance do Firebird não apresenta queda acentuada relacionada a alguma restrição de tamanho. No mesmo hardware, a performance terá uma degradação lenta com o crescimento da base de dados. Essa degradação pode ser compensada com o tuning da configuração do Firebird ou com um upgrade inteligente de hardware.
Segundo – comprovamos que mesmo bases de dados gigantes (1.7TB) funcionarão em um hardware de baixo custo, com uma queda de performance significativa mas ainda aceitável.
Terceiro – SSD é muito bom para uso com aplicações OLTP. Provavelmente, é a opção de menor custo para aumentar a performance no momento. Obviamente, usar um SSD não resolverá os problemas relativos à queries com planos de acesso ruins e índices ineficientes, mas pode aumentar a performance de forma geral.
- DETALHAMENTO DOS TESTES
- TABELAS
Na tabela abaixo listamos as tabelas da base de dados com suas principais características. Os dados foram obtidos com o gstat -a -r e interpretados pelo IBAnalyst.
Tabela | Records | RecLength, bytes | Data Pages | Table size, Mb | Indices size, Mb | Total % |
ORDER_LINE | 6300024797 | 60.09 | 38880344 | 607505.3 | 50582.3 | 34 |
STOCK | 2100000000 | 298.88 | 43783806 | 684121.9 | 15809.61 | 39 |
ORDERS | 630004141 | 29.00 | 2692324 | 42067.56 | 4250.38 | 2 |
HISTORY | 630000434 | 48.77 | 3446455 | 53850.86 | 0.00 | 3 |
CUSTOMER | 630000000 | 577.52 | 24226054 | 378532.0 | 8675.78 | 21 |
NEW_ORDER | 188999981 | 13.00 | 623764 | 9746.31 | 1260.84 | 1 |
DISTRICT | 210000 | 103.92 | 1860 | 29.06 | 1.27 | ~0 |
ITEM | 100000 | 82.73 | 756 | 11.81 | 0.52 | ~0 |
WAREHOUSE | 21000 | 97.90 | 179 | 2.80 | 0.11 | ~0 |
Como podemos observar, a maior tabela é a ORDER_LINE – contendo mais de 6 bilhões de registros. Seu tamanho é de cerca de 600Gb sendo que 50GB são ocupados por índices. Ela ocupa 34% do tamanho total da base de dados.
A tabela STOCK também é imensa – cerca de 2 bilhões de registros. Apesar do número de registros ser menor do que a tabela ORDER_LINE, a STOCK ocupa ~680Gb na base de dados (39%), pelo fato do comprimento dos registros na tabela STOCK ser 298.88 bytes contra apenas 60.09 bytes na ORDER_LINE. Da mesma forma, o tamanho dos índices associados a tabela STOCK é de apenas 15Gb.
A terceira maior tabela, CUSTOMER, tem um comprimento de registro ainda maior – 577.52 bytes, e ocupa 378Gb (21%) com apenas 630 milhões de registros.
- ÍNDICES
Existem poucos índices nessa base de dados, pois foi modelada apenas para testes – a maioria das tabelas tem apenas um índice – a chave primária. No mundo real, os desenvolvedores criam diversos índices para servir a necessidades especiais, mas aqui, limitamos os índices para nos concentrar na velocidade das inserções e atualizações dos dados – como resultado, o tamanho do índice representa apenas 5-10% do tamanho da tabela, quando geralmente o cenário mais comum é de 30-50% (se mais de 50% do tamanho de uma base de dados é ocupada por índices, considere remodelar a base de dados, ou remover índices desnecessários).
Na tabela abaixo listamos todos os índices da base de dados e suas características:
Index | Table | Depth | Keys # | Key Len, bytes | # of unique keys | Size, Mb |
ORDER_LINE_PK | ORDER_LINE | 4 | 6300024797 | 1.41 | 6300024797 | 50582.34 |
STOCK_PK | STOCK | 4 | 2100000000 | 1.00 | 2100000000 | 15809.61 |
ORDERS_PK | ORDERS | 3 | 630004141 | 1.01 | 630004141 | 4250.38 |
CUSTOMER_LAST | CUSTOMER | 3 | 630000000 | 0.00 | 1000 | 4029.64 |
CUSTOMER_PK | CUSTOMER | 3 | 630000000 | 1.01 | 630000000 | 4646.14 |
NEW_ORDER_PK | NEW_ORDER | 3 | 188999981 | 1.01 | 188999981 | 1260.84 |
DISTRICT_PK | DISTRICT | 2 | 210000 | 1.37 | 210000 | 1.27 |
ITEM_PK | ITEM | 2 | 100000 | 1.00 | 100000 | 0.52 |
WAREHOUSE_PK | WAREHOUSE | 2 | 21000 | 1.00 | 21000 | 0.11 |
Todos os índices possuem um tamanho de chave reduzido – a maior é 1.41, significando que o índice tem um índice de compressão bastante efetivo – por exemplo, a o índice primário da tabela ORDER_LINE contém 6 bilhões de chaves em 50Gb de espaço. Um resultado muito bom.
Existem 2 índices com profundidade igual a 4. Isso significa que o Firebird precisa fazer 4 leituras em páginas de índices para encontrar o valor desejado. É recomendado que a profundidade dos índices não seja maior que 3. Se for maior, o tamanho da página da base de dados deve ser aumentado. No entanto, essa base de dados já está com o tamanho de página no limite (16kb), portanto, teremos que viver com isso.
- AQUECIMENTO
Antes de continuarmos e falarmos de grandes consultas, vamos “aquecer” a base de dados. Quando a base de dados é grande, os dados das tabelas de sistema associadas aos objetos do banco de dados também são grandes, e leva algum tempo para que o Firebird coloque as páginas de sistema no cache. Por exemplo, a tabela ORDER_LINE tem 10.110 páginas de ponteiro. “Aquecimento” é necessário para qualquer base de dados grande.
Com a base “fria”, a execução das queries levará muito mais tempo do que com a base “aquecida”.
Para aquecer o cache do banco de dados, vamos executar uma série de consultas simples, para ler os dados de sistema para o cache:
select first 1 * from ORDER_LINE;
select first 1 * from STOCK;
select first 1 * from customer;
select first 1 * from ORDERS;
select first 1 * from NEW_ORDER;
Isso é suficiente para uma base com modelagem tão simples. Para bases de dados mais complexas, com centenas de tabelas, o “aquecimento” pode ser mais complexo, e precisa ser bem pensado. (Veja na figura ao lado, o consumo de memória do processo do Firebird (Firebird SuperServer 2.5.2 64 bit)).
- QUERIES
Após o “aquecimento”, vamos executar diversas consultas típicas para simular o uso normal de um sistema. Vejamos o tempo de resposta para essas consultas, e o número de operações de leitura.
Query | Plan and stats | Description |
select first 10 w_id, w_name, c_id, c_last from WAREHOUSE, customer where c_w_id = w_id and c_w_id = 10000 |
PLAN JOIN (WAREHOUSE NATURAL, CUSTOMER INDEX (CUSTOMER_PK))STATISTICS Current memory = 166919744 Delta memory = 5616 Max memory = 166977488 Elapsed time= 0.08 sec Buffers = 10000 Reads = 1 Writes 0 Fetches = 51 |
Junção da tabela WAREHOUSE (21000 records) com a CUSTOMER (630 million records), com a condição de pegar um armazém específico |
select count(*) from WAREHOUSE, customer where c_w_id = w_id and c_w_id = 10000 |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (CUSTOMER_PK))COUNT ============ 30000STATISTICS Current memory = 166918560 Delta memory = -1184 Max memory = 166977488 Elapsed time= 0.16 sec Buffers = 10000 Reads = 1175 Writes 0 Fetches = 60040 |
Contagem de registros para a query anterior. |
SELECT first 10 * FROM ORDER_LINE WHERE OL_W_ID = 10050 |
PLAN (ORDER_LINE INDEX (ORDER_LINE_PK))STATISTICS Current memory = 167013640 Delta memory = 95080 Max memory = 167055968 Elapsed time= 0.80 sec Buffers = 10000 Reads = 10285 Writes 0 Fetches = 10424 |
Query na maior tabela da base – ORDER_LINE (~6billion records) com a condição de selecionar os registros de um armazém específico. Como a chave primária ORDER_LINE_PK é composta, e contém a ID do armazém (CONSTRAINT ORDER_LINE_PK: Primary key (OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER), o índice é efetivamente usado nessa consulta. |
SELECT count(*) FROM ORDER_LINE WHERE OL_W_ID = 10050; | PLAN (ORDER_LINE INDEX (ORDER_LINE_PK))COUNT ============ 299509STATISTICS Current memory = 167125464 Delta memory = -7160 Max memory = 167267976 Elapsed time= 3.41 sec Buffers = 10000 Reads = 1994 Writes 0 Fetches = 599170 |
Contagem da consulta anterior. A segunda consulta com os mesmos parâmetros sera muito mais rápida, mas queries com parâmetros diferentes apresentam um resultado similar. |
Select first 10 w_id, w_name, c_id, c_last from WAREHOUSE, CUSTOMER where c_w_id = w_id and (c_w_id > 8000) and (c_w_id < 10000) |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK), CUSTOMER INDEX (CUSTOMER_PK))STATISTICS Current memory = 167687664 Delta memory = -651888 Max memory = 168931400 Elapsed time= 0.19 sec Buffers = 10000 Reads = 31 Writes 0 Fetches = 63 |
Query com join e duas condições. |
select first 10 c1.C_ID, c1.C_FIRST, c1.C_LAST, o1.O_ID, o1.O_OL_CNT, i1.I_NAME, i1.I_PRICE, ol1.OL_AMOUNT from customer c1 join orders o1 on (c1.c_w_id = o1.O_w_ID and c1.C_D_ID = o1.O_D_ID and c1.C_ID = o1.O_C_ID) join ORDER_LINE ol1 on (ol1.ol_w_id = c1.C_W_ID and ol1.OL_D_ID = c1.C_D_ID and ol1.OL_O_ID = o1.O_ID) join Item i1 on (ol1.OL_I_ID = i1.i_id) where o1.o_d_id = 1 and o1.o_w_id = 1 and c1.c_id = 10; |
PLAN JOIN (C1 INDEX (CUSTOMER_PK), O1 INDEX (ORDERS_PK), OL1 INDEX (ORDER_LINE_PK), I1 INDEX (ITEM_PK))STATISTICS Current memory = 166807128 Delta memory = 6016 Max memory = 166879200 Elapsed time= 0.20 sec Buffers = 9999 Reads = 1 Writes 0 Fetches = 4960 |
Query para mostrar os detalhes de um cliente específico em um armazém e distrito específico. Demonstra a performance de junções mais complexas. |
- CONCLUSÃO DOS TESTES
Como podemos ver, a base de dados de 1.7 Terabytes apresenta uma boa performance com o Firebird, para consultas comuns. Se a query for bem desenhada e fizer uso de bons índices, a performance é boa até mesmo em bases de dados imensas. É claro, há pontos críticos, como o tempo de fetch para datasets muito grandes e longo tempo para operações de count (pelo fato do Firebird visitar todas as páginas para obter o número exato de registros para aquela query naquela transação especifica), mas esses pontos críticos são bem conhecidos pelos desenvolvedores mais experientes, e há métodos de se modelar a base de dados para contorna-los.
Consolidando a parceria técnica e comercial com a JB Software, a Soluvert esteve presente na 12º convenção anual de franquias.
+ ler tudoA Manutenção preventiva é a ação de controle e monitoramento dos equipamentos, com o objetivo de reduzir ou impedir falhas em seu desempenho.
+ ler tudo