【问题标题】:ORA-01013 only on the first SELECT executionORA-01013 仅在第一次 SELECT 执行时
【发布时间】:2016-09-18 11:56:27
【问题描述】:

我有一个 java 程序,它使用 Spring 框架中的 JdbcTemplate 类在我的 Oracle 数据库上执行各种 SELECT 查询。

每次我在长时间停顿(1-2 天)后运行此程序时,它仍会阻止特定查询,并且在等待十分钟后出现超时异常,并出现 ORA-01013 错误。如果我再次运行该程序,它将正常运行而不会出现任何错误。

具体查询为:

SELECT ca.ARTICLE as article, r.COUNTRY as country, count(1) as total
    FROM CLIENT_ARTICLES ca 
      INNER JOIN ARTICLES aa ON a.ID = substr(ca.ARTICLE, 0, 8) 
      INNER JOIN SEAZON_P sp ON sp.PARAM = 'paramS1' AND substr(a.id, 1, 1) = sp.seazon 
      INNER JOIN REGISTER r ON r.id = ca.CLIENT_ID 
    WHERE ca.ACTION_DATE > sysdate - 5 AND ca.ACTION = 'I' 
    GROUP BY ca.ARTICLE, r.COUNTRY 
    ORDER BY ca.ARTICLE, r.COUNTRY;

这个查询的解释计划:

Plan hash value: 3771965889

-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name                       | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |                            |    11 |   759 | 71934   (2)| 00:14:24 |       |       |
|   1 |  SORT ORDER BY                   |                            |    11 |   759 | 71934   (2)| 00:14:24 |       |       |
|   2 |   HASH GROUP BY                  |                            |    11 |   759 | 71934   (2)| 00:14:24 |       |       |
|   3 |    NESTED LOOPS                  |                            |    11 |   759 | 71932   (2)| 00:14:24 |       |       |
|   4 |     NESTED LOOPS                 |                            |    40 |  1920 | 71932   (2)| 00:14:24 |       |       |
|   5 |      NESTED LOOPS                |                            |     2 |    78 | 71928   (2)| 00:14:24 |       |       |
|   6 |       PARTITION RANGE ITERATOR   |                            |     2 |    58 | 71924   (2)| 00:14:24 |   KEY |1048575|
|*  7 |        TABLE ACCESS FULL         | CLIENT_ARTICLES            |     2 |    58 | 71924   (2)| 00:14:24 |   KEY |1048575|
|   8 |       TABLE ACCESS BY INDEX ROWID| REGISTER                   |     1 |    10 |     2   (0)| 00:00:01 |       |       |
|*  9 |        INDEX UNIQUE SCAN         | PK_REGISTER                |     1 |       |     1   (0)| 00:00:01 |       |       |
|* 10 |      INDEX RANGE SCAN            | PK_ARTICLES                |    20 |   180 |     2   (0)| 00:00:01 |       |       |
|* 11 |     INDEX UNIQUE SCAN            | SEAZON_P_PK                |     1 |    21 |     0   (0)| 00:00:01 |       |       |
-------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

"   7 - filter(""CA"".""ACTION_DATE"">SYSDATE@!-3 AND ""CA"".""ACTION""='I')"
"   9 - access(""R"".""ID""=""CA"".""CLIENT_ID"")"
"  10 - access(""A"".""ID""=SUBSTR(""CA"".""ARTICLE"",0,8))"
"  11 - access(""SP"".""SEAZON""=SUBSTR(""CA"".""ID"",1,1) AND ""A"".""PARAM""='paramS1')"

执行查询的java代码:

public List<ArticleDTO> select(final String param) {
        List<ArticleDTO> articleList;
        String[] queryArgs = { param};
        super.jdbcTemplate.setFetchSize(20000);

        articleList = super.jdbcTemplate.query(SELECT_ARTICLES, queryArgs, this.articleRowMapper);

        return articleList;
    }

查询返回超过 80,000 个结果,但表非常大(> 1000 万行)。

有什么想法可能是问题吗?

谢谢!

【问题讨论】:

  • 让有数据库的人知道如何分析执行计划和创建缺失的索引。这也可能有助于调整数据库设计。像 a.ID = substr(ca.ARTICLE, 0, 8) 这样使用 substr 会阻止使用普通索引。您可能会摆脱功能索引,但我强烈建议您尽可能调整数据库设计。
  • 您能否验证该表在哪个字段上进行了分区?如果它在一个字段上分区(例如“action_month”),那么当您根据此类字段限制您的选择时,查询将仅从几个分区中检索数据,而不是全表扫描。
  • 表 CLIENT_ARTICLES 有以下分区: PARTITION BY RANGE ("ACTION_DATE") INTERVAL (NUMTODSINTERVAL (1, 'DAY')) (PARTITION "CLIENT_ARTICLES" VALUES LESS THAN (TO_DATE(' 2014-01 -01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) 段创建延迟
  • 我知道数据库设计一团糟,但真正的问题是 java 进程在第一次执行时被阻塞。

标签: java sql oracle spring-data query-optimization


【解决方案1】:

“我在等待 10 分钟后收到超时异常 ORA-01013 错误。如果我再次运行该程序将执行正常没有 任何错误”

ORA-01013 的含义是用户请求取消当前操作。所以最可能的解释是你的 Spring 层配置为十分钟后超时请求。但是第二次成功了,因为相关数据存储在数据库内存和/或操作系统缓存中。

那么你能做些什么来改善问题呢?钝器是检查超时参数并增加它。那将是最快的胜利,但可能会引起争议。减少执行时间是可取的,但会花费更长的时间,因为您需要进行一些调查和测试。

你的问题值得注意的是:

“查询返回超过 80.000 个结果,但表非常大(> 1000 万行)。”

您的解释计划中的rows 数字远不及这个数量级。优化器认为您在 CLIENT_ARTICLE 上的过滤器将在每个分区返回两行,对于如此大的表来说这似乎是可疑的低。因此,首先要检查的是表格统计信息的新鲜度。准确的统计数据有助于优化器找到一个好的执行计划。

另一件事是查询正在范围内的分区上运行全表扫描(以ca.ACTION_DATE &gt; sysdate - 5 为界,因此有五个或六个分区)。如果表很宽(很多列),那么当您只需要投影中的 ARTICLE 和过滤器中的 ACTION 时,这是一项昂贵的操作。如果这是您经常运行的查询,您可能会从 (ARTICLE, ACTION) 上的本地分区索引中受益。

【讨论】:

  • 有没有办法检查这个数据是否在数据库缓存中并清除它?
猜你喜欢
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
  • 2016-08-05
  • 1970-01-01
  • 2015-11-06
相关资源
最近更新 更多