Java筆記(一)–Eclipse 操作MySQL資料庫的效率問題

來源:互聯網
上載者:User

說明:這是最近學習java過程中遇到的一些問題,順便記錄下來,僅供參考。

去前幾天剛簡單的測試了一下ADO.NET操作SQL Server的效率,這兩天又來試試MySQL,用Eclipse來測試。

硬體環境同前。
軟體環境如下:
Eclipse Version : 3.4.0
MySQL Version : 5.0.51b-communicty-nt
JDBC Version: mysql-connector-java-5.1.6-bin.jar
Java Version: 1.6.0_07

測試代碼:
  就是簡單的往資料庫裡迴圈插入100萬條記錄,再全部讀出,最後刪除,看看花費多少時間。
   

Code
static Connection conn =null; 
  static Statement stmt=null;
  static ResultSet rs=null;
   
  // 測試連接MySQL數據庫,並讀取內容進行顯示
  private static boolean Conn_MySQL(){
  try{
  conn=DriverManager.getConnection("jdbc:mysql://localhost/test?" + 
"user=root&password=chu");
  Class.forName("com.mysql.jdbc.Driver").newInstance();
  try{
  stmt=conn.createStatement();
  return true;
  }
  catch(SQLException s_e){
  System.out.println("s_E"+s_e.getMessage().toString());
  return false;
  }
  }
  catch(SQLException s_e){
  System.out.println("串連錯誤!SQLException"+s_e.toString());
  return false;
  }
  catch(ClassNotFoundException c_e){
  System.out.println("串連錯誤!ClassNotFoundException"+c_e.toString());
  return false;
  }
  catch(InstantiationException in_e){
  System.out.println("串連錯誤!InstantiationException"+in_e.toString());
  return false;
  }
  catch(IllegalAccessException il_e){
  System.out.println("串連錯誤!IllegalAccessException"+il_e.toString());
  return false;
  }
  }
   
  // 執行SQL語句,要求資料庫已經串連好,本函數不負責檢測
  // 參數flag表示sql語句類型
  // 1:select 等要求返回結果的查詢語句
  // 2:insert,update,delete 等不要求返回查詢結果的更新語句
  //
  private static void ExeSQL(String sql,int flag){
  try{
  long begin_SQL_Ticks=System.currentTimeMillis();
  boolean sql_exe=false;
  //for(int i=0;i<1000000;i++){
  sql_exe=stmt.execute(sql);
  //}
  long end_SQL_Ticks=System.currentTimeMillis();
  if(sql_exe){
  //如果要求返回結果
  if(flag==1){
  rs=stmt.getResultSet();
  rs.first();
  while(!rs.isLast()){
  System.out.print(rs.getString(1)+" ");
  System.out.print(rs.getInt(2)+" ");
  System.out.print(rs.getInt(3)+"\n");
  rs.next();
  }
  rs.last();
  System.out.print(rs.getString(1)+" ");
  System.out.print(rs.getInt(2)+" ");
  System.out.print(rs.getInt(3)+"\n");
  long show_Ticks=System.currentTimeMillis();
  System.out.println("顯示共耗時:"+(show_Ticks-end_SQL_Ticks)+"毫秒");
  }
  }
  System.out.println("執行SQL語句共耗時:"+(end_SQL_Ticks-begin_SQL_Ticks)+"毫秒");
  }
  catch(SQLException s_e){
  System.out.println(s_e.getMessage());
  }
  }
   
  public static void main(String[] args) {
  if(Conn_MySQL()){  
  ExeSQL("insert into test_1 values('nalan',435,65786888)",2);
  ExeSQL("select * from test_1",1);
  ExeSQL("delete from test_1",2);

但奇怪的是,這次執行過程極為緩慢:大概20分鐘才插入5萬多條記錄!這在前面測試SQL Server中是不可想象的!前面的測試插入100萬條花費11分33秒,而且資料記錄要大很多,

下面是MySQL 5.1參考手冊裡給的一些說法:

INSERT語句的速度
插入一個記錄需要的時間由下列因素組成,其中的數字表示大約比例:
串連:(3)
發送查詢給伺服器:(2)
分析查詢:(2)
插入記錄:(1x記錄大小)
插入索引:(1x索引)
關閉:(1)

這不考慮開啟表的初始開銷,每個並發啟動並執行查詢開啟。
表的大小以logN (B樹)的速度減慢索引的插入。


加快插入的一些方法:
• 如果同時從同一個用戶端插入很多行,使用含多個VALUE的INSERT語句同時插入幾行。這比使用單行INSERT語句快(在某些情況下快幾倍)。如果你正向一個非空表添加資料,可以調節bulk_insert_buffer_size變數,使資料插入更快。參見5.3.3節,“伺服器系統變數”。
• 如果你從不同的用戶端插入很多行,能通過INSERT DELAYED語句加快速度。參見13.2.4節,“INSERT文法”。
• 用MyISAM,如果在表中沒有刪除的行,能在SELECT語句正在啟動並執行同時插入行。
• 當從一個文字檔裝載一個表時,使用LOAD DATA INFILE。這通常比使用很多INSERT語句快20倍。參見13.2.5節,“LOAD DATA INFILE文法”。
• 當表有很多索引時,有可能要多做些工作使得LOAD DATA INFILE更快些。使用下列過程:
有選擇地用CREATE TABLE建立表。
執行FLUSH TABLES語句或命令mysqladmin flush-tables。
使用myisamchk --keys-used=0 -rq /path/to/db/tbl_name。這將從表中取消所有索引的使用。
用LOAD DATA INFILE把資料插入到表中,因為不更新任何索引,因此很快。
如果只想在以後讀取表,使用myisampack壓縮它。參見15.1.3.3節,“壓縮表特性”。
用myisamchk -r -q /path/to/db/tbl_name重新建立索引。這將在寫入磁碟前在記憶體中建立索引樹,並且它更快,因為避免了大量磁碟搜尋。結果索引樹也被完美地平衡。
執行FLUSH TABLES語句或mysqladmin flush-tables命令。
請注意如果插入一個空MyISAM表,LOAD DATA INFILE也可以執行前面的最佳化;主要不同處是可以讓myisamchk為建立索引分配更多的臨時記憶體,比執行LOAD DATA INFILE語句時為伺服器重新建立索引分配得要多。
也可以使用ALTER TABLE tbl_name DISABLE KEYS代替myisamchk --keys-used=0 -rq /path/to/db/tbl_name,使用ALTER TABLE tbl_name ENABLE KEYS代替myisamchk -r -q /path/to/db/tbl_name。使用這種方式,還可以跳過FLUSH TABLES。

• 鎖定表可以加速用多個語句執行的INSERT操作:
LOCK TABLES a WRITE;
INSERT INTO a VALUES (1,23),(2,34),(4,33);
INSERT INTO a VALUES (8,26),(6,29);
UNLOCK TABLES;
這樣效能會提高,因為索引緩衝區僅在所有INSERT陳述式完成後重新整理到磁碟上一次。一般有多少INSERT語句即有多少索引緩衝區重新整理。如果能用一個語句插入所有的行,就不需要鎖定。
對於事務表,應使用BEGIN和COMMIT代替LOCK TABLES來加快插入。

鎖定也將降低多串連測試的整體時間,儘管因為它們等候鎖定最大等待時間將上升。例如:
Connection 1 does 1000 inserts
Connections 2, 3, and 4 do 1 insert
Connection 5 does 1000 inserts
如果不使用鎖定,2、3和4將在1和5前完成。如果使用鎖定,2、3和4將可能不在1或5前完成,但是整體時間應該快大約40%。

INSERT、UPDATE和DELETE操作在MySQL中是很快的,通過為在一行中多於大約5次連續不斷地插入或更新的操作加鎖,可以獲得更好的整體效能。如果在一行中進行多次插入,可以執行LOCK TABLES,隨後立即執行UNLOCK TABLES(大約每1000行)以允許其它的線程訪問表。這也會獲得好的效能。
INSERT裝載資料比LOAD DATA INFILE要慢得多,即使是使用上述的策略。
• 為了對LOAD DATA INFILE和INSERT在MyISAM表得到更快的速度,通過增加key_buffer_size系統變數來擴大 鍵高速緩衝區。參見7.5.2節,“調節伺服器參數”。

createStatement
Statement createStatement()
  throws SQLException
建立一個 Statement 對象來將 SQL 陳述式發送到資料庫。沒有參數的 SQL 陳述式通常使用 Statement 對象執行。如果多次執行相同的 SQL 陳述式,使用 PreparedStatement 對象可能更有效。 

使用返回的 Statement 對象建立的結果集在預設情況下類型為 TYPE_FORWARD_ONLY,並帶有 CONCUR_READ_ONLY 並發層級。 

返回:
一個新的預設 Statement 對象 
拋出: 
SQLException - 如果發生資料庫訪問錯誤

prepareStatement
PreparedStatement prepareStatement(String sql)
  throws SQLException
建立一個 PreparedStatement 對象來將參數化的 SQL 陳述式發送到資料庫。 

帶有 IN 參數或不帶有 IN 參數的 SQL 陳述式都可以被先行編譯並儲存在 PreparedStatement 對象中。然後可以有效地使用此對象來多次執行該語句。 

註:為了處理受益於先行編譯的帶參數 SQL 陳述式,此方法進行了最佳化。如果驅動程式支援先行編譯,則 prepareStatement 方法會將該語句發送給資料庫進行先行編譯。一些驅動程式可能不支援先行編譯。在這種情況下,執行 PreparedStatement 對象之前無法將語句發送給資料庫。這對使用者沒有直接的影響;但它的確會影響拋出某些 SQLException 對象的方法。 

使用返回的 PreparedStatement 對象建立的結果集在預設情況下類型為 TYPE_FORWARD_ONLY,並帶有 CONCUR_READ_ONLY 並發層級。 

參數:
sql - 可能包含一個或多個 '?' IN 參數預留位置的 SQL 陳述式 
返回:
包含先行編譯的 SQL 陳述式的新的預設 PreparedStatement 對象 
拋出: 
SQLException - 如果發生資料庫訪問錯誤

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.