2014-01-12 50 views
1

在我的Java应用程序中,我需要在硬盘上存储一个大表,因为我希望它是持久性的。在数据库中按阵列存储数组

我的第一次尝试是这样的: (我& J可以获得爬上300.000多,所以我有300.000^2双项数组,坠毁我的系统。)

stmt.executeUpdate("DROP TABLE IF EXISTS calculations;"); 
stmt.executeUpdate("CREATE TABLE calculations (factorA, factorB, result);"); 
double temp = 0; 
for (i = 0; i < datasource.size(); i++) { 
    for (int j = 0; j < datasource.size(); j++) { 
     if (i != j) { 
      temp = calc(datasource.get(i),datasource.get(j)); 
      stmt.execute("INSERT INTO calculations (factorA, factorB, result) VALUES ('"+i+"','"+j+"','"+temp+"')"); 
     } 
    } 
} 

现在,这可能会执行得非常慢,可能是因为SQL命令是一个字符串等。

我的新猜测是,它可能更好地首先计算结果,即10.000我的,然后将它们作为一个单元存储到数据库。

但在我尝试实现之前,有没有人有更好的主意?数据库使用不是强制性的,只是一个简单的访问和快速实施。

谢谢!

+0

请确保做你的批量插入作为交易; https://www.sqlite.org/lang_transaction.html - 这会将它们排列在SQLite引擎中,然后当您指出事务已完成时,将快速提交它们,而不是一个一个地执行它们。 –

+0

你需要快速写入还是快速读取?你要提取多少行?因子A +因子B的组成可用作指标吗? – elbuild

+0

其实我需要两个,快速写作和阅读,但在第一次写作。 – goetzmoritz

回答

1

尝试在每个内部添加每行n行(假设失败不是问题,例如,如果某些行无法插入,则可以继续而不回滚先前的行)。 声明oustide循环计数器:在外环

int n = 1000; //commit every 1000 rows, or you can tweak 
int count = 0; //counter for rows inserted 

开始交易。增加并检查计数器在内部循环

if(count % n == 0){ 
    //commit the transaction 
} 
count++ 

(Dont't忘记在外环重新打开事务)

http://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html

+0

谢谢,这实际上是我现在正在做的。但是,阅读很慢。我只是想,当你需要访问真正的BIG表时,SQLite是不可行的。但还有什么?! – goetzmoritz

+0

您的查询速度是否缓慢,尝试直接在Sql IDE中运行?尝试分页,读/写每一行,这是记忆效率。 – isah

1
 int BLOCK_SIZE = 15000; 
     stmt.executeUpdate("DROP TABLE IF EXISTS calculations;"); 
     stmt.executeUpdate("CREATE TABLE calculations (factor_idx text NOT NULL PRIMARY KEY,result text NOT NULL);"); 
     double temp = 0; 
     int block_ctr = 1; 
     StringBuilder sb = new StringBuilder(); 
     for (int i = 0; i < datasource.size; i++) { 
      for (int j = 0; j < datasource.size; j++) { 
       if (i != j) { 
        temp = calc(a, b); 
        // init the statement when counter = 1 
        if (block_ctr == 1) { 
         sb.append("INSERT INTO 'calculations' SELECT '" + i + "_" + j + "' AS 'factor_idx', '" + temp + "' AS 'result'"); 
        } 


        // then commit only every BLOCK_SIZE blocks 
        if (block_ctr <= BLOCK_SIZE) { 
         sb.append("UNION SELECT '" + i + "_" + j + "','" + temp + "'"); 
        } else { 
         stmt.execute(sb.toString()); 
         sb.setLength(0); // better then creating a new sb 
         block_ctr = 0; 
        } 
        block_ctr++; 
       } 
      } 
     } 

我降低和列I的数使用StringBuilder创建了一个组合语句。它应该快得多,可以使用您创建的连接i和j的主键列上的索引更快地进行读取。试着让我知道,我很好奇:)

+0

有趣,这只是停止,当我得到> 1 ...嗯,我需要弄清楚,为什么会发生。 – goetzmoritz

+0

当我将BLOCK_SIZE减小到500时,出现以下情况:[SQLITE_ERROR] SQL错误或缺少数据库(复合SELECT中的条目过多)。当我使用100作为BLOCK_SIZE时,它执行得更快,但不如预备语句快:-D – goetzmoritz

+0

我不知道复合SELECT中术语的限制......我想我学到了一些东西:)我认为我的想法是在单个索引列上更快的读取将比在i和j上选择更好。使用preparedStatement和我建议的表结构。 – elbuild