在一次刷微博中偶然看到这么一个例子,下面是执行的语句信息:
-
SQL> select * from emp_p;
-
-
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
-
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
-
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
-
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
-
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
-
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
-
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
-
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
-
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
-
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
-
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
-
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
-
7870 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
-
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
-
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
-
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
-
-
14 rows selected.
-
-
SQL> select * from emp_p where empno=7870;
-
-
no rows selected
-
-
SQL>
加入where条件后查不出结果,而转换一下却可以:
-
SQL> select * from emp_p where to_char(empno)=7870;
-
-
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
-
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
-
7870 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
-
-
SQL>
这是什么情况呢, 隐式转换?
下面我们看一下 表结构信息:
-
SQL> desc emp_p
-
Name Null? Type
-
----------------------------------------------------------------------------------- -------- --------------------------------------------------------
-
EMPNO NOT NULL NUMBER(4) --类型
-
ENAME VARCHAR2(10)
-
JOB VARCHAR2(9)
-
MGR NUMBER(4)
-
HIREDATE DATE
-
SAL NUMBER(7,2)
-
COMM NUMBER(7,2)
-
DEPTNO NUMBER(2)
再看一下select * from emp_p where empno=7870的执行计划:
-
SQL> select * from table(dbms_xplan.display);
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------
-
Plan hash value: 1248329429
-
-
-------------------------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-
-------------------------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 87 | 1 (0)| 00:00:01 | | |
-
| 1 | TABLE ACCESS BY GLOBAL INDEX ROWID| EMP_P | 1 | 87 | 1 (0)| 00:00:01 | 2 | 2 |
-
|* 2 | INDEX UNIQUE SCAN | SYS_C0014288 | 1 | | 0 (0)| 00:00:01 | | |
-
-------------------------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
2 - access("EMPNO"=7870)
-
-
14 rows selected.
我们可以看到,该SQL语句查找的是表EMP_P中的分区P2, 好,下面我们看看该分区数据:
-
SQL> select * from emp_p partition(p2);
-
-
no rows selected
再次查看该表几个分区
-
SQL> set lines 150
-
SQL> select TABLE_OWNER,table_name,partition_name,PARTITION_POSITION from dba_tab_partitions where table_name='EMP_P';
-
-
TABLE_OWNER TABLE_NAME PARTITION_NAME PARTITION_POSITION
-
------------------------------ ------------------------------ ------------------------------ ------------------
-
SCOTT EMP_P P1 1
-
SCOTT EMP_P P2 2
-
SCOTT EMP_P P3 3
前面我们知道,分区表中有数据,下面我们看看其他分区是否有需要的数据
-
SQL> select * from emp_p partition(p1);
-
-
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
-
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
-
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
-
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
-
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
-
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
-
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
-
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
-
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
-
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
-
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
-
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
-
7870 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
-
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
-
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
-
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
-
-
14 rows selected.
-
-
SQL> select * from emp_p partition(p3);
-
-
no rows selected
-
-
SQL>
从上面内容可以看到,我们需要的数据在分区P1中,而执行查询语句的时候Oracle找的却是P2,那么下面就看看该分区表的分区机制(建表信息):
-
CREATE TABLE "SCOTT"."EMP_P"
-
( "EMPNO" NUMBER(4,0),
-
"ENAME" VARCHAR2(10),
-
"JOB" VARCHAR2(9),
-
"MGR" NUMBER(4,0),
-
"HIREDATE" DATE,
-
"SAL" NUMBER(7,2),
-
"COMM" NUMBER(7,2),
-
"DEPTNO" NUMBER(2,0),
-
PRIMARY KEY ("EMPNO")
-
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
-
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
-
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
-
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
-
TABLESPACE "USERS" ENABLE
-
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
-
STORAGE(
-
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
-
TABLESPACE "USERS"
-
PARTITION BY RANGE ("EMPNO")
-
(PARTITION "P1" VALUES LESS THAN (7000) SEGMENT CREATION IMMEDIATE
-
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
-
NOCOMPRESS LOGGING
-
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
-
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
-
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
-
TABLESPACE "USERS" ,
-
PARTITION "P2" VALUES LESS THAN (8000) SEGMENT CREATION DEFERRED
-
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
-
NOCOMPRESS LOGGING
-
STORAGE(
-
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
-
TABLESPACE "USERS" ,
-
PARTITION "P3" VALUES LESS THAN (9000) SEGMENT CREATION DEFERRED
-
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
-
NOCOMPRESS LOGGING
-
STORAGE(
-
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
-
TABLESPACE "USERS" )
从上面的信息我们可以看到,表EMP_P 根据列empno 分区,每个分区的限制如黄色部分。好,我们再看看刚查询语句:
select * from emp_p where empno=7870; 正常情况下该数据应该存放于分区P2,但却存放到分区p1上了。
上面的执行计划中也说明了,根据分区规则及where条件,Oracle会只会查找分区P2,下面我们通过类型转换再次查看。
-
SQL> select * from emp_p where to_char(empno)=7870;
-
-
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
-
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
-
7870 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
-
-
SQL>
查看该语句执行计划:
-
SQL> explain plan for select * from emp_p where to_char(empno)=7870;
-
-
Explained.
-
-
SQL> select * from table(dbms_xplan.display);
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------
-
Plan hash value: 2733612900
-
-
---------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-
---------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 87 | 3 (0)| 00:00:01 | | |
-
| 1 | PARTITION RANGE ALL| | 1 | 87 | 3 (0)| 00:00:01 | 1 | 3 |
-
|* 2 | TABLE ACCESS FULL | EMP_P | 1 | 87 | 3 (0)| 00:00:01 | 1 | 3 |
-
---------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
2 - filter(TO_NUMBER(TO_CHAR("EMPNO"))=7870)
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
18 rows selected.
Oracle做了一个隐式类型转换,TO_NUMBER,但该语句查找的是全部分区。
where条件无法检索的原因我们知道了,在做数据转换的时候添加了without validation,致使数据导入了P1分区,应该导入到P2,算是工作中失误。有哪些方法会造成该语句查不出结果呢,后续会再做一个简单的测试。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29487349/viewspace-1764438/
,如需转载,请注明出处,否则将追究法律责任。