2012-06-07 102 views
2

我正在嘗試在Java程序中使用SQL數據庫。我製作了一張寬度爲7列,行數爲250萬的表格(我需要構建的下一個表格大約需要2億行)。我有兩個問題:構建SQL表的速度太慢(大約每分鐘2000行),並且搜索數據庫太慢(如果可能,我需要在一秒鐘內找到超過1億行,目前需要一分鐘)。我曾嘗試創建一個csv文件並導入它,但I can't get it to workJava SQL優化

我在我的電腦上使用xampp和phpMyAdmin(i5 + 6gb ram)。我有三個測試方法:createTable(),writeSQL()和searchSQL()。

CREATETABLE:

public static void createTable() { 
    String driverName = "org.gjt.mm.mysql.Driver"; 
    Connection connection = null; 
    try { 
     Class.forName(driverName); 

    } catch (ClassNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    String serverName = "localhost"; 
    String mydatabase = "PokerRanks4"; 
    String url = "jdbc:mysql://" + serverName + "/" + mydatabase;                   
    String username = "root"; 
    String password = ""; 

    try { 
     connection = DriverManager.getConnection(url, username, password); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    /////////////// 
    String table = "CREATE TABLE ranks(deckForm bigint(10) NOT NULL,rank0 int(2) NOT NULL,rank1 int(2) NOT NULL,rank2 int(2) NOT NULL,rank3 int(2) NOT NULL,rank4 int(2) NOT NULL,rank5 int(2) NOT NULL,PRIMARY KEY (deckForm),UNIQUE id (deckForm),KEY id_2 (deckForm))"; 
    try { 
     Statement st = connection.createStatement(); 
     st.executeUpdate(table); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    /////////////// 

    try { 
     connection.close(); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

writeSQL():

public static void writeSQL() { 
    String driverName = "org.gjt.mm.mysql.Driver"; 
    Connection connection = null; 
    try { 
     Class.forName(driverName); 

    } catch (ClassNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    String serverName = "localhost"; 
    String mydatabase = "PokerRanks4"; 
    String url = "jdbc:mysql://" + serverName + "/" + mydatabase;                   
    String username = "root"; 
    String password = ""; 

    try { 
     connection = DriverManager.getConnection(url, username, password); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


    /////////////// Prepared Statement with Batch 
    PreparedStatement statement = null; 
    String sql = "INSERT INTO ranks VALUES (? ,0, 0, 0, 0, 0, 0)";  
    long start = System.currentTimeMillis(); 
    try { 
     statement = connection.prepareStatement(sql); 
     for (int i = 0; i < 100; i++) { 
      for (int j = 0; j < 100; j++) { 
       statement.setLong(1, (i*100 + j)); 
       statement.addBatch(); 
      } 
      System.out.println(i); 
      statement.executeBatch(); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     if (statement != null) { 
     try { 
      statement.close(); 
     } catch (SQLException e) { 
     } // nothing we can do 
     } 
     if (connection != null) { 
     try { 
      connection.close(); 
     } catch (SQLException e) { 
     } // nothing we can do 
     }  
    } 
    System.out.println("Total Time: " + (System.currentTimeMillis() - start)/1000); 
    /////////////// 

} 

searchSQL():

public static void searchSQL() { 
    String driverName = "org.gjt.mm.mysql.Driver"; 
    Connection connection = null; 
    try { 
     Class.forName(driverName); 

    } catch (ClassNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    String serverName = "localhost"; 
    String mydatabase = "PokerRanks2"; 
    String url = "jdbc:mysql://" + serverName + "/" + mydatabase;                   
    String username = "root"; 
    String password = ""; 

    try { 
     connection = DriverManager.getConnection(url, username, password); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 



    /////////////// Option 1, Prepared Statement 
    ResultSet rs = null; 
    PreparedStatement pstmt = null; 
    String query = "SELECT rank0, rank1, rank2, rank3, rank4, rank5 FROM ranks WHERE deckForm = ?"; 
    long start = System.currentTimeMillis(); 
    try { 
     pstmt = connection.prepareStatement(query);    
     for (int i = 0; i < 100000; i++) {    
      pstmt.setLong(1, 1423354957); 
      rs = pstmt.executeQuery(); 
      while (rs.next()) {    
       int[] arr = {rs.getInt(1), rs.getInt(2), rs.getInt(3), rs.getInt(4), rs.getInt(5), rs.getInt(6)};    
      } 
     } 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    }      
    System.out.println("Total Time: " + (System.currentTimeMillis() - start)/1000); 
    /////////////// 

    /* 
    /////////////// Option 2 
    Statement st = null; 
    long start = System.currentTimeMillis(); 
    try { 
     st = connection.createStatement(); 
     ResultSet rs = null; 
     long deckForm = 1012213456;    
     for (int i = 0; i < 100000; i++) {   
      rs = st.executeQuery("SELECT rank0, rank1, rank2, rank3, rank4, rank5 FROM ranks WHERE deckForm = " + deckForm); 
      while (rs.next()) { 
       int[] arr = {rs.getInt(1), rs.getInt(2), rs.getInt(3), rs.getInt(4), rs.getInt(5), rs.getInt(6)}; 
      } 
     } 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    }   
    System.out.println("Total Time: " + (System.currentTimeMillis() - start)/1000); 
    /////////////// 
    */ 


    try { 
     connection.close(); 
    } catch (SQLException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

對不起這是這麼長時間。我嘗試了所有我能想到的方法來讓這個更快,但我無法弄清楚。有什麼建議麼?

+0

哪個RDBMS?哪個版本?你的桌子上是否有任何索引?查詢優化器告訴你關於'select'語句的是什麼? – 2012-06-07 22:39:47

回答

0

至於插入速度,您需要在插入之前禁用所有索引,並在完成後重新啓用它們。有關提高批量插入速度的詳細信息,請參閱Speed of Insert Statements

查詢速度可能受限於您的CPU和磁盤速度。您可能不得不在問題上拋出更多硬件。

+0

謝謝。我在創建表格時刪除了索引,甚至將它從7列降爲2,我仍然以相同的速度(約2000行/分鐘)看起來是否正確?我打算把它放在一臺比我的電腦快得多的服務器上,但我聽到有人說建立這個桌子應該比現在快得多。此外,fww在csv中構建這些數據需要大約一分鐘,而sql爲17小時 – user1441453

+0

這隻有33行/秒,似乎非常緩慢,除非I/O中存在瓶頸或系統負載過重。您可能會考慮編輯您的帖子以包含詳細的硬件規格(CPU型號和速度,總線速度,內存速度和容量,磁盤RPM和接口類型)。 –

0

建立SQL表太慢(約2000行/分鐘)

因此,對插入行的大量的觀點是肯定的使用Heap table,它的基本表,也它命名爲通常由CREATE TABLE創建的持久性頁面數組,它不是有效的搜索,因爲您的意思是搜索速度慢,但對於插入非常有效,因爲它將行添加到第一個空閒位置,即在表的末尾找到的位置。但另一方面,搜索是非常無效的,因爲不保證排序的項目/行。

搜索數據庫太慢(我需要找到100多萬 排在第二,如果可能的話,目前接管一分鐘)

因此,對於這個,你應該在創建表即搜索是有效的。在的情況下,如果你使用Oracle,所以它提供了物理實現許多建築例如Index organized tablesData clusteringClustered tables - 索引/散列/排序哈希... SQL Server我不知道,但也聚集表和MySQL我不確切地說,我不想告訴你最糟糕的事情。我不說,MySQL是壞的或者像Oracle例如差,但只是不適合例如提供對物理實現的一些技術,如Oracle


所以,我的意思是,這是相當很難說這種方法的一些建議但是你認真思考並研究一些關於數據庫系統的物理實現的東西,看看關係代數來優化你的語句,你應該創建哪種類型的表,@duffymo意思是說你可以用EXPLAIN PLANE FOR來解釋你的查詢執行計劃,根據結果​​進行優化。還如何使用indexes,它的強大數據庫的建設,但每個指標意味着更多的操作對數據庫的任何修改,從而很好地重新思考其屬性創建索引等

通過谷歌,你會發現有關數據建模許多有用的文章,物理實現等

問候的人,我希望好運

1

嗯,有一些改進,你可以做:

  1. 您要搜索每次你創建一個連接,WRI te或創建, 您應該使用池連接和數據源。
  2. 通過執行解釋計劃優化您的查詢,並優化您的表關係和索引。
  3. 您可以使用存儲過程並調用它們。

那麼這就是我可以幫助的,當然還有更多的提示。