Table not created in specific tablespace - Oracle - oracle

I am a moderate user of Oracle and I had to create some of the tables in specified table space as shown below.
create table t_abc tablespace abc_tbspc as select * from abc;
create table t_xyz tablespace abc_tbspc as select * from xyz;
After running these through jobs (file containing around 5 tables to be created in a single tablespace), I could see that the table t_abc is created in abc_tbspc ; but the table t_xyz is assigned to null when I query the all_tables. Not sure why the 2nd table is not created in the specified tablespace even though there is abundant space in the table space.

TABLESPACE_NAME will be null for one of these reasons:
Temporary Temporary tables use a temporary tablespace.
Index Organized Index-organized tables store data in an index, not in a heap.
Partitioned Each partition could have a different tablespace, there is not necessarily one tablespace for the whole table.
External External tables do not store their data in a tablespace.
Your code should not meet one of the conditions above; did you leave out some details? I ran the query below to look for other cases where TABLESPACE_NAME is null but could not find any.
select *
from dba_tables
where tablespace_name is null
and (temporary is null or temporary <> 'Y') -- #1
and (iot_type is null or iot_type <> 'IOT') -- #2
and (partitioned is null or partitioned <> 'YES') -- #3
and (owner, table_name) not in -- #4
(select owner, table_name from dba_external_tables)

Related

How to change the default tablespace of the schema in Oracle

There is a schema called Docker, in which there are tables named TABLE2, TABLE3.
Example
SELECT * FROM all_all_tables WHERE TABLE_name= 'TABLE3';
Also, the Docker schema belongs to the DEFAULT TABLESPACE SYSTEM tablespace.
select
username
, default_tablespace from dba_users WHERE USERNAME = 'DOCKER';
The following syntax is used to change the default tablespace of the schema. (TS3 tablespace already exists)
ALTER USER docker DEFAULT tablespace TS3;
Then, when I searched again, I found that the DEFAULT TABLESPACE was changed.
select
username
, default_tablespace from dba_users WHERE USERNAME = 'DOCKER';
And, of course, I thought that the tablespace in which TABLE2 and TABLE3 were designated would also have been changed to TS3, and the following statement was executed.
However, the tablespace of the table was SYSTEM, not TS3. I am curious about why it hasn't changed, and I want to know how.
SELECT * FROM all_all_tables WHERE TABLE_name= 'TABLE3';
The default tablespace is just that-- a default for when you create a segment (normally a table or an index but a segment could be a partition of a table, a materialized view, or anything else that requires space) and don't specify the tablespace. Once you create a segment and it is assigned to a particular tablespace, it will remain in that tablespace unless you move it.
Assuming you are on 12.2 or later so that online moves are an option (in other versions you'd need to remove the online keyword)
alter table table3
move online tablespace ts3;
You'd need to do that for each table. If there are also indexes in the system tablespace, you'd want to move those as well
alter index index_name
rebuild online tablespace ts3;
Depending on the number of tables and indexes involved, you may want to write a bit of dynamic SQL to generate the various alter table and alter index statements for you.

Is "Create Table" or "Create Any Table" Privilages grant the user a quota implicitly?

I am working on our database users privileges, and I am facing a confusing issue. I first created a user (user1) without any quota and grant him the role CONNECT which have the system privilege (Create Session). After that I grant him the (Create Table) privilege. The user try to create a table and he succeeded to create a table in his tablespace!! my questions are:
Based on my understanding, the user must have a quota to create any objects, how this user created the table?
Is there any privilege or roles that give the user a quota implicitly?
Regards,
A quota isn't being granted implicitly. But creating a table doesn't necessarily require any storage, and so doesn't necessarily require a quota:
create table t42 (id number);
Table T42 created.
select segment_type, bytes from user_segments where segment_name = 'T42';
no rows selected
Adding data to the table does require storage, and therefore a quota:
insert into t42 (id) values (1);
1 row inserted.
select segment_type, bytes from user_segments where segment_name = 'T42';
SEGMENT_TYPE BYTES
------------------ ----------
TABLE 65536
If the owner doesn't have a quota on the tablespace then they will get an error when they try to insert; which is the case when they do have a quota and try to exceed it too of course (though the error will be different).
This behaviour is due to deferred segment creation; the default behaviour is controlled by an initialisation parameter. You can override that during table creation with the segment creation clause.
drop table t42 purge;
Table T42 dropped.
create table t42 (id number) segment creation immediate;
Table T42 created.
select segment_type, bytes from user_segments where segment_name = 'T42';
SEGMENT_TYPE BYTES
------------------ ----------
TABLE 65536
Read more in the documentation.
Incidentally, if you create a table with deferred segment creation then dbms_metadata.get_ddl shows that; if you then insert a row to force a segment to be created, dbms_metadata.get_ddl changes to SEGMENT CREATION IMMEDIATE. Which might not be expected. Truncating the table with the DROP ALL STORAGE clause will remove the segments, and revert the DDL to SEGMENT CREATION DEFERRED. Just something I noticed in passing.

Move LOB tablespace on partitioned tables

Consider following tables:
CREATE TABLE TAB_ONE
(
<irrelevant columns>
MESSAGE CLOB,
REC_DATE DATE,
<irrelevant columns>
) TABLESPACE DATA_TS;
and
CREATE TABLE TAB_TWO
(
<irrelevant columns>
RESPONSE CLOB,
PART_ID NUMBER,
<irrelevant columns>
CONSTRAINT "FK_01"
FOREIGN KEY ("PART_ID") REFERENCES <IRRELEVANT_TABLE> ("SEQ_ID")
) TABLESPACE DATA_TS PARTITION BY REFERENCE (FK_01) ENABLE ROW MOVEMENT;
now, the task is to move all the (C)LOBs from DATA_TS to newly allocated tablespace called LOB_TS.
For the first table, it is easy enough:
ALTER TABLE TAB_ONE MOVE LOB ("MESSAGE") store as (tablespace LOB_TS compress low);
For the other one, partitioning does all the trouble. The aforementioned command does not work for obvious reasons, so I managed to find another:
ALTER TABLE TAB_TWO MOVE PARTITION SYS_P18485 LOB (RESPONSE) STORE AS ( TABLESPACE LOB_TS COMPRESS LOW );
ALTER TABLE TAB_TWO MOVE PARTITION SYS_P18299 LOB (RESPONSE) STORE AS ( TABLESPACE LOB_TS COMPRESS LOW );
(one for each partition the table TAB_TWO has)
These ALTER TABLES do not fail per se. The SQL Developer proudly states "Table TAB_TWO altered."
But then I ran SELECT * FROM USER_LOBS WHERE TABLE_NAME = 'TAB_TWO' and found out, that the CLOB stayed in the previous tablespace and did not move.
Of course, the idea of copying data via Create Table as Select, dropping the table, creating a new table and restoring the data occurred to me, but I would prefer a cleaner solution without the need of duplicating large amounts of data to different tables.

PL/SQL Creating a table with indexes

I have the following PL/SQL code:
DROP TABLE TAB_PARAM;
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE TAB_PARAM
(
TABLE_OWNER VARCHAR2(30) NOT NULL,
TABLE_NAME VARCHAR2(30) NOT NULL,
COLUMN_NAME VARCHAR2(30) NOT NULL,
PATTERN VARCHAR2(1024),
TYPE_METHODE VARCHAR2(30) NOT NULL,
SEPARATEUR VARCHAR2(20),
ID VARCHAR2(30),
CONSTRAINT PK_TAB_PARAM PRIMARY KEY (TABLE_OWNER,TABLE_NAME,COLUMN_NAME) USING INDEX TABLESPACE IND_PARC_256M NOLOGGING
)
TABLESPACE TAB_PARC_256M NOLOGGING NOCACHE NOMONITORING NOPARALLEL';
commit;
END;
/
I don't understand the part :
CONSTRAINT PK_TAB_PARAM PRIMARY KEY (TABLE_OWNER,TABLE_NAME,COLUMN_NAME) USING INDEX TABLESPACE IND_PARC_256M NOLOGGING
Nor the part:
TABLESPACE TAB_PARC_256M NOLOGGING NOCACHE NOMONITORING NOPARALLEL';
I know that it is setting the ID as primary key of TAB_PARAM but then I do not get the index part.
Can anyone help me understand this code please?
Sometimes you can create a table in a disposable way , for example you need to read data via sqlloader from file and insert in table , after that you will select all records from table . This operation doesnt need indexes and doesnt need primary key . Anyway it is always good to create primary key when you create a table and Oracle will create index for you . You can create more indexes whenever you want since the table was created . Now suppose you wanna update the table using where condition on a field who is not a primary key , it could be a better decision create an index on that field . In addition when you create indexes or table , you can associate tablespaces (created before) and could be good practice separate tablespaces for tables and indexes . All those operations are DDL Statements . In Oracle you can check datafiles , tables and indexes with those queries select * from dba_data_files; select * from dba_tables; select * from dba_indexes;
For primary key oracle implicitly creates unique index in table's tablespace.
This part USING INDEX TABLESPACE allow us to indicate tablespace for this implicitly index.
NOLOGGING - data is modified with minimal logging (to mark new extents invalid and to record dictionary changes).
NOCACHE - Oracle doesn't store blocks in the buffer cache.
NOPARALLEL - Parallel execution is not allowed on this table.(Default value)
NOMONITORING - Disable statistics collection. Now is deprecated. There is other mechanism to collect statistic
Edit. from oracle doc
Oracle Database uses an existing index if it contains a unique set of values before enforcing the primary key constraint. The existing
index can be defined as unique or nonunique. When a DML operation is
performed, the primary key constraint is enforced using this existing
index.
If there already index hitting the pk columns , oracle will used it, else then Oracle Database generates a unique index.
so you can create a primary key in oracle without an index if there was already index for that columns , specifying an index is for performance issue. The purpose of an index in a table is to 'read' the data faster.
From the oracle document
An index is a schema object that contains an entry for each value that
appears in the indexed column(s) of the table or cluster and provides
direct, fast access to rows.
As for the TABLESPACE, its where the database object exists, so when you create a table you specify in which tablespace you want it to exists. Read more here oracle document
As for NOLOGGING NOCACHE NOMONITORING, so the table not to be logged in redo logs or cached, also related to performance issue.

How to find out that an Oracle Table Partition is a System Generated Partition?

Am creating an Oracle HASH Table Partitions by using the below query
CREATE TABLE Table1 (
ID NUMBER, NAME VARCHAR2(50))
PARTITION BY HASH (ID)
PARTITIONS 25
STORE IN (Tablespace1);
Which Creates 25 HASH table partitions and also, the Database generates the 25 Unique partition names like SYS_P122, SYS_P123, SYS_P124... and so on for the partitions. Is there a way to find out this Partition lets say SYS_P123 is a system generated Partition name with the help of Oracle Catalog tables.
With the below link
http://docs.oracle.com/cd/B28359_01/server.111/b28320/statviews_2096.htm#REFRN20281
I could find the Oracle Table Partition information, but this catalog table does not have any value to say that the give Table Partition is a system generate or not. Is there any way to find out the given table partition name is system generated ?
Am using Oracle version 10 and 11.
Thanks,
Ravi,
Yes. The generated column in dba_objects gives the information.
Run the following query -
select owner, object_name, subobject_name, generated from all_objects where object_name = 'TABLE1' and object_type = 'TABLE PARTITION';
View the description for the 'generated' column in the following link - http://docs.oracle.com/cd/B28359_01/server.111/b28320/statviews_1145.htm#REFRN20146

Resources