Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 10 ■ DATABASE TABLES 397 ops$tkyte@ORA10G> SELECT /*+NESTED_TABLE_GET_REFS*/ 2 NESTED_TABLE_ID,SYS_NC_ROWINFO$ 3 FROM "OPS$TKYTE"."EMPS_NT" 4 / NESTED_TABLE_ID SYS_NC_ROWINFO$(EMPNO, EN -------------------------------- ------------------------- F60DEEE0FF7D7BC1E030007F01001321 EMP_TYPE(7782, 'CLARK', ' MANAGER', 7839, '09-JUN-8 1', 2450, 100) F60DEEE0FF7D7BC1E030007F01001321 EMP_TYPE(7839, 'KING', 'P RESIDENT', NULL, '17-NOV- 81', 5000, 100) ... Well, this is somewhat surprising if you describe this table: ops$tkyte@ORA10G> desc emps_nt Name Null? Type ----------------------------- -------- -------------------- EMPNO NUMBER(4) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(4) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) These two columns don’t even show up. They are part of the hidden implementation of nested tables. The NESTED_TABLE_ID is really a foreign key to the parent table DEPT_AND_EMP. DEPT_AND_EMP actually has a hidden column in it that is used to join to EMPS_NT. The SYS_NC_ ROWINF$ “column” is a magic column; it is more of a function than a column. The nested table here is really an object table (it is made of an object type), and SYS_NC_INFO$ is the internal way Oracle references the row as an object, instead of referencing each of the scalar columns. Under the covers, all Oracle has done for us is implement a parent/child table with systemgenerated primary and foreign keys. If we dig a little deeper, we can query the “real” data dictionary to see all of the columns in the DEPT_AND_EMP table: sys@ORA10G> select name 2 from sys.col$ 3 where obj# = ( select object_id 4 from dba_objects 5 where object_name = 'DEPT_AND_EMP' 6 and owner = 'OPS$TKYTE' ) 7 / NAME ------------------------------ DEPTNO
398 CHAPTER 10 ■ DATABASE TABLES DNAME EMPS LOC SYS_NC0000400005$ Selecting this column out from the nested table, we’ll see something like this: ops$tkyte@ORA10G> select SYS_NC0000400005$ from dept_and_emp; SYS_NC0000400005$ -------------------------------- F60DEEE0FF887BC1E030007F01001321 F60DEEE0FF897BC1E030007F01001321 F60DEEE0FF8A7BC1E030007F01001321 F60DEEE0FF8B7BC1E030007F01001321 The weird-looking column name, SYS_NC0000400005$, is the system-generated key placed into the DEPT_AND_EMP table. If we dig even deeper, we will find that Oracle has placed a unique index on this column. Unfortunately, however, it neglected to index the NESTED_TABLE_ID in EMPS_NT. This column really needs to be indexed, as we are always joining from DEPT_AND_EMP to EMPS_NT. This is an important thing to remember about nested tables if you use them with all of the defaults as just done: always index the NESTED_TABLE_ID in the nested tables! I’ve gotten off track, though, at this point—I was talking about how to treat the nested table as if it were a real table. The NESTED_TABLE_GET_REFS hint does that for us. We can use the hint like this: ops$tkyte@ORA10G> select /*+ nested_table_get_refs */ empno, ename 2 from emps_nt where ename like '%A%'; EMPNO ENAME ---------- ---------- 7782 CLARK 7876 ADAMS 7499 ALLEN 7521 WARD 7654 MARTIN 7698 BLAKE 7900 JAMES 7 rows selected. ops$tkyte@ORA10G> update /*+ nested_table_get_refs */ emps_nt 2 set ename = initcap(ename); 14 rows updated. ops$tkyte@ORA10G> select /*+ nested_table_get_refs */ empno, ename 2 from emps_nt where ename like '%a%';
- Page 391 and 392: 346 CHAPTER 10 ■ DATABASE TABLES
- Page 393 and 394: 348 CHAPTER 10 ■ DATABASE TABLES
- Page 395 and 396: 350 CHAPTER 10 ■ DATABASE TABLES
- Page 397 and 398: 352 CHAPTER 10 ■ DATABASE TABLES
- Page 399 and 400: 354 CHAPTER 10 ■ DATABASE TABLES
- Page 401 and 402: 356 CHAPTER 10 ■ DATABASE TABLES
- Page 403 and 404: 358 CHAPTER 10 ■ DATABASE TABLES
- Page 405 and 406: 360 CHAPTER 10 ■ DATABASE TABLES
- Page 407 and 408: 362 CHAPTER 10 ■ DATABASE TABLES
- Page 409 and 410: 364 CHAPTER 10 ■ DATABASE TABLES
- Page 411 and 412: 366 CHAPTER 10 ■ DATABASE TABLES
- Page 413 and 414: 368 CHAPTER 10 ■ DATABASE TABLES
- Page 415 and 416: 370 CHAPTER 10 ■ DATABASE TABLES
- Page 417 and 418: 372 CHAPTER 10 ■ DATABASE TABLES
- Page 419 and 420: 374 CHAPTER 10 ■ DATABASE TABLES
- Page 421 and 422: 376 CHAPTER 10 ■ DATABASE TABLES
- Page 423 and 424: 378 CHAPTER 10 ■ DATABASE TABLES
- Page 425 and 426: 380 CHAPTER 10 ■ DATABASE TABLES
- Page 427 and 428: 382 CHAPTER 10 ■ DATABASE TABLES
- Page 429 and 430: 384 CHAPTER 10 ■ DATABASE TABLES
- Page 431 and 432: 386 CHAPTER 10 ■ DATABASE TABLES
- Page 433 and 434: 388 CHAPTER 10 ■ DATABASE TABLES
- Page 435 and 436: 390 CHAPTER 10 ■ DATABASE TABLES
- Page 437 and 438: 392 CHAPTER 10 ■ DATABASE TABLES
- Page 439 and 440: 394 CHAPTER 10 ■ DATABASE TABLES
- Page 441: 396 CHAPTER 10 ■ DATABASE TABLES
- Page 445 and 446: 400 CHAPTER 10 ■ DATABASE TABLES
- Page 447 and 448: 402 CHAPTER 10 ■ DATABASE TABLES
- Page 449 and 450: 404 CHAPTER 10 ■ DATABASE TABLES
- Page 451 and 452: 406 CHAPTER 10 ■ DATABASE TABLES
- Page 453 and 454: 408 CHAPTER 10 ■ DATABASE TABLES
- Page 455 and 456: 410 CHAPTER 10 ■ DATABASE TABLES
- Page 457 and 458: 412 CHAPTER 10 ■ DATABASE TABLES
- Page 459 and 460: 414 CHAPTER 10 ■ DATABASE TABLES
- Page 461 and 462: 416 CHAPTER 10 ■ DATABASE TABLES
- Page 463 and 464: 418 CHAPTER 10 ■ DATABASE TABLES
- Page 466 and 467: CHAPTER 11 ■ ■ ■ Indexes Inde
- Page 468 and 469: CHAPTER 11 ■ INDEXES 423 value of
- Page 470 and 471: CHAPTER 11 ■ INDEXES 425 One of t
- Page 472 and 473: CHAPTER 11 ■ INDEXES 427 We then
- Page 474 and 475: CHAPTER 11 ■ INDEXES 429 we ended
- Page 476 and 477: CHAPTER 11 ■ INDEXES 431 The data
- Page 478 and 479: CHAPTER 11 ■ INDEXES 433 if ( (++
- Page 480 and 481: CHAPTER 11 ■ INDEXES 435 Table 11
- Page 482 and 483: CHAPTER 11 ■ INDEXES 437 When Sho
- Page 484 and 485: CHAPTER 11 ■ INDEXES 439 an 8KB b
- Page 486 and 487: CHAPTER 11 ■ INDEXES 441 select *
- Page 488 and 489: CHAPTER 11 ■ INDEXES 443 select *
- Page 490 and 491: CHAPTER 11 ■ INDEXES 445 Indicate
CHAPTER 10 ■ DATABASE TABLES 397<br />
ops$tkyte@ORA10G> SELECT /*+NESTED_TABLE_GET_REFS*/<br />
2 NESTED_TABLE_ID,SYS_NC_ROWINFO$<br />
3 FROM "OPS$TKYTE"."EMPS_NT"<br />
4 /<br />
NESTED_TABLE_ID<br />
SYS_NC_ROWINFO$(EMPNO, EN<br />
-------------------------------- -------------------------<br />
F60DEEE0FF7D7BC1E030007F01001321 EMP_TYPE(7782, 'CLARK', '<br />
MANAGER', 7839, '09-JUN-8<br />
1', 2450, 100)<br />
F60DEEE0FF7D7BC1E030007F01001321 EMP_TYPE(7839, 'KING', 'P<br />
RESIDENT', NULL, '17-NOV-<br />
81', 5000, 100) ...<br />
Well, this is somewhat surprising if you describe this table:<br />
ops$tkyte@ORA10G> desc emps_nt<br />
Name Null? Type<br />
----------------------------- -------- --------------------<br />
EMPNO<br />
NUMBER(4)<br />
ENAME<br />
VARCHAR2(10)<br />
JOB<br />
VARCHAR2(9)<br />
MGR<br />
NUMBER(4)<br />
HIREDATE<br />
DATE<br />
SAL<br />
NUMBER(7,2)<br />
COMM<br />
NUMBER(7,2)<br />
These two columns don’t even show up. They are part of the hidden implementation of<br />
nested tables. The NESTED_TABLE_ID is really a foreign key to the parent table DEPT_AND_EMP.<br />
DEPT_AND_EMP actually has a hidden column in it that is used to join to EMPS_NT. The SYS_NC_<br />
ROWINF$ “column” is a magic column; it is more of a function than a column. The nested table<br />
here is really an object table (it is made of an object type), <strong>and</strong> SYS_NC_INFO$ is the internal<br />
way <strong>Oracle</strong> references the row as an object, instead of referencing each of the scalar columns.<br />
Under the covers, all <strong>Oracle</strong> has done for us is implement a parent/child table with systemgenerated<br />
primary <strong>and</strong> foreign keys. If we dig a little deeper, we can query the “real” data<br />
dictionary to see all of the columns in the DEPT_AND_EMP table:<br />
sys@ORA10G> select name<br />
2 from sys.col$<br />
3 where obj# = ( select object_id<br />
4 from dba_objects<br />
5 where object_name = 'DEPT_AND_EMP'<br />
6 <strong>and</strong> owner = 'OPS$TKYTE' )<br />
7 /<br />
NAME<br />
------------------------------<br />
DEPTNO