【问题标题】:ORA-14763: Unable to resolve FOR VALUES clause to a partition numberORA-14763: 无法将 FOR VALUES 子句解析为分区号
【发布时间】:2017-12-19 04:13:24
【问题描述】:

我每天都对我的表进行分区。

表名称 MY_TABLE 列名 IN_TIME TIMESTAMP

我想获取最近 2 天分区的行。 我正在使用以下查询。

SELECT * FROM MY_TABLE PARTITION FOR  (TO_DATE('17-DEC-2017','DD-MON-YYYY'))
UNION
SELECT * FROM MY_TABLE PARTITION FOR  (TO_DATE('18-DEC-2017','DD-MON-YYYY'))

我正在尝试使用准备好的语句设置日期

preparedStatement.setString(1, "17-DEC-2017");
preparedStatement.setString(2, "18-DEC-2017");  

但我收到异常“原因:java.sql.SQLException: ORA-14763: 无法将 FOR VALUES 子句解析为分区号”

请提出任何更好的方法来做到这一点。

【问题讨论】:

  • 如果您只按这些日期过滤,Oracle 将自动找到正确的分区。您不需要放置分区子句。只需添加一个 where 子句。
  • SELECT * FROM MY_TABLE WHERE IN_TIME > SYSDATE-2 应该自动考虑分区,我们可能不必担心它。你说的对吗?
  • 是的。正是……
  • “ORA-14763”到底是什么意思?我们不能将准备好的语句用于与分区相关的查询?
  • 你问题中的错误信息很清楚

标签: sql oracle jdbc database-partitioning


【解决方案1】:

绑定变量适用于值,但不能用于动态选择对象,例如表、视图或分区。在条件中使用绑定变量,并希望进行分区修剪,或者为每个查询创建一个字符串。

考虑到绑定变量限制是有道理的。解析查询可能是一项艰巨的工作——检查安全性、构建执行计划等。使用绑定变量可以让 Oracle 在下一个查询仅使用不同的文字时重用大部分工作。但是,如果表名不同,则必须放弃所有工作并完全重新解析语句。所以在这种情况下绑定变量没有任何好处。

有了分区,它似乎可能会有好处。分区只是表的一部分。权限不会改变,因此 Oracle 似乎可以通过允许绑定变量来节省一些工作。但是,有些对象可能因分区而异。例如,可以创建仅存在于某些分区上的索引。在这种情况下,一个分区的执行计划可能不适用于另一个分区。

(您仍然可以提出绑定变量分区名称可能有用的案例。Oracle 具有一些动态执行计划功能,例如过滤操作和自适应重新优化。因此它可以创建一个智能计划适应不同的分区。但它没有。)

幸运的是,分区修剪通常与指定分区值一样有效。将查询更改为此应该运行得一样快:

select * from my_table where some_date > trunc(:date_2_days_ago);

但是使用分区意味着从表中检索大部分行。在这种情况下,查询解析时间可能无关紧要。如果查询需要一分钟来处理,那么查询解析时间是否需要 0.02 秒而不是 0.01 秒真的很重要吗?如果是这种情况,那么硬编码的 SQL 语句也可以正常工作。

【讨论】:

  • 谢谢@Jon Heller
【解决方案2】:

扩展 GurV 的评论。如果您分析您的表并仅使用常规 where 子句,您将获得所需的结果,并且您的代码将不依赖于物理分区结构,并且您将降低复杂性。

这是一个例子。首先设置您的情况:

SQL> create table my_table
  2  ( id      integer
  3  , in_time timestamp
  4  )
  5  partition by range (in_time) interval (interval '1' day)
  6  ( partition empty values less than (timestamp '2017-01-01 00:00:00')
  7  )
  8  /

Tabel is aangemaakt.

SQL> insert into my_table
  2   select rownum
  3        , timestamp '2017-12-16 00:00:00' + numtodsinterval(dbms_random.value * 4,'day')
  4     from dual
  5  connect by level <= 20
  6  /

20 rijen zijn aangemaakt.

SQL> exec dbms_stats.gather_table_stats(user,'my_table')

PL/SQL-procedure is geslaagd.

SQL> select * from my_table
  2  /

        ID IN_TIME
---------- ---------------------------------------------------------------------------
         1 16-12-2017 16:01:58,394131
         3 16-12-2017 11:20:52,900366
        13 16-12-2017 05:09:02,822579
        17 16-12-2017 22:25:01,376019
        19 16-12-2017 05:04:57,256665
         6 17-12-2017 00:03:17,346513
         9 17-12-2017 03:30:38,802184
        10 17-12-2017 22:38:55,227404
        16 17-12-2017 04:24:45,611941
         4 18-12-2017 14:58:42,373178
         5 18-12-2017 05:53:20,329375
         7 18-12-2017 19:45:22,642099
         8 18-12-2017 22:08:19,232150
        20 18-12-2017 07:48:00,259104
         2 19-12-2017 02:00:59,745124
        11 19-12-2017 16:35:24,682363
        12 19-12-2017 19:51:38,389568
        14 19-12-2017 10:09:45,821531
        15 19-12-2017 23:22:56,745163
        18 19-12-2017 20:21:31,664647

20 rijen zijn geselecteerd.

所以一个虚拟的第一个分区和四个“真实”分区:

SQL> select partition_name
  2       , high_value
  3       , num_rows
  4       , last_analyzed
  5    from user_tab_partitions
  6   where table_name = 'MY_TABLE'
  7  /

PARTITION_NAME    HIGH_VALUE                          NUM_ROWS LAST_ANALYZED
----------------- --------------------------------- ---------- -------------------
EMPTY             TIMESTAMP' 2017-01-01 00:00:00'            0 19-12-2017 09:46:23
SYS_P2752         TIMESTAMP' 2017-12-17 00:00:00'            5 19-12-2017 09:46:23
SYS_P2753         TIMESTAMP' 2017-12-20 00:00:00'            6 19-12-2017 09:46:23
SYS_P2754         TIMESTAMP' 2017-12-19 00:00:00'            5 19-12-2017 09:46:23
SYS_P2755         TIMESTAMP' 2017-12-18 00:00:00'            4 19-12-2017 09:46:23

5 rijen zijn geselecteerd.

现在解释了您的查询(PS:您真的需要对结果集进行排序吗?如果不需要,请使用 UNION ALL 而不是 UNION):

SQL> set serveroutput off
SQL> alter session set statistics_level = all
  2  /

Sessie is gewijzigd.

SQL> SELECT * FROM MY_TABLE PARTITION FOR  (TO_DATE('17-DEC-2017','DD-MON-YYYY'))
  2  UNION
  3  SELECT * FROM MY_TABLE PARTITION FOR  (TO_DATE('18-DEC-2017','DD-MON-YYYY'))
  4  /

        ID IN_TIME
---------- ---------------------------------------------------------------------------
         4 18-12-2017 14:58:42,373178
         5 18-12-2017 05:53:20,329375
         6 17-12-2017 00:03:17,346513
         7 18-12-2017 19:45:22,642099
         8 18-12-2017 22:08:19,232150
         9 17-12-2017 03:30:38,802184
        10 17-12-2017 22:38:55,227404
        16 17-12-2017 04:24:45,611941
        20 18-12-2017 07:48:00,259104

9 rijen zijn geselecteerd.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------
SQL_ID  41102hfzfq92x, child number 0
-------------------------------------
SELECT * FROM MY_TABLE PARTITION FOR
(TO_DATE('17-DEC-2017','DD-MON-YYYY')) UNION SELECT * FROM MY_TABLE
PARTITION FOR  (TO_DATE('18-DEC-2017','DD-MON-YYYY'))

Plan hash value: 3775556890

--------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |          |      1 |        |      9 |00:00:00.01 |      74 |       |       |          |
|   1 |  SORT UNIQUE             |          |      1 |      9 |      9 |00:00:00.01 |      74 |  2048 |  2048 | 2048  (0)|
|   2 |   UNION-ALL              |          |      1 |        |      9 |00:00:00.01 |      74 |       |       |          |
|   3 |    PARTITION RANGE SINGLE|          |      1 |      4 |      4 |00:00:00.01 |      37 |       |       |          |
|   4 |     TABLE ACCESS FULL    | MY_TABLE |      1 |      4 |      4 |00:00:00.01 |      37 |       |       |          |
|   5 |    PARTITION RANGE SINGLE|          |      1 |      5 |      5 |00:00:00.01 |      37 |       |       |          |
|   6 |     TABLE ACCESS FULL    | MY_TABLE |      1 |      5 |      5 |00:00:00.01 |      37 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------


20 rijen zijn geselecteerd.

这是另一种选择。请注意,这一次也使用了大致相同数量的缓冲区获取,并且它还使用了两次完整的分区扫描(参见开始:2)

SQL> select *
  2    from my_table
  3   where in_time >= timestamp '2017-12-17 00:00:00'
  4     and in_time < timestamp '2017-12-19 00:00:00'
  5  /

        ID IN_TIME
---------- ---------------------------------------------------------------------------
         6 17-12-2017 00:03:17,346513
         9 17-12-2017 03:30:38,802184
        10 17-12-2017 22:38:55,227404
        16 17-12-2017 04:24:45,611941
         4 18-12-2017 14:58:42,373178
         5 18-12-2017 05:53:20,329375
         7 18-12-2017 19:45:22,642099
         8 18-12-2017 22:08:19,232150
        20 18-12-2017 07:48:00,259104

9 rijen zijn geselecteerd.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------
SQL_ID  9bbraqwrk3pb2, child number 0
-------------------------------------
select *   from my_table  where in_time >= timestamp '2017-12-17
00:00:00'    and in_time < timestamp '2017-12-19 00:00:00'

Plan hash value: 3786094972

-----------------------------------------------------------------------------------------------
| Id  | Operation                | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |          |      1 |        |      9 |00:00:00.01 |      75 |
|   1 |  PARTITION RANGE ITERATOR|          |      1 |     12 |      9 |00:00:00.01 |      75 |
|*  2 |   TABLE ACCESS FULL      | MY_TABLE |      2 |     12 |      9 |00:00:00.01 |      75 |
-----------------------------------------------------------------------------------------------

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

   2 - filter(("IN_TIME"<TIMESTAMP' 2017-12-19 00:00:00.000000000' AND
              "IN_TIME">=TIMESTAMP' 2017-12-17 00:00:00.000000000'))


21 rijen zijn geselecteerd.

【讨论】:

  • 感谢您的精彩解释。我不接受这个作为答案,因为我从 java-oracle 的角度思考更多。从数据库的角度来看,这提供了很好的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-14
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-17
相关资源
最近更新 更多