2010-08-27 74 views
3

我真的在這裏看到一個很大的問題。我正在使用MySQL在表格中存儲帶有詞性標記的句子。該表是這樣的:JDBC和MySQL讀取性能

+------------+------------------+------+-----+---------+-------+ 
| Field  | Type    | Null | Key | Default | Extra | 
+------------+------------------+------+-----+---------+-------+ 
| idTitle | varchar(25)  | NO | PRI | NULL |  | 
| idReview | int(10) unsigned | NO | PRI | NULL |  | 
| idSentence | int(10) unsigned | NO | PRI | NULL |  | 
| content | text    | NO |  | NULL |  | 
| POSInfo | text    | YES |  | NULL |  | 
+------------+------------------+------+-----+---------+-------+ 

這些表上的索引:

+-----------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table   | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-----------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| reviewsentences |   0 | PRIMARY      |   1 | idSentence | A   |   23 |  NULL | NULL |  | BTREE  |   | 
| reviewsentences |   0 | PRIMARY      |   2 | idTitle  | A   |  32087 |  NULL | NULL |  | BTREE  |   | 
| reviewsentences |   0 | PRIMARY      |   3 | idReview | A   |  2470720 |  NULL | NULL |  | BTREE  |   | 
| reviewsentences |   1 | fk_ReviewSentences_Reviews1 |   1 | idTitle  | A   |   983 |  NULL | NULL |  | BTREE  |   | 
| reviewsentences |   1 | fk_ReviewSentences_Reviews1 |   2 | idReview | A   |  494144 |  NULL | NULL |  | BTREE  |   | 
+-----------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 

我試圖讀取blong到一定的審查reviewsentences的將它們添加到審查對象。我正在通過JDBC訪問數據庫,並且這些讀取將永遠消失!我說26分鐘2分鐘!這是我使用來查詢數據庫中的Java代碼:如果我通過My​​SQL工作臺它需要0.296秒具有相同的查詢訪問相同的表

public List<Review> fillupReviews(List<Review> reviews, boolean tagged){ 

    try { 
     Statement stmt = dbConnection.createStatement() ; 


     for (Review review : reviews) { 
      ResultSet rs=null; 
      if(tagged==true){ 
       rs = stmt.executeQuery("SELECT idSentence, POSInfo FROM reviewsentences WHERE idTitle="+review.getMovieID()+" and idReview="+review.getReviewID()+";") ; 
      }else{ 
       rs = stmt.executeQuery("SELECT idSentence, content FROM reviewsentences WHERE idTitle="+review.getMovieID()+" and idReview="+review.getReviewID()+";") ; 
      } 

      while(rs.next()){ 
       review.addTaggedSentence(rs.getInt(1),rs.getString(2)); 
      } 
     } 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 

    return reviews; 
} 

?所以我的猜測是必須有嚴重錯誤!但我真的不知道出了什麼問題或要改變什麼來加速這件事情。請有人給我一個提示?

這是我再次,我終於找到解決方案!被稱爲準備聲明! < - 誰會猜到!?這裏是代碼:

public List<Review> fillupReviews(List<Review> reviews, boolean tagged){ 

     try { 

      PreparedStatement selectReview=null; 
      if(tagged==true){ 
       selectReview = dbConnection.prepareStatement("SELECT idSentence, POSInfo FROM reviewsentences WHERE idTitle= ? AND idReview= ?;"); 
      }else{ 
       selectReview = dbConnection.prepareStatement("SELECT idSentence, Content FROM reviewsentences WHERE idTitle= ? AND idReview= ?;"); 
      } 

      for (Review review : reviews) { 

       selectReview.setString(1, review.getMovieID()); 
       selectReview.setInt(2, review.getReviewID()); 

       ResultSet rs = selectReview.executeQuery(); 

       while(rs.next()){ 
        review.addTaggedSentence(rs.getInt(1),rs.getString(2)); 
       } 
       rs.close(); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 

     return reviews; 
    } 

現在這個洞的東西像地獄一樣運行(幾乎與MySQL Workbench的速度一樣[0.3秒])。我不明白爲什麼一個正常的陳述如此緩慢?有人有解釋嗎?

+0

一箇舊的,但爲解釋。 preparedStatement只能由SGBD編譯一次,然後將參數設置到正確的位置(不是使用java,而是使用sgbd)。每個查詢執行都會編譯一條簡單的語句。這個編譯需要時間。 – AxelH 2016-07-05 10:56:56

回答

1

首先,您是否只計時調用此方法?

你從哪裏獲得數據庫連接,你計時只是執行查詢的時間或獲得連接的時間嗎?

您使用連接池嗎?也許有一個問題,嘗試先獲得一個新的連接來縮小它。無論它不應該花這麼長時間,有些事情是錯誤的,我懷疑你的連接設置可能是java找到mysql的方式(是否是本地的,你是否使用dns等)。

此外,我會使用準備的語句,他們更安全,更好的表現。

另外你在用什麼驅動程序?

+0

我得到我的類的構造函數中的數據庫連接,像這樣this.dbConnection = MySQLConnectionFactory.getConnection(「moviereviews」);. Im時間只是直到rs = stmt.executeQuery(...返回的時間。不,我不使用連接池。數據庫運行一個相同的機器,其中的java代碼運行,所以我沒有你任何DNS。我正在使用的驅動程序http://www.mysql.com/downloads/connector/j/ – evermean 2010-08-27 12:51:58

+0

只是一個WAG,但是你的盒子裏有足夠的內存,你是否像瘋了似的交換?是否有可能JVM正在使用你的內存通常是mysql會使用的嗎? – Joelio 2010-08-27 13:59:02

+0

Wheres the love,看到我對於準備語句的建議.... – Joelio 2010-08-27 19:44:23

0

如果它是本地MySQL服務器,那麼我會嘗試評論MySQL提取,並用虛代碼替換以檢查代碼的性能(不要忘記使用GetMovieId()等東西))。

0

註釋掉review.addTaggedSentence(rs.getInt(1),rs.getString(2));這是否還需要那麼多時間?

您沒有關閉ResultSet,您需要在while(rs.next())完成後執行rs.close()

打印出您在Java中運行的實際SQL - 您是否100%確定它是在MySQL工作臺中運行的相同查詢?

您還在for (Review review : reviews)中運行查詢,因此運行了多少個查詢?

你不告訴我們什麼需要2.36分鐘。所以 - 配置文件或在你的java應用程序中做一些簡單的System.out.println(),這樣你就可以確定你實際運行的是什麼SQL,以及它們中有多少運行。

+0

1.如果註釋掉了review.addTaggedSentence(rs.getInt(1),rs.getString(2));它並不能幫助:( 2.增加rs.close()還是一樣。 3.經過和是100%肯定! 4.準確159598!但是這需要2分鐘,每單之一!所以, p roblem不是159598的數字,但是每個查詢需要2分鐘:( )5. rs = stmt.executeQuery(...)需要2分鐘才能返回將值分配給評論的部分。 – evermean 2010-08-27 12:46:41

+0

當你在MySQL工作臺中這樣做時,你確定你真的得到了159598行嗎?運行mysql上的'mysqladmin pr'狀態,看看你的java代碼執行時它正在做什麼 – nos 2010-08-27 12:49:30

0

您好像有2470720條評論。與在Mysql Workbench中本地運行相比,遠程運行(在您的代碼中)將花費更長時間來查詢,返回並傳輸多個值。

Mysql工作臺可能會提取結果的計數並對它給出的分頁進行分頁 - 只根據需要返回結果;另外,您的工作臺可以在連接上啓用壓縮,而JDBC不會,因此創建更快的連接。

0

首先。你能詳細說明你的代碼需要2m ++的哪一部分。它是在聲明stmt.executeQuery(String)或另一部分?

我自己碰巧遇到了一個大的主要數據庫管理系統的問題。但是我的數據大於150K。不幸的是,我沒有針對您的問題的現成解決方案。但是我做了一些足跡。

  1. 我試圖從驅動程序切換到驅動程序。請記住,某些驅動程序可能運行得更快,但它會要求您犧牲可移植性。
  2. 我試圖從硬編碼連接切換到連接池。不幸的是,這並沒有真正的幫助。
  3. 我試着不使用VARCHAR字段上的「WHERE」子句。
  4. 我試圖索引一些字段,我經常「在哪裏」d
  5. 我試圖使用Prepared Statement來確保DBMS不會重新散列相同的查詢。

還有其他的事情,但我認爲他們是DMBS特定的。

+0

是的,它的stmt.executeQuery()部分需要這麼長時間。感謝您的回答! – evermean 2010-08-27 12:39:48