Dúvidas/Problemas com performance com inserção de grande quantidade de registros em SQLite

2 respostas
aboult

Boa tarde,

Em meu aplicativo eu tenho um processo que faz requisições ao web service, chamando web método a web método e recebendo o retorno faz o tratamento necessário e grava no banco SQLite.
Hoje ela está funcionando dessa maneira:

Eu tenho uma Activity que chama um AsyncTask no AsyncTask eu faço a chamada:

Cliente cliente = new Cliente();
			cliente.setWsRepresentante(getSharedPreferences("PREFS_PRIVATE", MODE_PRIVATE).getInt("representante", 0));
			cliente.importarDados();
Na classe de cliente, eu tenho o método importarDados() que faz o Override do método da sua super classe que no caso é a Persistência:
@Override
	public void importarDados(){
		
		this.setWsNomeMetodo("GetClientes");
		this.setTabela(this.getClass().getSimpleName());
		this.setCamposPK(new String[]{"Identificacao"});
		super.importarDados();
	}

E na minha classe Persistencia eu tenho o método de importação(Hoje o processo está assim):

DataBase = new DadosBD(Singleton.getContextoAplicacao());
			SoapObject request = new SoapObject(this.getWsNameSpace(), this.getWsNomeMetodo());
			request.addProperty("representante", WsRepresentante);
			SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
			envelope.dotNet = true;
			envelope.implicitTypes = false;
			envelope.setOutputSoapObject(request);
			
			HttpTransportSE httpTransport = new HttpTransportSE(this.getWsUrl());
			httpTransport.call(this.getWsNameSpace() + "" + this.getWsNomeMetodo(), envelope);
			SoapObject result = (SoapObject) envelope.getResponse();
			
			if (result != null) {
				
				int resultCount = result.getPropertyCount();
				
				if(resultCount > 0){
					
					SoapObject objResult = new SoapObject();
					SoapObject objSoap = new SoapObject();
	
					objResult = (SoapObject) result.getProperty(1);
					if(objResult.getPropertyCount() > 0){
						
						objSoap = (SoapObject) objResult.getProperty(0);
						int propertyResultCount = objSoap.getPropertyCount();
		                
		                if (propertyResultCount > 0){
		                	
		                	this.Dados = new ContentValues();
		                    
		        	    	for (int currentProperty = 0; currentProperty < propertyResultCount; currentProperty++) {
		       	    		 
		                        SoapObject obj = (SoapObject) objSoap.getProperty(currentProperty);
		                        int attributeResultCount = obj.getPropertyCount();
		                        
		                        for(int index = 0; index < attributeResultCount; index++){
		                        	
		                        	PropertyInfo pi = new PropertyInfo();
		                        	obj.getPropertyInfo(index, pi);
		                        	this.Dados.put(pi.name.toString(), ((pi.getValue().toString().equals("anyType{}")?(""):(pi.getValue().toString()))));
		                        }
		                        
		                        for (int i = 0; i < this.getCamposPK().length; i++) {
		                        	if(condicao=="")
		                        		condicao = condicao + CamposPK[i].toString() + " = '" + this.Dados.get(CamposPK[i].toString()) + "'";
		                        	else
		                        		condicao = condicao + " AND " + CamposPK[i].toString() + " = '" + this.Dados.get(CamposPK[i].toString()) + "'";
		                        }
		                        
		                        this.setTabelaSelecao(condicao);
		                        RsAtual = DataBase.ExecSelect(Tabela, TabelaColunaComposta, TabelaSelecao, TabelaSelecaoArgumentos, TabelaGroupBy, TabelaHaving, TabelaOrderBy);
		                        
		                        if(RsAtual.moveToNext()) {
		                        	Encontrou = true;
		                        	RsAtual.close();
		                        }
		                        
		                        if(!Encontrou){
		                        	
		                        	DataBase.ExecInsert(Tabela, TabelaColunaSimples, Dados);
		                        	RsAtual.close();
		                        }else{
		                        	
		                        	this.setTabelaWhere(this.getTabelaSelecao().toString());
		                        	DataBase.ExecUpdate(Tabela, Dados, TabelaWhere, TabelaWhereArgumentos);
		                        	RsAtual.close();
		                        }
		                        condicao = "";
		                        Encontrou = false;
		                    }
		                }
					}
				}
			}

Só que por exemplo dependendo do método chamado no WS ele retorna coisa de 4000 mil registros e isso demora coisa de 3 minutos para ser inserido no banco de dados. E ainda não tenho só esse método são 10 tabelas a serem preenchidas e dá mais ou menos 10 minutos ou mais.

Pesquisando na internet me sugeriram InsertHelper() implementei o mesmo fazendo o uso de transações, mas como podem ver eu preciso receber os dados validar e se já existir no banco atualizar o registro. E não conseguia fazer update dos registros utilizando o InsertHelper(). Então pesquisando um pouco mais vi bastante gente falando que conseguiram arrumar o problema de performance utilizando SQLiteStatement que é bem mais leve e chega a inserir 4000 registros em milissegundos.

Então primeiramente qual seria a melhor maneira de fazer esse tipo de insert?

Só que hoje minha Classe de Persistencia faz o uso de uma instância do meu banco de dados. E nele eu tenho os meus métodos:

public void ExecInsert(String tableName, String tableColumn, ContentValues valores){
		
		database.insert(tableName, tableColumn, valores);
	}
	
	public void ExecUpdate(String tableName, ContentValues valores, String whereClause, String[] whereArgs){
		
		database.update(tableName, valores, whereClause, whereArgs);
	}
	
	public void ExecDelete(String tableName, String whereClause, String[] whereArgs){
		
		database.delete(tableName, whereClause, whereArgs);
	}

Alguém já teve problema semelhante?

Obrigado desde já.

2 Respostas

Marky.Vasconcelos

O que demora não é a consulta?

Normalmente é bem rapido para inserir. Separe a consulta da inserção e meça-os separadamente.

aboult
Marky.Vasconcelos:
O que demora não é a consulta?

Normalmente é bem rapido para inserir. Separe a consulta da inserção e meça-os separadamente.

Marky a consulta que você diz seria este trecho de código abaixo?

this.setTabelaSelecao(condicao);
		                        RsAtual = DataBase.ExecSelect(Tabela, TabelaColunaComposta, TabelaSelecao, TabelaSelecaoArgumentos, TabelaGroupBy, TabelaHaving, TabelaOrderBy);
		                        
		                        if(RsAtual.moveToNext()) {
		                        	Encontrou = true;
		                        	RsAtual.close();
		                        }

Então porque antes eu estava utilizando o método:

public void ExecInsert(String tableName, String tableColumn, ContentValues valores){
		
		database.insert(tableName, tableColumn, valores);
	}

Esse database é um:

dbHelper = new DbHelper(ctx, DadosBD.DataBaseName, null, DadosBD.DataBaseVersion, DadosBD.ScriptDataBaseCreate, DadosBD.ScriptDataBaseDelete);
    	database = dbHelper.getWritableDatabase();

E conforme pesquisei esse é o método mais lento de inserção, utilizando o ContentValues e fazendo a inserção dos registros.

Inclusive acabei de fazer um teste, fazendo a requisição da tabela Cidade que tinham 2805 registros.
Utilizando o SQLiteStatement ele fez essa inserção em bem menos de 30 segundos.

Antes demorava de 2 a 3 minutos.

Mas estou com problemas em como fazer da forma mais dinâmica possível até porque é 1 método para todas as tabelas.

Criado 18 de abril de 2013
Ultima resposta 18 de abr. de 2013
Respostas 2
Participantes 2