这不是网上罕见的问题,但是我在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的人,请告诉我你有这些问题吗?如果没有,您可以发布任何示例,我该怎么做才能绕过上述问题?也许您使用其他连接器。请告诉我,该怎么办?
答案 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有WHERE
和LIMIT
条款的原因。