连续使用 sql "update" 时,Oracle 意外且快速地减速
Oracle slow down unexpected and rapidly when using sql "update" continuously
情况很简单,oracle中有一个table作为数据交换的"shared table"。 table 结构和记录数保持不变。在正常情况下,我不断将数据更新到此 table 中,其他进程读取此 table 以获取当前数据。
奇怪的是,当我的进程启动时,每条update语句执行的耗时大约是2ms。并且在一定时间后(比如 8 小时),每条语句的耗时增加到 10 ~ 20 ms。它使过程非常缓慢。
更新语句如下:
anaNum = anaList.size();
qry.prepare(tr("update YC set MEAVAL=:MEAVAL, QUALITY=:QUALITY, LASTUPDATE=:LASTUPDATE where YCID=:YCID"));
foreach(STbl_ANA ana, anaList)
{
qry.bindValue(":MEAVAL",ana.meaVal);
qry.bindValue(":QUALITY",ana.quality);
qry.bindValue(":LASTUPDATE",QDateTime::fromTime_t(ana.lastUpdate));
qry.bindValue(":YCID",ana.ycId);
if(!qry.exec())
{
qWarning() << QObject::tr("update yc failed, ")
<< qry.lastError().databaseText() << qry.lastError().driverText();
failedAnaList.append(ana);
}
}
the update statement using qt interface
导致 orcle 运行变慢的原因有很多,但我找不到解释的线索。
我在qt代码中从来不手动启动事务,也就是说每次更新语句后都会执行commit操作
更新频率约为每秒200条记录,但数量是随时间动态变化的。可能上一次增加到1000,下一次又降到10。
一旦每条语句的耗时达到10~20ms,就再也不会下降了。 只有重启oracle服务才能恢复到2ms耗时。(关闭或重启任何访问orcle的用户进程都没有用)
请告诉我如何解决或至少要检查什么。
您可以在 运行 时快速跟踪会话,然后在 运行 时缓慢跟踪会话。使用 sql 跟踪功能和 tkprof 来详细了解更新在每种情况下花费的时间,并查看发生了什么变化。
https://docs.oracle.com/cd/E25178_01/server.1111/e16638/sqltrace.htm#i4640
如果您需要帮助解释结果,您可以更新您的问题或提出新问题。
其次,通常单个记录更新不是在 Oracle 中进行更新的最佳方式。由于在准备查询之前您已经准备好许多要更新的记录,请查看 execBatch。
https://doc.qt.io/qt-4.8/qsqlquery.html#execBatch
这将更快地执行更新并且只发出一次提交。
最好的起点是查看 AWR and ASH 报告。
比较 "good" 和 "bad" 次的报告,您可以发现变化的原因。例如,这可以是 执行计划的更改或等待事件的增加 。一种可能的结果是,您看到的唯一变化是 数据库在客户端 上等待更多时间(即问题不在数据库中)。
无论如何,正如其他答案所诊断的那样,问题的根本原因似乎是循环更新。如果您的更新列表很长(比如超过 10-100 个条目),您可以通过使用 MERGE 在单个语句中更新整个列表来获益。
- 从您的列表中创建一个集合
- 将集合转换为 TABLE
- 在 MERGE 语句中使用此 table 更新行。
有关详细信息,请参阅 here。
情况很简单,oracle中有一个table作为数据交换的"shared table"。 table 结构和记录数保持不变。在正常情况下,我不断将数据更新到此 table 中,其他进程读取此 table 以获取当前数据。
奇怪的是,当我的进程启动时,每条update语句执行的耗时大约是2ms。并且在一定时间后(比如 8 小时),每条语句的耗时增加到 10 ~ 20 ms。它使过程非常缓慢。
更新语句如下:
anaNum = anaList.size();
qry.prepare(tr("update YC set MEAVAL=:MEAVAL, QUALITY=:QUALITY, LASTUPDATE=:LASTUPDATE where YCID=:YCID"));
foreach(STbl_ANA ana, anaList)
{
qry.bindValue(":MEAVAL",ana.meaVal);
qry.bindValue(":QUALITY",ana.quality);
qry.bindValue(":LASTUPDATE",QDateTime::fromTime_t(ana.lastUpdate));
qry.bindValue(":YCID",ana.ycId);
if(!qry.exec())
{
qWarning() << QObject::tr("update yc failed, ")
<< qry.lastError().databaseText() << qry.lastError().driverText();
failedAnaList.append(ana);
}
}
the update statement using qt interface
导致 orcle 运行变慢的原因有很多,但我找不到解释的线索。
我在qt代码中从来不手动启动事务,也就是说每次更新语句后都会执行commit操作
更新频率约为每秒200条记录,但数量是随时间动态变化的。可能上一次增加到1000,下一次又降到10。
一旦每条语句的耗时达到10~20ms,就再也不会下降了。 只有重启oracle服务才能恢复到2ms耗时。(关闭或重启任何访问orcle的用户进程都没有用)
请告诉我如何解决或至少要检查什么。
您可以在 运行 时快速跟踪会话,然后在 运行 时缓慢跟踪会话。使用 sql 跟踪功能和 tkprof 来详细了解更新在每种情况下花费的时间,并查看发生了什么变化。
https://docs.oracle.com/cd/E25178_01/server.1111/e16638/sqltrace.htm#i4640
如果您需要帮助解释结果,您可以更新您的问题或提出新问题。
其次,通常单个记录更新不是在 Oracle 中进行更新的最佳方式。由于在准备查询之前您已经准备好许多要更新的记录,请查看 execBatch。
https://doc.qt.io/qt-4.8/qsqlquery.html#execBatch
这将更快地执行更新并且只发出一次提交。
最好的起点是查看 AWR and ASH 报告。
比较 "good" 和 "bad" 次的报告,您可以发现变化的原因。例如,这可以是 执行计划的更改或等待事件的增加 。一种可能的结果是,您看到的唯一变化是 数据库在客户端 上等待更多时间(即问题不在数据库中)。
无论如何,正如其他答案所诊断的那样,问题的根本原因似乎是循环更新。如果您的更新列表很长(比如超过 10-100 个条目),您可以通过使用 MERGE 在单个语句中更新整个列表来获益。
- 从您的列表中创建一个集合
- 将集合转换为 TABLE
- 在 MERGE 语句中使用此 table 更新行。
有关详细信息,请参阅 here。