ORA-14763: 无法将 FOR VALUES 子句解析为分区号
ORA-14763: Unable to resolve FOR VALUES clause to a partition number
我每天对 table 进行分区。
TABLE 姓名 MY_TABLE
列名 IN_TIME 时间戳
我想获取最近 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");
但是我遇到了异常"Caused by: java.sql.SQLException: ORA-14763: Unable to resolve FOR VALUES clause to a partition number"
请提出更好的方法。
绑定变量适用于值,但不能用于动态 select 对象,例如 table、视图或分区。在条件中使用绑定变量,希望分区p运行ing,或者为每个查询创建一个字符串。
绑定变量的限制是有道理的。解析查询可能是一项艰巨的工作 - 检查安全性、构建执行计划等。使用绑定变量可以让 Oracle 在下一个查询仅包含不同的文字时重新使用大部分工作。但是,如果 table 名称不同,则它必须放弃所有工作并完全重新解析该语句。所以在那种情况下绑定变量没有任何好处。
有了分区,似乎可能会有好处。分区只是 table 的一部分。权限不会改变,因此 Oracle 似乎可以通过允许绑定变量来节省一些工作。但是,有些对象可能因分区而异。例如,可以创建仅存在于某些分区上的索引。在那种情况下,一个分区的执行计划可能不适用于另一个分区。
(您仍然可以证明绑定变量分区名称可能有用。Oracle 具有一些动态执行计划功能,例如 FILTER 操作和自适应重新优化。因此它可能 创建一个适应不同分区的智能计划。但它没有。)
幸运的是,分区 p运行ing 通常与指定分区值一样有效。将查询更改为此应该 运行 一样快:
select * from my_table where some_date > trunc(:date_2_days_ago);
但是使用分区意味着从 table 中检索大部分行。在这种情况下,查询解析时间可能无关紧要。如果一个查询需要一分钟来处理,那么查询解析时间是 0.02 秒而不是 0.01 秒真的重要吗?如果是这种情况,那么硬编码的 SQL 语句也可以正常工作。
扩展 GurV 的评论。如果您分析 table 并仅使用常规的 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.
所以第一个虚拟分区和四个 "real" 分区:
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.
我每天对 table 进行分区。
TABLE 姓名 MY_TABLE 列名 IN_TIME 时间戳
我想获取最近 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");
但是我遇到了异常"Caused by: java.sql.SQLException: ORA-14763: Unable to resolve FOR VALUES clause to a partition number"
请提出更好的方法。
绑定变量适用于值,但不能用于动态 select 对象,例如 table、视图或分区。在条件中使用绑定变量,希望分区p运行ing,或者为每个查询创建一个字符串。
绑定变量的限制是有道理的。解析查询可能是一项艰巨的工作 - 检查安全性、构建执行计划等。使用绑定变量可以让 Oracle 在下一个查询仅包含不同的文字时重新使用大部分工作。但是,如果 table 名称不同,则它必须放弃所有工作并完全重新解析该语句。所以在那种情况下绑定变量没有任何好处。
有了分区,似乎可能会有好处。分区只是 table 的一部分。权限不会改变,因此 Oracle 似乎可以通过允许绑定变量来节省一些工作。但是,有些对象可能因分区而异。例如,可以创建仅存在于某些分区上的索引。在那种情况下,一个分区的执行计划可能不适用于另一个分区。
(您仍然可以证明绑定变量分区名称可能有用。Oracle 具有一些动态执行计划功能,例如 FILTER 操作和自适应重新优化。因此它可能 创建一个适应不同分区的智能计划。但它没有。)
幸运的是,分区 p运行ing 通常与指定分区值一样有效。将查询更改为此应该 运行 一样快:
select * from my_table where some_date > trunc(:date_2_days_ago);
但是使用分区意味着从 table 中检索大部分行。在这种情况下,查询解析时间可能无关紧要。如果一个查询需要一分钟来处理,那么查询解析时间是 0.02 秒而不是 0.01 秒真的重要吗?如果是这种情况,那么硬编码的 SQL 语句也可以正常工作。
扩展 GurV 的评论。如果您分析 table 并仅使用常规的 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.
所以第一个虚拟分区和四个 "real" 分区:
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.