Initial Extent for a table gets allocated only after data insertion in Locally managed user tablespace - oracle

In case of Locally managed SYSTEM tablespace, when objects are created in a user tablespace (which is also locally managed) initial extents are getting allocated only after data insertion.
Whereas in the same scenario where SYSTEM tablespace is dictionary managed, initial extent gets allocated whenever table is created.
create tablespace lmt datafile 'df.f' size 5M extent management local;
conn scott/tiger
create table sample (id nuber) tablespace lmt;
select * from user_tables where table_name = 'SAMPLE';
initial extent is null when SYSTEM tablespace is Locally managed
initial extent has value when SYSTEM tablespace is dictionary managed
After data insertion, initial extent is allocated in case (1)
Is this the expected behavior? because as per Oracle docs, 'Oracle allocates space for initial extent when you create the schema object'

I think you're quoting (or rather, slightly paraphrasing) this part of the documentation:
INITIAL
Specify the size of the first extent of the object. Oracle allocates space for this extent when you create the schema object. ...
That isn't the whole story though. Tables can be created with deferred segment creation:
deferred_segment_creation
Use this clause to determine when the database should create the segment(s) for this table:
SEGMENT CREATION DEFERRED: This clause defers creation of the table segment — as well as segments for any LOB columns of the table, any indexes created implicitly as part of table creation, and any indexes subsequently explicitly created on the table — until the first row of data is inserted into the table. ...
SEGMENT CREATION IMMEDIATE: The table segment is created as part of this CREATE TABLE statement.
It looks like what you are seeing is nothing to do with the SYSTEM tablespace being locally managed, as you suspected, and that is just a coincidence. The difference is the default for segment creation, which is controlled by an initialisation parameter, deferred_segment_creation. From what you've shown that is set to TRUE in the database that has the locally-managed SYSTEM tablespace, and FALSE in the one that has that dictionary-managed.
You can get consistent behaviour by overriding the default, either to defer creation:
create table sample (id number) segment creation deferred tablespace lmt;
Table SAMPLE created.
set null "(null)"
select initial_extent from user_tables where table_name = 'SAMPLE';
INITIAL_EXTENT
--------------
(null)
or to create immediately:
create table sample (id number) segment creation immediate tablespace lmt;
Table SAMPLE created.
select initial_extent from user_tables where table_name = 'SAMPLE';
INITIAL_EXTENT
--------------
65536
Or you could change the initialisation parameters to be the same, of course, but that's more work and might affect other code that assumes the current behaviour.

Related

Is there any major impact if we don't add tablespace clause while creating the table or indexes in oracle?

While creating tables or indexes, I always get the recommendation to add tablespace clause in the queries. Is there any major impact later on our table if we don't use the tablespace clause while creating them ?
This is what I am doing for a very long time.
CREATE TABLE XT_PMB_NOTIFY_UNSUB(
TXNID NUMBER(15),
APP_SEQNO NUMBER(15),
PRIMARY_KEYVAL VARCHAR2(4000) NOT NULL,
OP_CODE VARCHAR2(15),
TXN_STATUS VARCHAR2(1),
CREATE_DT DATE,
PRIMARY KEY (TXNID) );
Recommendation from DBA.
CREATE TABLE XT_PMB_NOTIFY_UNSUB(
TXNID NUMBER(15),
APP_SEQNO NUMBER(15),
PRIMARY_KEYVAL VARCHAR2(4000) NOT NULL,
OP_CODE VARCHAR2(15),
TXN_STATUS VARCHAR2(1),
CREATE_DT DATE,
PRIMARY KEY (TXNID) )
TABLESPACE DATA_ENC_TS;
The answer is it depends on how your company has defined its tablespace rules.
Oracle users (or schemas) can have one "default tablespace" which you can see by querying the database:
select username, default_tablespace from dba_users;
or if you do not have permission for that and you want to know what it is for the current user only:
select username, default_tablespace from user_users;
Or perhaps this one to see all users that are visible to your current connected user:
select username, default_tablespace from user_users;
According to Oracle documentation (https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_8003.htm) this is what it means:
Specify the default tablespace for objects that the user creates. If
you omit this clause, then the user's objects are stored in the
database default tablespace. If no default tablespace has been
specified for the database, then the user's objects are stored in the
SYSTEM tablespace.
So for your intents and purposes, when you create a table without explicitly using a tablespace at the end it will go to the user's default tablespace in general. If your DBAs tend to not define a default tablespace then it starts to have more serious impacts, because the table will be stored in a global default tablespace or (heaven forbid) it will go to SYSTEM tablespace. That last option would be extremely detrimental to the database health.
Some companies have the habit of assigning different tablespaces for tables and for indexes for instance. In that case, the users can only have one default tablespace, and if you omit the tablespace clause in the create index (or create table) statement, objects will go to the incorrect tablespace.
Now to the consequences of having a table or index in an incorrect tablespace. A tablespace is a collection of one or more physical operating system files (Oracle refers to them as data files). Whenever you create a table or index in a tablespace oracle allocates space in that datafile, which Oracle calls segments. Segments are logical units inside a data file. Keep in mind Oracle further breaks down segments into smaller logical units called extents and blocks, but that is a bit beyond the topic here. If you are interested there is more to read here: https://docs.oracle.com/cd/B19306_01/server.102/b14220/logical.htm
Let's go back to segments. Segments exist inside datafiles that belong to tablespaces. When you put your object in a tablespace and you want to move it out to a different tablespace, Oracle needs to physically write to files on the OS. And that can be simple if the table is empty, or can be a fair amount of work if it concerns a massive table spanning multiple datafiles or containing gigabytes or terabytes of data. It may mean an application outage is required to fix it.
Oracle provides certain methods to avoid application outages in those scenarios, like for example Online Redefinition (package DBMS_REDEFINITION). But I would hope we can agree that their use can be better leveraged for application migrations and things of the sort.
Using default tablespace settings is fine in many cases, by all means, but if you will allow me perhaps, the rule of thumb for many things Oracle is if you can write code to do something explicitly instead of relying on default values, do yourself and your DBA the favor. In general, the flexibility of relying on it is trumped by even a couple times of facing yourself with a surprise and then being responsible for cleaning it up later.
If you don't specify a tablespace, Oracle will use the default tablespaces assigned to the schema. You can find your default tablespace with the query below. Unless you have a very small development database w/o many schemas, that may be OK, but otherwise it is good practice to explicitly define them.
select *
from database_properties
where property_name like 'DEFAULT%TABLESPACE';
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
------------------------------ -------------------- ----------------------------------------
DEFAULT_TEMP_TABLESPACE TEMP Name of default temporary tablespace
DEFAULT_PERMANENT_TABLESPACE USERS Name of default permanent tablespace

Tablespace Segments and Schema Objects

I am learning about tablespaces, but I am not sure what a segment of a tablespace constitutes. Is it safe to say that the following query displays all schema objects that can be moved to different tablespaces:
select distinct segment_type
from dba_segments;
Result:
SEGMENT_TYPE
------------------
LOBINDEX
INDEX PARTITION
TABLE SUBPARTITION
ROLLBACK
TABLE PARTITION
NESTED TABLE
LOB PARTITION
LOBSEGMENT
INDEX
TABLE
TYPE2 UNDO
CLUSTER
A segment represents the storage associated with an object such as a table or index. Segments reside in tablespaces.
You probably won't be moving rollback or undo segments, as those will be in their own dedicated tablespace and are system-managed in recent versions of Oracle.
I don't think there is a convenient way to move a cluster to a new tablespace, but then aside from the ones used internally for the data dictionary they are rarely used, so probably you won't have to deal with those either.

Oracle segment space

I have a Tablespace with some tables and I can insert data without problem. Now I want to create a new table and I get this:
00000 - "unable to create INITIAL extent for segment in tablespace %s"
*Cause: Failed to find sufficient contiguous space to allocate INITIAL
extent for segment being created.
My question is: if there is a space problem, why am I able to insert data but not create new tables?
This is the CREATE script:
CREATE TABLE EC_SYS_NOTIFY_KYC (
ID NUMBER(38,0) PRIMARY KEY,
ID_OP NUMBER(38,0),
PROCESS_ID VARCHAR2(50) NOT NULL,
SYSTEM_ID VARCHAR2(50) NOT NULL)
TABLESPACE ECONTKYC_LARGE_1;
Space in Oracle is allocated in chunks called 'extents'. Your existing tables have already been allocated extents containing enough space to allow inserts for now, but you don't have enough unallocated free space in the tablespace to add a whole new extent, which is needed for a new table.
Eventually inserts into existing tables will start to fail as well, when their existing space is used up and they need more.

unable to create INITIAL extent for segment in tablespace SYSAUX

My program creates a database schema. The queries related to tables and/or view creations work just fine but the first insert I do fails with
unable to create INITIAL extent for segment in tablespace SYSAUX
error. It is a straightforward insert in a table that has just two columns, one two strings.
The user is obviously not set to use SYSAUX tablespace and has one on its own so:
I don't understand where a SYSAUX-related failure can come from?
How to fix this?

Is it safe to put an index on an Oracle Temporary Table?

I have read that one should not analyze a temp table, as it screws up the table statistics for others. What about an index? If I put an index on the table for the duration of my program, can other programs using the table be affected by that index?
Does an index affect my process, and all other processes using the table?
or Does it affect my process alone?
None of the responses have been authoritative, so I am offering said bribe.
Does an index effect my process, and all other processes using the table? or Does it effect my process alone?
I'm assuming we are talking of GLOBAL TEMPORARY tables.
Think of a temporary table as of multiple tables that are created and dropped by each process on the fly from a template stored in the system dictionary.
In Oracle, DML of a temporary table affects all processes, while data contained in the table will affect only one process that uses them.
Data in a temporary table is visible only inside the session scope. It uses TEMPORARY TABLESPACE to store both data and possible indexes.
DML for a temporary table (i. e. its layout, including column names and indexes) is visible to everybody with sufficient privileges.
This means that existence of the index will affect your process as well as other processes using the table in sense that any process that modifies data in the temporary table will also have to modify the index.
Data contained in the table (and in the index too), on the contrary, will affect only the process that created them, and will not even be visible to other processes.
IF you want one process to use the index and another one not to use it, do the following:
Create two temporary tables with same column layout
Index on one of them
Use indexed or non-indexed table depending on the process
I assume you're referring to true Oracle temporary tables and not just a regular table created temporarily and then dropped. Yes, it is safe to create indexes on the temp tables and they will be used according to the same rules as a regular tables and indexes.
[Edit]
I see you've refined your question, and here's a somewhat refined answer:
From:
Oracle® Database Administrator's Guide
10g Release 2 (10.2)
Part Number B14231-02
"Indexes can be created on temporary tables. They are also temporary and the data in the index has the same session or transaction scope as the data in the underlying table."
If you need the index for efficient processing during the scope of the transaction then I would imagine you'll have to explicitly hint it in the query because the statistics will show no rows for the table.
You're asking about two different things, indexes and statistics.
For indexes, yes, you can create indexes on the temp tables, they will be maintained as per usual.
For statistics, I recommend that you explicitly set the stats of the table to represent the average size of the table when queried. If you just let oracle gather stats by itself, the stats process isn't going to find anything in the tables (since by definition, the data in the table is local to your transaction), so it will return inaccurate results.
e.g. you can do:
exec dbms_stats.set_table_stats(user, 'my_temp_table', numrows=>10, numblks=>4)
Another tip is that if the size of the temporary table varies greatly, and within your transaction, you know how many rows are in the temp table, you can help out the optimizer by giving it that information. I find this helps out a lot if you are joining from the temp table to regular tables.
e.g., if you know the temp table has about 100 rows in it, you can:
SELECT /*+ CARDINALITY(my_temp_table 100) */ * FROM my_temp_table
Well, I tried it out and the index was visible and used by the second session. Creating a new global temporary table for your data would be safer if you really need an index.
You are also unable to create an index while any other session is accessing the table.
Here's the test case I ran:
--first session
create global temporary table index_test (val number(15))
on commit preserve rows;
create unique index idx_val on index_test(val);
--second session
insert into index_test select rownum from all_tables;
select * from index_test where val=1;
You can also use the dynamic sampling hint (10g):
select /*+ DYNAMIC_SAMPLING (3) */ val
from index_test
where val = 1;
See Ask Tom
You cannot create an index on a temporary table while it is used by another session, so answer is: No, it cannot affect any other process, because it is not possible.
An existing Index affects only your current session, because for any other session the temporary table appears empty, so it cannot access any index values.
Session 1:
SQL> create global temporary table index_test (val number(15)) on commit preserve rows;
Table created.
SQL> insert into index_test values (1);
1 row created.
SQL> commit;
Commit complete.
SQL>
Session 2 (while session 1 is still connected):
SQL> create unique index idx_val on index_test(val);
create unique index idx_val on index_test(val)
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
SQL>
Back to session 1:
SQL> delete from index_test;
1 row deleted.
SQL> commit;
Commit complete.
SQL>
Session 2:
SQL> create unique index idx_val on index_test(val);
create unique index idx_val on index_test(val)
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
SQL>
still failing, you first have to disconnect session 1 or table has to be truncated.
Session 1:
SQL> truncate table index_test;
Table truncated.
SQL>
Now you can create the index in Session 2:
SQL> create unique index idx_val on index_test(val);
Index created.
SQL>
This index of course will be used by any session.

Resources