SELECT

时间:2017-05-19 12:16:48

标签: java mysql jdbc mysql-connector

这不是网上罕见的问题,但是我在MySQL服务器上做了一些优化工作来解决这个问题并且没有得到结果。所以起初我使用maven的包mysql:mysql-connector-java:6.0.6。 我试着运行这段代码:

try {
            mysqlConnection = DriverManager.getConnection(DatabaseUtils.mysqlUrl, DatabaseUtils.mysqlUser, DatabaseUtils.mysqlPassword);
            PreparedStatement valuesStatement = "SELECT * FROM `test` ORDER BY `id`"
            ResultSet cursor = valuesStatement.executeQuery();
            double value = 0;
            if (cursor.next())
                value = cursor.getDouble("value");
        } catch (SQLException sqlEx) {
            sqlEx.printStackTrace();
        } finally {
            cursor.close();
            pricesStatement.close();
        }

我在表格中有很多记录。这大约是百万,但每天增加大约一千条记录。当这个简单的例子执行30秒时,我感到非常惊讶。我google了我的问题,我发现只有“使用池”,“调整mysql服务器”,“尝试EXPLAIN SELECT”。但我注意到与行数相关的执行时间。所以我查看了驱动程序的代码并发现:

TextResultsetReader ::读():

        while(true) {
            if(row == null) {
                rows = new ResultsetRowsStatic(rowList, cdef);
                break;
            }

            if(maxRows == -1 || rowList.size() < maxRows) {
                rowList.add(row);
            }

            row = (ResultsetRow)this.protocol.read(ResultsetRow.class, trf);
        }

这意味着,即使我只想获取一行驱动程序,也会获取所有查询的行,并首先获取它。手册建议使用“setFetchSize”仅获取n条记录。但它不起作用。无论如何,驱动程序代码获取所有数据。然后我发现有两个记录集:ResultRowsStatic和ResultSetStreaming。第二个似乎只是在我需要查询时才获取数据。如何使用ResultRowsStreaming?我发现它只是代码。参数“fetchSize”必须等于-2147483648。我确实尝试过它有效!现在,如果大约0.0007秒,则执行“executeQuery()”的执行时间。这对我来说非常快。但是等等..我的剧本反正需要30秒。为什么?我在执行查询后调试了代码。之后只有两种“接近”的方法。什么可能出错?这是真的,“cursor.close()”需要剩下的时间。我再次查看库代码并到达ResultsetRowsStreaming :: close():

boolean hadMore = false;
int howMuchMore = 0;
synchronized(mutex) {
    while(this.next() != null) {
        hadMore = true;
        ++howMuchMore;
        if(howMuchMore % 100 == 0) {
            Thread.yield();
        }
    }

    if(conn != null) {
        if(!((Boolean)this.protocol.getPropertySet().getBooleanReadableProperty("clobberStreamingResults").getValue()).booleanValue() && ((Integer)this.protocol.getPropertySet().getIntegerReadableProperty("netTimeoutForStreamingResults").getValue()).intValue() > 0) {
            int oldValue = this.protocol.getServerSession().getServerVariable("net_write_timeout", 60);
            this.protocol.clearInputStream();

            try {
                this.protocol.sqlQueryDirect((StatementImpl)null, "SET net_write_timeout=" + oldValue, (String)this.protocol.getPropertySet().getStringReadableProperty("characterEncoding").getValue(), (PacketPayload)null, -1, false, (String)null, (ColumnDefinition)null, (GetProfilerEventHandlerInstanceFunction)null, this.resultSetFactory);
            } catch (Exception var9) {
                throw ExceptionFactory.createException(var9.getMessage(), var9, this.exceptionInterceptor);
            }
        }

        if(((Boolean)this.protocol.getPropertySet().getBooleanReadableProperty("useUsageAdvisor").getValue()).booleanValue() && hadMore) {
            ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(conn.getSession());
            eventSink.consumeEvent(new ProfilerEventImpl(0, "", this.owner.getCurrentCatalog(), this.owner.getConnectionId(), this.owner.getOwningStatementId(), -1, System.currentTimeMillis(), 0L, Constants.MILLIS_I18N, (String)null, (String)null, Messages.getString("RowDataDynamic.2") + howMuchMore + Messages.getString("RowDataDynamic.3") + Messages.getString("RowDataDynamic.4") + Messages.getString("RowDataDynamic.5") + Messages.getString("RowDataDynamic.6") + this.owner.getPointOfOrigin()));
        }
    }
}

此代码无条件地获取所有其余数据,仅用于记录我未提取的记录数。真的很奇怪。如果连接了记录器,那将是合理的。但在我的情况下,这段代码在30秒内计算出未经编辑的行,并且......对它没有任何作用。而这个问题我无法解决,因为没有参数可以告诉代码不计算行。

现在我不知道接下来该做什么。查询时间对我来说非常慢。例如,用于php的mysql驱动程序在0.0004-0.001秒内执行此查询。

那么使用mysql-connector for Java的人,请告诉我你有这些问题吗?如果没有,您可以发布任何示例,我该怎么做才能绕过上述问题?也许您使用其他连接器。请告诉我,该怎么办?

1 个答案:

答案 0 :(得分:1)

您的SQL查询说

SELECT * FROM test ORDER BY id

通过该查询,您可以指示MySQL服务器序列化 每个test表,并将其发送到Java程序。所以,MySQL服从。你有一张大桌子。所以你对MySQL的指令需要时间。是的,表中的行越多,所需的时间就越长。这不是JDBC或驱动程序的问题;这是你正在使用的SQL的一个问题。

从您的示例代码中可以看出,您想要一个列(名为value - 来自一行 - 第一行 - 在您的表中。您可以使用此SQL语句完成此操作:

 SELECT value FROM test ORDER BY id LIMIT 1

如果您的id列是表格的主键,则速度很快。

SQL的整点是允许您的表包含这么多行,在短时间内将它们全部提取到Java(或其他)程序中是不合理的。这就是SQL有WHERELIMIT条款的原因。