【问题标题】:JDBC & MySQL read performanceJDBC 和 MySQL 读取性能
【发布时间】:2010-08-27 11:56:37
【问题描述】:

我在这里似乎真的有一个大问题。我正在使用 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      |         |
+-----------------+------------+-----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

我正在尝试阅读属于某个评论的评论句子,并将它们添加到评论对象中。我正在通过 JDBC 访问数据库,读取需要永远!!我说 2 分钟 26 行!这是我用来查询数据库的java代码:

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;
}

如果我通过 MySQL Workbench 使用相同的查询访问同一个表,则需要 0.296 秒?所以我的猜测是一定有什么严重的错误!但我真的看不出哪里出了问题或改变什么来加速这个该死的事情。请问有人可以给我一个提示吗?

又是我,我终于找到了解决办法!叫做Prepared Statement!!

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 秒])。我不完全明白为什么正常的陈述如此缓慢?有人对此有解释吗?

【问题讨论】:

  • 一个旧的,但为了解释。 SGBD 只编译一次preparedStatement,然后将参数设置到正确的位置(不是在java 中,而是在sgbd 中)。一个简单的语句将在每次查询执行时编译。这个编译需要时间。

标签: java mysql performance jdbc


【解决方案1】:

首先,你是在计时这个方法调用吗?

你从哪里得到数据库连接,你是只计时执行查询的时间还是获得连接的时间?

您是否使用连接池?可能那里有问题,请先尝试建立新连接以缩小范围。

不管它不应该花这么长时间,还是有问题,我怀疑你的连接设置可能是 java 找到 mysql 的方式(它是本地的,你是否使用 dns 等)。

我也会使用准备好的语句,它们更安全,性能更好。

还有你用的是什么驱动?

【讨论】:

  • 我在类的构造函数中获得了数据库连接,如下所示 this.dbConnection = MySQLConnectionFactory.getConnection("moviereviews");。我正在计时直到 rs = stmt.executeQuery(... 返回。不,我不使用连接池。数据库在运行 java 代码的同一台机器上运行,所以我没有任何 dns。这是我正在使用的驱动程序mysql.com/downloads/connector/j
  • 只是一个 WAG,但是你的盒子有足够的内存吗,你在疯狂交换吗? JVM 是否可能正在耗尽您通常 mysql 会使用的内存?
【解决方案2】:

如果是本地 MySQL 服务器,那么我会尝试评论 MySQL fetch,并用虚拟代码替换以检查代码的性能(不要忘记使用 GetMovieId() 等东西)。

【讨论】:

    【解决方案3】:

    注释掉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,以及其中运行了多少。

    【讨论】:

    • 1.如果注释掉 review.addTaggedSentence(rs.getInt(1),rs.getString(2));它没有帮助 :( 2. 添加 rs.close() 仍然相同。3. 已检查,是的 100% 确定!4. 正好 159598!但每一个都需要 2 分钟!所以问题不在于数量159598 但每个查询需要 2 分钟 :( 5. rs = stmt.executeQuery(... 需要 2 分钟才能返回将值分配给审查的部分。
    • 当你在 MySQL 工作台中执行此操作时,你确定你真的得到了 159598 行吗?在开启 mysql 的机器上运行 mysqladmin pr 状态,看看你的 java 代码执行时它在做什么
    【解决方案4】:

    您似乎有 2470720 条评论。与在 Mysql Workbench 中本地运行相比,远程运行(在您的代码中)肯定会花费更长的时间来查询、返回和传输那么多值。

    Mysql 工作台可能会获取结果的计数并将它给你的内容分页——只在必要时返回结果;此外,您的工作台可以在 JDBC 未启用的情况下对连接启用压缩,从而创建更快的连接。

    【讨论】:

      【解决方案5】:

      首先。您能否详细说明代码的哪一部分需要 2m++。是在语句 stmt.executeQuery(String) 还是其他部分?

      我本人碰巧在大型主要 DBMS 中遇到了这个问题。但是我的数据大于 150K。不幸的是,我没有针对您的问题的现成解决方案。但是有一些我所做的事情的足迹。

      1. 我尝试从驱动程序切换到驱动程序。请记住,某些驱动程序可能运行得更快,但它要求您牺牲便携性。
      2. 我尝试从硬编码连接切换到连接池。不幸的是,它并没有真正的帮助。
      3. 我尝试不在 VARCHAR 字段上使用“WHERE”子句。
      4. 我试图索引一些我经常“WHERE”d的字段
      5. 我尝试使用 Prepared Statement 只是为了确保 DBMS 不会重新散列相同的查询。

      还有其他东西,但我认为它们是特定于 DMBS 的。

      【讨论】:

      • 是的,它的 stmt.executeQuery() 部分需要这么长时间。感谢您的回答!
      猜你喜欢
      • 2015-06-04
      • 1970-01-01
      • 2019-01-19
      • 2015-12-13
      • 1970-01-01
      • 2013-06-13
      • 2013-04-22
      • 1970-01-01
      • 2016-12-26
      相关资源
      最近更新 更多