Guia do desenvolvedor

Local Navigation

Desempenho de bancos de dados SQLite

Comparados com computadores, os aparelhos móveis fornecem um ambiente muito restrito para os bancos de dados SQLite. Para obter o desempenho ideal em um smartphone BlackBerry, considere as seguintes restrições:

  • O limite de memória dinâmica é 16 MB. Este limite refere-se à quantidade de RAM disponível para um banco de dados SQLite armazenar as estruturas de dados internas para esquemas e transações. O esquema de banco de dados inteiro é carregado na memória quando um banco de dados SQLite é aberto e persiste até que o banco de dados seja fechado.

  • O tamanho máximo de consulta SQL é 1 MB.

  • O número máximo de bancos de dados que podem estar abertos ao mesmo tempo é aproximadamente 50. A API Database usa um modo de cache compartilhado para fazer uso eficiente de memória para várias conexões ao mesmo banco de dados.

  • Somente uma conexão de leitura-gravação de banco de dados a um banco de dados SQLite pode ser feita por vez. Outras conexões de banco de dados são somente leitura.

Quando você usa os métodos Database.createBlobOutputStream e Database.createBlobInputStream para ler e gravar blobs, a memória disponível para o SQLite não restringe o tamanho do blob que você pode usar: seu conjunto de resultados não está limitado a 1 MB.

Você pode controlar uso de memória para cada conexão de banco de dados usando os seguintes métodos: Database.getCacheUsed, Database.getSchemaUsed e Database.getStatementUsed.

Entender o SQLite como um serviço

Em um smartphone BlackBerry, o SQLite é executado como um serviço. As operações de banco de dados usam uma ponte de tempo de execução para transferir dados entre Java e código nativo. Há um limite de 1 MB na quantidade de dados que pode ser transferida sobre a ponte de tempo de execução. A ponte de tempo de execução pode fornecer um excelente desempenho de operações de banco de dados, mas pode reduzir o desempenho caso não seja usada adequadamente.

Quando você cria uma instrução preparada para inserir ou atualizar dados, você deve usar os métodos Statement.executeInsert ou Statement.executeUpdate para reduzir o número de chamadas sobre a ponte de tempo de execução. Estes métodos executam as seguintes operações em código nativo:

  • Unir parâmetros SQL
  • Executar a instrução
  • Redefinir a instrução
  • Apagar as uniões
  • Retornar o último ID de linha inserido (somente executeInsert)

Quando você executa uma consulta que não retorna um conjunto de resultados e você não une parâmetros, você deve usar o método Database.executeStatement, que reduz o número de chamadas sobre a ponte de tempo de execução realizando as seguintes operações em código nativo:

  • Preparar a instrução
  • Executar a instrução
  • Finalizar a instrução

Quando você executa uma consulta que retorna conjuntos de resultados usando o método Statement.getCursor, você pode fazer uma busca prévia de um determinado número de linhas usando o método Statement.setCursorBufferSize. Esta abordagem reduz a utilização da ponte de tempo de execução. Quando o cursor passa pelo conjunto em buffer, um novo grupo de linhas é buscado automaticamente. Você pode recuperar um número de filas que um cursor realiza buffer com o método Statement.getCursorBufferSize.

Quando você recupera valores de número inteiro para usar como chaves em outra consulta, você pode usar os métodos Statement.getIntegers e Statement.getLongs. Estes métodos simplificam e otimizam a recuperação de colunas de números inteiros.

Prática recomendada: Otimizando o desempenho do banco de dados SQLite

Considere as seguintes diretrizes:

Prática recomendada Descrição

Usar o modo apropriado de diário

Por padrão, um diário de reversão é usado para registrar transações, mas você poder optar por usar um log de write-ahead em vez disso. O log de write-ahead fornece maior concorrência e é mais rápido que o diário de reversão na maioria dos casos porque a gravação para o banco de dados não bloqueia a leitura. No entanto, o log de write-ahead usa mais manipuladores de arquivo. O log de write-ahead usa até três manipuladores de arquivo que podem persistir por longos períodos, enquanto o diário de reversão usa um, ou de vez em quando dois, durante as transações de gravação. Para alterar o modo de geração de diário para um log de write-ahead, execute a instrução SQL "PRAGMA journal_mode = WAL;".

Considere reduzir as restrições de segurança para tabelas

Quando a integridade de dados não for uma preocupação, considere usar comandos Pragma para não especificar um diário e desativar o modo síncrono. Por exemplo, PRAGMA journal_mode=OFF e PRAGMA synchronous=OFF.

Teste

Se planeja criar um banco de dados com um esquema grande ou inserir blobs grandes, você deve testar o banco de dados em seus smartphones BlackBerry de destino para certificar-se de que os smartphones tenham memória adequada.

Armazenar o mínimo de dados possível

A maioria do tempo de processamento dos bancos de dados SQLite é dedicada a ler e gravar no armazenamento. Menos dados geralmente significa menos leitura e gravação. O mecanismo de banco de dados SQLite armazena em cache as páginas de banco de dados freqüentemente acessadas. Ao armazenar menos dados, você pode aumentar a probabilidade de o mecanismo de banco de dados SQLite recuperar dados solicitados mais rapidamente do cache, em vez de recuperar do acesso de armazenamento, que é relativamente lento.

Agrupar instruções com transações explícitas

Se você não usar transações explícitas, uma transação será criada para cada instrução que você executar. Este comportamento padrão é ineficiente. Requer que o arquivo de diário seja aberto, reaberto, editado e fechado para cada instrução. Com transações explícitas, você pode agrupar instruções para obter maior eficiência. Você pode executar várias instruções em uma transação colocando Database.beginTransaction e Database.commitTransaction ao redor de um grupo de instruções.

Criar índices eficientes

Os índices podem reduzir bastante o tempo requerido para varrer uma tabela. Aqui estão algumas observações sobre a criação de índices eficientes:

  • Os índices podem melhorar o desempenho de consultas somente-leitura como SELECT, mas podem reduzir o desempenho de consultas que modificam as linhas. Considere somente a indexação de tabelas que sejam atualizadas com menos frequência.
  • A ordem das colunas em um índice afeta o desempenho. As colunas que geralmente são usadas nas cláusulas WHERE devem ser colocadas primeiro, seguidas por colunas que geralmente são usadas em cláusulas ORDER BY.
  • Para as colunas contendo dados que são recuperados, crie um índice de cobertura.
  • Evite índices duplicados. O mecanismo de banco de dados SQLite cria automaticamente índices para colunas que têm limitações UNIQUE ou PRIMARY KEY.
  • As colunas declaradas como INTEGER PRIMARY KEY resultam em consultas mais rápidas porque possuem acesso direto a dados de tabela.

Minimizar o tamanho das linhas

Se houver uma coluna muito larga, coloque-a em uma tabela separada.

Armazenar blobs adequadamente

Se seus dados incluem blobs, você deve ler e gravá-los usando os objetos InputStream e OutputStream usando createBlobInputStream e createBlobOutputStream.

Você também pode considerar armazenar cada blob em uma tabela separada. Se os blobs forem muito grandes, você poderá armazená-los como arquivos fora do banco de dados (e armazenar o caminho para cada arquivo no banco de dados), mas esta prática introduz códigos extras para a busca de nomes de arquivos.

Usar tabelas temporárias

Se não precisar que os dados estejam disponíveis após reiniciar um smartphone, use a instrução CREATE TEMP TABLE em vez de CREATE TABLE.

Usar parâmetros SQL

Para executar um conjunto de instruções do mesmo formato, primeiro prepare uma instrução genérica que use parâmetros SQL. Você pode executar a instrução através da iteração pelos valores variáveis e vincular os valores às variáveis nomeadas em cada iteração.

Evitar subconsultas

Em alguns casos, o mecanismo de banco de dados SQLite armazena subconsultas que resultam em um arquivo temporário, o que pode retardar o processamento.

Desfragmentar o banco de dados

Use o comando VACUUM do SQLite para desfragmentar o banco de dados. Este processo também reduz o tamanho do arquivo do banco de dados.

Considerar a ordem das colunas nas instruções em tabela

A ordem das colunas em uma instrução em tabela afeta o desempenho, especialmente na ausência de um índice, porque o mecanismo de banco de dados SQLite varre as colunas na ordem definida na instrução em tabela. As colunas que contêm uma quantidade pequena de dados que são frequentemente acessados devem ser colocadas antes das colunas que contêm uma quantidade grande de dados que são acessados com menos frequência.

Usar métodos de operação em massa

Os seguintes métodos de operação em massa fazem uso eficiente da ponte de tempo de execução:

Para obter mais informações, consulte Entender o SQLite como um serviço.


Estas informações foram úteis? Gostaríamos de receber seus comentários.